1use crate::{
2 elements::ElementBox,
3 executor,
4 keymap::{self, Keystroke},
5 platform::{self, App as _, WindowOptions},
6 presenter::Presenter,
7 util::post_inc,
8 AssetCache, AssetSource, FontCache, TextLayoutCache,
9};
10use anyhow::{anyhow, Result};
11use async_std::sync::Condvar;
12use keymap::MatchResult;
13use parking_lot::Mutex;
14use pathfinder_geometry::{rect::RectF, vector::vec2f};
15use platform::Event;
16use smol::prelude::*;
17use std::{
18 any::{type_name, Any, TypeId},
19 cell::RefCell,
20 collections::{HashMap, HashSet, VecDeque},
21 fmt::{self, Debug},
22 hash::{Hash, Hasher},
23 marker::PhantomData,
24 rc::{self, Rc},
25 sync::{Arc, Weak},
26};
27
28pub trait Entity: 'static + Send + Sync {
29 type Event;
30}
31
32pub trait View: Entity {
33 fn ui_name() -> &'static str;
34 fn render<'a>(&self, app: &AppContext) -> ElementBox;
35 fn on_focus(&mut self, _ctx: &mut ViewContext<Self>) {}
36 fn on_blur(&mut self, _ctx: &mut ViewContext<Self>) {}
37 fn keymap_context(&self, _: &AppContext) -> keymap::Context {
38 Self::default_keymap_context()
39 }
40 fn default_keymap_context() -> keymap::Context {
41 let mut ctx = keymap::Context::default();
42 ctx.set.insert(Self::ui_name().into());
43 ctx
44 }
45}
46
47pub trait ModelAsRef {
48 fn model<T: Entity>(&self, handle: &ModelHandle<T>) -> &T;
49}
50
51pub trait UpdateModel {
52 fn update_model<T, F, S>(&mut self, handle: &ModelHandle<T>, update: F) -> S
53 where
54 T: Entity,
55 F: FnOnce(&mut T, &mut ModelContext<T>) -> S;
56}
57
58pub trait ViewAsRef {
59 fn view<T: View>(&self, handle: &ViewHandle<T>) -> &T;
60}
61
62pub trait UpdateView {
63 fn update_view<T, F, S>(&mut self, handle: &ViewHandle<T>, update: F) -> S
64 where
65 T: View,
66 F: FnOnce(&mut T, &mut ViewContext<T>) -> S;
67}
68
69pub struct Menu<'a> {
70 pub name: &'a str,
71 pub items: &'a [MenuItem<'a>],
72}
73
74pub enum MenuItem<'a> {
75 Action {
76 name: &'a str,
77 keystroke: Option<&'a str>,
78 action: &'a str,
79 },
80 Separator,
81}
82
83#[derive(Clone)]
84pub struct App(Rc<RefCell<MutableAppContext>>);
85
86impl App {
87 pub fn test<T, A: AssetSource, F: Future<Output = T>, G: FnOnce(App) -> F>(
88 asset_source: A,
89 f: G,
90 ) -> T {
91 let platform = platform::test::app();
92 let foreground = Rc::new(executor::Foreground::test());
93 let app = Self(Rc::new(RefCell::new(MutableAppContext::new(
94 foreground.clone(),
95 Arc::new(platform),
96 asset_source,
97 ))));
98 app.0.borrow_mut().weak_self = Some(Rc::downgrade(&app.0));
99 smol::block_on(foreground.run(f(app)))
100 }
101
102 pub fn new(asset_source: impl AssetSource) -> Result<Self> {
103 let platform = Arc::new(platform::current::app());
104 let foreground = Rc::new(executor::Foreground::platform(platform.dispatcher())?);
105 let app = Self(Rc::new(RefCell::new(MutableAppContext::new(
106 foreground,
107 platform,
108 asset_source,
109 ))));
110 app.0.borrow_mut().weak_self = Some(Rc::downgrade(&app.0));
111 Ok(app)
112 }
113
114 pub fn on_window_invalidated<F: 'static + FnMut(WindowInvalidation, &mut MutableAppContext)>(
115 &self,
116 window_id: usize,
117 callback: F,
118 ) {
119 self.0
120 .borrow_mut()
121 .on_window_invalidated(window_id, callback);
122 }
123
124 pub fn add_action<S, V, T, F>(&self, name: S, handler: F)
125 where
126 S: Into<String>,
127 V: View,
128 T: Any,
129 F: 'static + FnMut(&mut V, &T, &mut ViewContext<V>),
130 {
131 self.0.borrow_mut().add_action(name, handler);
132 }
133
134 pub fn add_global_action<S, T, F>(&self, name: S, handler: F)
135 where
136 S: Into<String>,
137 T: 'static + Any,
138 F: 'static + FnMut(&T, &mut MutableAppContext),
139 {
140 self.0.borrow_mut().add_global_action(name, handler);
141 }
142
143 pub fn dispatch_action<T: 'static + Any>(
144 &self,
145 window_id: usize,
146 responder_chain: Vec<usize>,
147 name: &str,
148 arg: T,
149 ) {
150 self.0.borrow_mut().dispatch_action(
151 window_id,
152 &responder_chain,
153 name,
154 Box::new(arg).as_ref(),
155 );
156 }
157
158 pub fn dispatch_global_action<T: 'static + Any>(&self, name: &str, arg: T) {
159 self.0
160 .borrow_mut()
161 .dispatch_global_action(name, Box::new(arg).as_ref());
162 }
163
164 pub fn add_bindings<T: IntoIterator<Item = keymap::Binding>>(&self, bindings: T) {
165 self.0.borrow_mut().add_bindings(bindings);
166 }
167
168 pub fn dispatch_keystroke(
169 &self,
170 window_id: usize,
171 responder_chain: Vec<usize>,
172 keystroke: &Keystroke,
173 ) -> Result<bool> {
174 let mut state = self.0.borrow_mut();
175 state.dispatch_keystroke(window_id, responder_chain, keystroke)
176 }
177
178 pub fn add_model<T, F>(&mut self, build_model: F) -> ModelHandle<T>
179 where
180 T: Entity,
181 F: FnOnce(&mut ModelContext<T>) -> T,
182 {
183 let mut state = self.0.borrow_mut();
184 state.pending_flushes += 1;
185 let handle = state.add_model(build_model);
186 state.flush_effects();
187 handle
188 }
189
190 fn read_model<T, F, S>(&self, handle: &ModelHandle<T>, read: F) -> S
191 where
192 T: Entity,
193 F: FnOnce(&T, &AppContext) -> S,
194 {
195 let state = self.0.borrow();
196 read(state.model(handle), &state.ctx)
197 }
198
199 pub fn add_window<T, F>(&mut self, build_root_view: F) -> (usize, ViewHandle<T>)
200 where
201 T: View,
202 F: FnOnce(&mut ViewContext<T>) -> T,
203 {
204 self.0.borrow_mut().add_window(build_root_view)
205 }
206
207 pub fn window_ids(&self) -> Vec<usize> {
208 self.0.borrow().window_ids().collect()
209 }
210
211 pub fn root_view<T: View>(&self, window_id: usize) -> Option<ViewHandle<T>> {
212 self.0.borrow().root_view(window_id)
213 }
214
215 pub fn add_view<T, F>(&mut self, window_id: usize, build_view: F) -> ViewHandle<T>
216 where
217 T: View,
218 F: FnOnce(&mut ViewContext<T>) -> T,
219 {
220 let mut state = self.0.borrow_mut();
221 state.pending_flushes += 1;
222 let handle = state.add_view(window_id, build_view);
223 state.flush_effects();
224 handle
225 }
226
227 pub fn add_option_view<T, F>(
228 &mut self,
229 window_id: usize,
230 build_view: F,
231 ) -> Option<ViewHandle<T>>
232 where
233 T: View,
234 F: FnOnce(&mut ViewContext<T>) -> Option<T>,
235 {
236 let mut state = self.0.borrow_mut();
237 state.pending_flushes += 1;
238 let handle = state.add_option_view(window_id, build_view);
239 state.flush_effects();
240 handle
241 }
242
243 pub fn read<T, F: FnOnce(&AppContext) -> T>(&mut self, callback: F) -> T {
244 callback(self.0.borrow().downgrade())
245 }
246
247 pub fn update<T, F: FnOnce(&mut MutableAppContext) -> T>(&mut self, callback: F) -> T {
248 let mut state = self.0.borrow_mut();
249 state.pending_flushes += 1;
250 let result = callback(&mut *state);
251 state.flush_effects();
252 result
253 }
254
255 fn read_view<T, F, S>(&self, handle: &ViewHandle<T>, read: F) -> S
256 where
257 T: View,
258 F: FnOnce(&T, &AppContext) -> S,
259 {
260 let state = self.0.borrow();
261 read(state.view(handle), state.downgrade())
262 }
263
264 pub fn finish_pending_tasks(&self) -> impl Future<Output = ()> {
265 self.0.borrow().finish_pending_tasks()
266 }
267
268 pub fn font_cache(&self) -> Arc<FontCache> {
269 self.0.borrow().font_cache.clone()
270 }
271
272 pub fn platform(&self) -> Arc<dyn platform::App> {
273 self.0.borrow().platform.clone()
274 }
275}
276
277impl UpdateModel for App {
278 fn update_model<T, F, S>(&mut self, handle: &ModelHandle<T>, update: F) -> S
279 where
280 T: Entity,
281 F: FnOnce(&mut T, &mut ModelContext<T>) -> S,
282 {
283 let mut state = self.0.borrow_mut();
284 state.pending_flushes += 1;
285 let result = state.update_model(handle, update);
286 state.flush_effects();
287 result
288 }
289}
290
291impl UpdateView for App {
292 fn update_view<T, F, S>(&mut self, handle: &ViewHandle<T>, update: F) -> S
293 where
294 T: View,
295 F: FnOnce(&mut T, &mut ViewContext<T>) -> S,
296 {
297 let mut state = self.0.borrow_mut();
298 state.pending_flushes += 1;
299 let result = state.update_view(handle, update);
300 state.flush_effects();
301 result
302 }
303}
304
305type ActionCallback =
306 dyn FnMut(&mut dyn AnyView, &dyn Any, &mut MutableAppContext, usize, usize) -> bool;
307
308type GlobalActionCallback = dyn FnMut(&dyn Any, &mut MutableAppContext);
309
310pub struct MutableAppContext {
311 weak_self: Option<rc::Weak<RefCell<Self>>>,
312 platform: Arc<dyn platform::App>,
313 font_cache: Arc<FontCache>,
314 assets: Arc<AssetCache>,
315 ctx: AppContext,
316 actions: HashMap<TypeId, HashMap<String, Vec<Box<ActionCallback>>>>,
317 global_actions: HashMap<String, Vec<Box<GlobalActionCallback>>>,
318 keystroke_matcher: keymap::Matcher,
319 next_entity_id: usize,
320 next_window_id: usize,
321 next_task_id: usize,
322 subscriptions: HashMap<usize, Vec<Subscription>>,
323 observations: HashMap<usize, Vec<Observation>>,
324 window_invalidations: HashMap<usize, WindowInvalidation>,
325 invalidation_callbacks:
326 HashMap<usize, Box<dyn FnMut(WindowInvalidation, &mut MutableAppContext)>>,
327 foreground: Rc<executor::Foreground>,
328 future_handlers: Rc<RefCell<HashMap<usize, FutureHandler>>>,
329 stream_handlers: Rc<RefCell<HashMap<usize, StreamHandler>>>,
330 task_done: Arc<Condvar>,
331 pending_effects: VecDeque<Effect>,
332 pending_flushes: usize,
333 flushing_effects: bool,
334}
335
336impl MutableAppContext {
337 pub fn new(
338 foreground: Rc<executor::Foreground>,
339 platform: Arc<dyn platform::App>,
340 asset_source: impl AssetSource,
341 ) -> Self {
342 let fonts = platform.fonts();
343 Self {
344 weak_self: None,
345 platform,
346 font_cache: Arc::new(FontCache::new(fonts)),
347 assets: Arc::new(AssetCache::new(asset_source)),
348 ctx: AppContext {
349 models: HashMap::new(),
350 windows: HashMap::new(),
351 ref_counts: Arc::new(Mutex::new(RefCounts::default())),
352 background: Arc::new(executor::Background::new()),
353 },
354 actions: HashMap::new(),
355 global_actions: HashMap::new(),
356 keystroke_matcher: keymap::Matcher::default(),
357 next_entity_id: 0,
358 next_window_id: 0,
359 next_task_id: 0,
360 subscriptions: HashMap::new(),
361 observations: HashMap::new(),
362 window_invalidations: HashMap::new(),
363 invalidation_callbacks: HashMap::new(),
364 foreground,
365 future_handlers: Default::default(),
366 stream_handlers: Default::default(),
367 task_done: Default::default(),
368 pending_effects: VecDeque::new(),
369 pending_flushes: 0,
370 flushing_effects: false,
371 }
372 }
373
374 pub fn upgrade(&self) -> App {
375 App(self.weak_self.as_ref().unwrap().upgrade().unwrap())
376 }
377
378 pub fn downgrade(&self) -> &AppContext {
379 &self.ctx
380 }
381
382 pub fn platform(&self) -> Arc<dyn platform::App> {
383 self.platform.clone()
384 }
385
386 pub fn foreground_executor(&self) -> &Rc<executor::Foreground> {
387 &self.foreground
388 }
389
390 pub fn background_executor(&self) -> &Arc<executor::Background> {
391 &self.ctx.background
392 }
393
394 pub fn on_window_invalidated<F: 'static + FnMut(WindowInvalidation, &mut MutableAppContext)>(
395 &mut self,
396 window_id: usize,
397 callback: F,
398 ) {
399 self.invalidation_callbacks
400 .insert(window_id, Box::new(callback));
401 self.update_windows();
402 }
403
404 pub fn add_action<S, V, T, F>(&mut self, name: S, mut handler: F)
405 where
406 S: Into<String>,
407 V: View,
408 T: Any,
409 F: 'static + FnMut(&mut V, &T, &mut ViewContext<V>),
410 {
411 let name = name.into();
412 let name_clone = name.clone();
413 let handler = Box::new(
414 move |view: &mut dyn AnyView,
415 arg: &dyn Any,
416 app: &mut MutableAppContext,
417 window_id: usize,
418 view_id: usize| {
419 match arg.downcast_ref() {
420 Some(arg) => {
421 let mut ctx = ViewContext::new(app, window_id, view_id);
422 handler(
423 view.as_any_mut()
424 .downcast_mut()
425 .expect("downcast is type safe"),
426 arg,
427 &mut ctx,
428 );
429 ctx.halt_action_dispatch
430 }
431 None => {
432 log::error!("Could not downcast argument for action {}", name_clone);
433 false
434 }
435 }
436 },
437 );
438
439 self.actions
440 .entry(TypeId::of::<V>())
441 .or_default()
442 .entry(name)
443 .or_default()
444 .push(handler);
445 }
446
447 pub fn add_global_action<S, T, F>(&mut self, name: S, mut handler: F)
448 where
449 S: Into<String>,
450 T: 'static + Any,
451 F: 'static + FnMut(&T, &mut MutableAppContext),
452 {
453 let name = name.into();
454 let name_clone = name.clone();
455 let handler = Box::new(move |arg: &dyn Any, app: &mut MutableAppContext| {
456 if let Some(arg) = arg.downcast_ref() {
457 handler(arg, app);
458 } else {
459 log::error!("Could not downcast argument for action {}", name_clone);
460 }
461 });
462
463 self.global_actions.entry(name).or_default().push(handler);
464 }
465
466 pub fn window_ids(&self) -> impl Iterator<Item = usize> + '_ {
467 self.ctx.windows.keys().cloned()
468 }
469
470 pub fn root_view<T: View>(&self, window_id: usize) -> Option<ViewHandle<T>> {
471 self.ctx
472 .windows
473 .get(&window_id)
474 .and_then(|window| window.root_view.as_ref().unwrap().clone().downcast::<T>())
475 }
476
477 pub fn root_view_id(&self, window_id: usize) -> Option<usize> {
478 self.ctx.root_view_id(window_id)
479 }
480
481 pub fn focused_view_id(&self, window_id: usize) -> Option<usize> {
482 self.ctx.focused_view_id(window_id)
483 }
484
485 pub fn render_view(&self, window_id: usize, view_id: usize) -> Result<ElementBox> {
486 self.ctx.render_view(window_id, view_id)
487 }
488
489 pub fn render_views(&self, window_id: usize) -> Result<HashMap<usize, ElementBox>> {
490 self.ctx.render_views(window_id)
491 }
492
493 pub fn dispatch_action(
494 &mut self,
495 window_id: usize,
496 path: &[usize],
497 name: &str,
498 arg: &dyn Any,
499 ) -> bool {
500 self.pending_flushes += 1;
501 let mut halted_dispatch = false;
502
503 for view_id in path.iter().rev() {
504 if let Some(mut view) = self
505 .ctx
506 .windows
507 .get_mut(&window_id)
508 .and_then(|w| w.views.remove(view_id))
509 {
510 let type_id = view.as_any().type_id();
511
512 if let Some((name, mut handlers)) = self
513 .actions
514 .get_mut(&type_id)
515 .and_then(|h| h.remove_entry(name))
516 {
517 for handler in handlers.iter_mut().rev() {
518 let halt_dispatch = handler(view.as_mut(), arg, self, window_id, *view_id);
519 if halt_dispatch {
520 halted_dispatch = true;
521 break;
522 }
523 }
524 self.actions
525 .get_mut(&type_id)
526 .unwrap()
527 .insert(name, handlers);
528 }
529
530 self.ctx
531 .windows
532 .get_mut(&window_id)
533 .unwrap()
534 .views
535 .insert(*view_id, view);
536
537 if halted_dispatch {
538 break;
539 }
540 }
541 }
542
543 if !halted_dispatch {
544 self.dispatch_global_action(name, arg);
545 }
546
547 self.flush_effects();
548 halted_dispatch
549 }
550
551 fn dispatch_global_action(&mut self, name: &str, arg: &dyn Any) {
552 if let Some((name, mut handlers)) = self.global_actions.remove_entry(name) {
553 self.pending_flushes += 1;
554 for handler in handlers.iter_mut().rev() {
555 handler(arg, self);
556 }
557 self.global_actions.insert(name, handlers);
558 self.flush_effects();
559 }
560 }
561
562 fn add_bindings<T: IntoIterator<Item = keymap::Binding>>(&mut self, bindings: T) {
563 self.keystroke_matcher.add_bindings(bindings);
564 }
565
566 pub fn dispatch_keystroke(
567 &mut self,
568 window_id: usize,
569 responder_chain: Vec<usize>,
570 keystroke: &Keystroke,
571 ) -> Result<bool> {
572 let mut context_chain = Vec::new();
573 let mut context = keymap::Context::default();
574 for view_id in &responder_chain {
575 if let Some(view) = self
576 .ctx
577 .windows
578 .get(&window_id)
579 .and_then(|w| w.views.get(view_id))
580 {
581 context.extend(view.keymap_context(self.downgrade()));
582 context_chain.push(context.clone());
583 } else {
584 return Err(anyhow!(
585 "View {} in responder chain does not exist",
586 view_id
587 ));
588 }
589 }
590
591 let mut pending = false;
592 for (i, ctx) in context_chain.iter().enumerate().rev() {
593 match self
594 .keystroke_matcher
595 .push_keystroke(keystroke.clone(), responder_chain[i], ctx)
596 {
597 MatchResult::None => {}
598 MatchResult::Pending => pending = true,
599 MatchResult::Action { name, arg } => {
600 if self.dispatch_action(
601 window_id,
602 &responder_chain[0..=i],
603 &name,
604 arg.as_ref().map(|arg| arg.as_ref()).unwrap_or(&()),
605 ) {
606 return Ok(true);
607 }
608 }
609 }
610 }
611
612 Ok(pending)
613 }
614
615 pub fn add_model<T, F>(&mut self, build_model: F) -> ModelHandle<T>
616 where
617 T: Entity,
618 F: FnOnce(&mut ModelContext<T>) -> T,
619 {
620 self.pending_flushes += 1;
621 let model_id = post_inc(&mut self.next_entity_id);
622 let mut ctx = ModelContext::new(self, model_id);
623 let model = build_model(&mut ctx);
624 self.ctx.models.insert(model_id, Box::new(model));
625 self.flush_effects();
626 ModelHandle::new(model_id, &self.ctx.ref_counts)
627 }
628
629 pub fn add_window<T, F>(&mut self, build_root_view: F) -> (usize, ViewHandle<T>)
630 where
631 T: View,
632 F: FnOnce(&mut ViewContext<T>) -> T,
633 {
634 self.pending_flushes += 1;
635 let window_id = post_inc(&mut self.next_window_id);
636 self.ctx.windows.insert(window_id, Window::default());
637 self.open_platform_window(window_id);
638 let root_handle = self.add_view(window_id, build_root_view);
639 self.ctx.windows.get_mut(&window_id).unwrap().root_view = Some(root_handle.clone().into());
640 self.focus(window_id, root_handle.id());
641 self.flush_effects();
642
643 (window_id, root_handle)
644 }
645
646 fn open_platform_window(&mut self, window_id: usize) {
647 match self.platform.open_window(
648 WindowOptions {
649 bounds: RectF::new(vec2f(0., 0.), vec2f(1024., 768.)),
650 title: "Zed".into(),
651 },
652 self.foreground.clone(),
653 ) {
654 Err(e) => log::error!("error opening window: {}", e),
655 Ok(mut window) => {
656 let text_layout_cache = TextLayoutCache::new(self.platform.fonts());
657 let presenter = Rc::new(RefCell::new(Presenter::new(
658 window_id,
659 self.font_cache.clone(),
660 text_layout_cache,
661 self.assets.clone(),
662 self,
663 )));
664
665 {
666 let mut app = self.upgrade();
667 let presenter = presenter.clone();
668 window.on_event(Box::new(move |event| {
669 app.update(|ctx| {
670 if let Event::KeyDown { keystroke, .. } = &event {
671 if ctx
672 .dispatch_keystroke(
673 window_id,
674 presenter.borrow().dispatch_path(ctx.downgrade()),
675 keystroke,
676 )
677 .unwrap()
678 {
679 return;
680 }
681 }
682
683 let actions = presenter
684 .borrow_mut()
685 .dispatch_event(event, ctx.downgrade());
686 for action in actions {
687 ctx.dispatch_action(
688 window_id,
689 &action.path,
690 action.name,
691 action.arg.as_ref(),
692 );
693 }
694 })
695 }));
696 }
697
698 {
699 let mut app = self.upgrade();
700 let presenter = presenter.clone();
701 window.on_resize(Box::new(move |window| {
702 app.update(|ctx| {
703 let scene = presenter.borrow_mut().build_scene(
704 window.size(),
705 window.scale_factor(),
706 ctx,
707 );
708 window.present_scene(scene);
709 })
710 }));
711 }
712
713 self.on_window_invalidated(window_id, move |invalidation, ctx| {
714 let mut presenter = presenter.borrow_mut();
715 presenter.invalidate(invalidation, ctx.downgrade());
716 let scene = presenter.build_scene(window.size(), window.scale_factor(), ctx);
717 window.present_scene(scene);
718 });
719 }
720 }
721 }
722
723 pub fn add_view<T, F>(&mut self, window_id: usize, build_view: F) -> ViewHandle<T>
724 where
725 T: View,
726 F: FnOnce(&mut ViewContext<T>) -> T,
727 {
728 self.add_option_view(window_id, |ctx| Some(build_view(ctx)))
729 .unwrap()
730 }
731
732 pub fn add_option_view<T, F>(
733 &mut self,
734 window_id: usize,
735 build_view: F,
736 ) -> Option<ViewHandle<T>>
737 where
738 T: View,
739 F: FnOnce(&mut ViewContext<T>) -> Option<T>,
740 {
741 let view_id = post_inc(&mut self.next_entity_id);
742 self.pending_flushes += 1;
743 let mut ctx = ViewContext::new(self, window_id, view_id);
744 let handle = if let Some(view) = build_view(&mut ctx) {
745 if let Some(window) = self.ctx.windows.get_mut(&window_id) {
746 window.views.insert(view_id, Box::new(view));
747 } else {
748 panic!("Window does not exist");
749 }
750 self.window_invalidations
751 .entry(window_id)
752 .or_default()
753 .updated
754 .insert(view_id);
755 Some(ViewHandle::new(window_id, view_id, &self.ctx.ref_counts))
756 } else {
757 None
758 };
759 self.flush_effects();
760 handle
761 }
762
763 fn remove_dropped_entities(&mut self) {
764 loop {
765 let (dropped_models, dropped_views) = self.ctx.ref_counts.lock().take_dropped();
766 if dropped_models.is_empty() && dropped_views.is_empty() {
767 break;
768 }
769
770 for model_id in dropped_models {
771 self.ctx.models.remove(&model_id);
772 self.subscriptions.remove(&model_id);
773 self.observations.remove(&model_id);
774 }
775
776 for (window_id, view_id) in dropped_views {
777 self.subscriptions.remove(&view_id);
778 self.observations.remove(&view_id);
779 if let Some(window) = self.ctx.windows.get_mut(&window_id) {
780 self.window_invalidations
781 .entry(window_id)
782 .or_default()
783 .removed
784 .push(view_id);
785 window.views.remove(&view_id);
786 }
787 }
788 }
789 }
790
791 fn flush_effects(&mut self) {
792 self.pending_flushes -= 1;
793
794 if !self.flushing_effects && self.pending_flushes == 0 {
795 self.flushing_effects = true;
796
797 while let Some(effect) = self.pending_effects.pop_front() {
798 match effect {
799 Effect::Event { entity_id, payload } => self.emit_event(entity_id, payload),
800 Effect::ModelNotification { model_id } => self.notify_model_observers(model_id),
801 Effect::ViewNotification { window_id, view_id } => {
802 self.notify_view_observers(window_id, view_id)
803 }
804 Effect::Focus { window_id, view_id } => {
805 self.focus(window_id, view_id);
806 }
807 }
808 }
809
810 self.flushing_effects = false;
811 self.remove_dropped_entities();
812 self.update_windows();
813 }
814 }
815
816 fn update_windows(&mut self) {
817 let mut invalidations = HashMap::new();
818 std::mem::swap(&mut invalidations, &mut self.window_invalidations);
819
820 for (window_id, invalidation) in invalidations {
821 if let Some(mut callback) = self.invalidation_callbacks.remove(&window_id) {
822 callback(invalidation, self);
823 self.invalidation_callbacks.insert(window_id, callback);
824 }
825 }
826 }
827
828 fn emit_event(&mut self, entity_id: usize, payload: Box<dyn Any>) {
829 if let Some(subscriptions) = self.subscriptions.remove(&entity_id) {
830 for mut subscription in subscriptions {
831 let alive = match &mut subscription {
832 Subscription::FromModel { model_id, callback } => {
833 if let Some(mut model) = self.ctx.models.remove(model_id) {
834 callback(model.as_any_mut(), payload.as_ref(), self, *model_id);
835 self.ctx.models.insert(*model_id, model);
836 true
837 } else {
838 false
839 }
840 }
841 Subscription::FromView {
842 window_id,
843 view_id,
844 callback,
845 } => {
846 if let Some(mut view) = self
847 .ctx
848 .windows
849 .get_mut(&window_id)
850 .and_then(|window| window.views.remove(view_id))
851 {
852 callback(
853 view.as_any_mut(),
854 payload.as_ref(),
855 self,
856 *window_id,
857 *view_id,
858 );
859 self.ctx
860 .windows
861 .get_mut(&window_id)
862 .unwrap()
863 .views
864 .insert(*view_id, view);
865 true
866 } else {
867 false
868 }
869 }
870 };
871
872 if alive {
873 self.subscriptions
874 .entry(entity_id)
875 .or_default()
876 .push(subscription);
877 }
878 }
879 }
880 }
881
882 fn notify_model_observers(&mut self, observed_id: usize) {
883 if let Some(observations) = self.observations.remove(&observed_id) {
884 if self.ctx.models.contains_key(&observed_id) {
885 for mut observation in observations {
886 let alive = match &mut observation {
887 Observation::FromModel { model_id, callback } => {
888 if let Some(mut model) = self.ctx.models.remove(model_id) {
889 callback(model.as_any_mut(), observed_id, self, *model_id);
890 self.ctx.models.insert(*model_id, model);
891 true
892 } else {
893 false
894 }
895 }
896 Observation::FromView {
897 window_id,
898 view_id,
899 callback,
900 } => {
901 if let Some(mut view) = self
902 .ctx
903 .windows
904 .get_mut(window_id)
905 .and_then(|w| w.views.remove(view_id))
906 {
907 callback(
908 view.as_any_mut(),
909 observed_id,
910 self,
911 *window_id,
912 *view_id,
913 );
914 self.ctx
915 .windows
916 .get_mut(window_id)
917 .unwrap()
918 .views
919 .insert(*view_id, view);
920 true
921 } else {
922 false
923 }
924 }
925 };
926
927 if alive {
928 self.observations
929 .entry(observed_id)
930 .or_default()
931 .push(observation);
932 }
933 }
934 }
935 }
936 }
937
938 fn notify_view_observers(&mut self, window_id: usize, view_id: usize) {
939 self.window_invalidations
940 .entry(window_id)
941 .or_default()
942 .updated
943 .insert(view_id);
944 }
945
946 fn focus(&mut self, window_id: usize, focused_id: usize) {
947 if self
948 .ctx
949 .windows
950 .get(&window_id)
951 .and_then(|w| w.focused_view)
952 .map_or(false, |cur_focused| cur_focused == focused_id)
953 {
954 return;
955 }
956
957 self.pending_flushes += 1;
958
959 if let Some((blurred_id, mut blurred)) =
960 self.ctx.windows.get_mut(&window_id).and_then(|w| {
961 let blurred_view = w.focused_view;
962 w.focused_view = Some(focused_id);
963 blurred_view.and_then(|id| w.views.remove(&id).map(|view| (id, view)))
964 })
965 {
966 blurred.on_blur(self, window_id, blurred_id);
967 self.ctx
968 .windows
969 .get_mut(&window_id)
970 .unwrap()
971 .views
972 .insert(blurred_id, blurred);
973 }
974
975 if let Some(mut focused) = self
976 .ctx
977 .windows
978 .get_mut(&window_id)
979 .and_then(|w| w.views.remove(&focused_id))
980 {
981 focused.on_focus(self, window_id, focused_id);
982 self.ctx
983 .windows
984 .get_mut(&window_id)
985 .unwrap()
986 .views
987 .insert(focused_id, focused);
988 }
989
990 self.flush_effects();
991 }
992
993 fn spawn<F, T>(&mut self, future: F) -> EntityTask<T>
994 where
995 F: 'static + Future,
996 T: 'static,
997 {
998 let task_id = post_inc(&mut self.next_task_id);
999 let app = self.weak_self.as_ref().unwrap().upgrade().unwrap();
1000 let task = {
1001 let app = app.clone();
1002 self.foreground.spawn(async move {
1003 let output = future.await;
1004 *app.borrow_mut()
1005 .handle_future_output(task_id, Box::new(output))
1006 .downcast::<T>()
1007 .unwrap()
1008 })
1009 };
1010 EntityTask::new(
1011 task_id,
1012 task,
1013 TaskHandlerMap::Future(self.future_handlers.clone()),
1014 self.task_done.clone(),
1015 )
1016 }
1017
1018 fn spawn_stream<F, T>(&mut self, mut stream: F) -> EntityTask<T>
1019 where
1020 F: 'static + Stream + Unpin,
1021 T: 'static,
1022 {
1023 let task_id = post_inc(&mut self.next_task_id);
1024 let app = self.weak_self.as_ref().unwrap().upgrade().unwrap();
1025 let task = self.foreground.spawn(async move {
1026 loop {
1027 match stream.next().await {
1028 Some(item) => {
1029 let mut app = app.borrow_mut();
1030 if app.handle_stream_item(task_id, Box::new(item)) {
1031 break;
1032 }
1033 }
1034 None => {
1035 break;
1036 }
1037 }
1038 }
1039
1040 *app.borrow_mut()
1041 .stream_completed(task_id)
1042 .downcast::<T>()
1043 .unwrap()
1044 });
1045
1046 EntityTask::new(
1047 task_id,
1048 task,
1049 TaskHandlerMap::Stream(self.stream_handlers.clone()),
1050 self.task_done.clone(),
1051 )
1052 }
1053
1054 fn handle_future_output(&mut self, task_id: usize, output: Box<dyn Any>) -> Box<dyn Any> {
1055 self.pending_flushes += 1;
1056 let future_callback = self.future_handlers.borrow_mut().remove(&task_id).unwrap();
1057 let result = future_callback(output, self);
1058 self.flush_effects();
1059 self.task_done.notify_all();
1060 result
1061 }
1062
1063 fn handle_stream_item(&mut self, task_id: usize, output: Box<dyn Any>) -> bool {
1064 self.pending_flushes += 1;
1065
1066 let mut handler = self.stream_handlers.borrow_mut().remove(&task_id).unwrap();
1067 let halt = (handler.item_callback)(output, self);
1068 self.stream_handlers.borrow_mut().insert(task_id, handler);
1069
1070 self.flush_effects();
1071 halt
1072 }
1073
1074 fn stream_completed(&mut self, task_id: usize) -> Box<dyn Any> {
1075 self.pending_flushes += 1;
1076
1077 let handler = self.stream_handlers.borrow_mut().remove(&task_id).unwrap();
1078 let result = (handler.done_callback)(self);
1079
1080 self.flush_effects();
1081 self.task_done.notify_all();
1082 result
1083 }
1084
1085 pub fn finish_pending_tasks(&self) -> impl Future<Output = ()> {
1086 let mut pending_tasks = self
1087 .future_handlers
1088 .borrow()
1089 .keys()
1090 .cloned()
1091 .collect::<HashSet<_>>();
1092 pending_tasks.extend(self.stream_handlers.borrow().keys());
1093
1094 let task_done = self.task_done.clone();
1095 let future_handlers = self.future_handlers.clone();
1096 let stream_handlers = self.stream_handlers.clone();
1097
1098 async move {
1099 // A Condvar expects the condition to be protected by a Mutex, but in this case we know
1100 // that this logic will always run on the main thread.
1101 let mutex = async_std::sync::Mutex::new(());
1102 loop {
1103 {
1104 let future_handlers = future_handlers.borrow();
1105 let stream_handlers = stream_handlers.borrow();
1106 pending_tasks.retain(|task_id| {
1107 future_handlers.contains_key(task_id)
1108 || stream_handlers.contains_key(task_id)
1109 });
1110 if pending_tasks.is_empty() {
1111 break;
1112 }
1113 }
1114 task_done.wait(mutex.lock().await).await;
1115 }
1116 }
1117 }
1118}
1119
1120impl ModelAsRef for MutableAppContext {
1121 fn model<T: Entity>(&self, handle: &ModelHandle<T>) -> &T {
1122 if let Some(model) = self.ctx.models.get(&handle.model_id) {
1123 model
1124 .as_any()
1125 .downcast_ref()
1126 .expect("Downcast is type safe")
1127 } else {
1128 panic!("Circular model reference");
1129 }
1130 }
1131}
1132
1133impl UpdateModel for MutableAppContext {
1134 fn update_model<T, F, S>(&mut self, handle: &ModelHandle<T>, update: F) -> S
1135 where
1136 T: Entity,
1137 F: FnOnce(&mut T, &mut ModelContext<T>) -> S,
1138 {
1139 if let Some(mut model) = self.ctx.models.remove(&handle.model_id) {
1140 self.pending_flushes += 1;
1141 let mut ctx = ModelContext::new(self, handle.model_id);
1142 let result = update(
1143 model
1144 .as_any_mut()
1145 .downcast_mut()
1146 .expect("Downcast is type safe"),
1147 &mut ctx,
1148 );
1149 self.ctx.models.insert(handle.model_id, model);
1150 self.flush_effects();
1151 result
1152 } else {
1153 panic!("Circular model update");
1154 }
1155 }
1156}
1157
1158impl ViewAsRef for MutableAppContext {
1159 fn view<T: View>(&self, handle: &ViewHandle<T>) -> &T {
1160 if let Some(window) = self.ctx.windows.get(&handle.window_id) {
1161 if let Some(view) = window.views.get(&handle.view_id) {
1162 view.as_any().downcast_ref().expect("Downcast is type safe")
1163 } else {
1164 panic!("Circular view reference");
1165 }
1166 } else {
1167 panic!("Window does not exist");
1168 }
1169 }
1170}
1171
1172impl UpdateView for MutableAppContext {
1173 fn update_view<T, F, S>(&mut self, handle: &ViewHandle<T>, update: F) -> S
1174 where
1175 T: View,
1176 F: FnOnce(&mut T, &mut ViewContext<T>) -> S,
1177 {
1178 self.pending_flushes += 1;
1179 let mut view = if let Some(window) = self.ctx.windows.get_mut(&handle.window_id) {
1180 if let Some(view) = window.views.remove(&handle.view_id) {
1181 view
1182 } else {
1183 panic!("Circular view update");
1184 }
1185 } else {
1186 panic!("Window does not exist");
1187 };
1188
1189 let mut ctx = ViewContext::new(self, handle.window_id, handle.view_id);
1190 let result = update(
1191 view.as_any_mut()
1192 .downcast_mut()
1193 .expect("Downcast is type safe"),
1194 &mut ctx,
1195 );
1196 self.ctx
1197 .windows
1198 .get_mut(&handle.window_id)
1199 .unwrap()
1200 .views
1201 .insert(handle.view_id, view);
1202 self.flush_effects();
1203 result
1204 }
1205}
1206
1207pub struct AppContext {
1208 models: HashMap<usize, Box<dyn AnyModel>>,
1209 windows: HashMap<usize, Window>,
1210 background: Arc<executor::Background>,
1211 ref_counts: Arc<Mutex<RefCounts>>,
1212}
1213
1214impl AppContext {
1215 pub fn root_view_id(&self, window_id: usize) -> Option<usize> {
1216 self.windows
1217 .get(&window_id)
1218 .and_then(|window| window.root_view.as_ref().map(|v| v.id()))
1219 }
1220
1221 pub fn focused_view_id(&self, window_id: usize) -> Option<usize> {
1222 self.windows
1223 .get(&window_id)
1224 .and_then(|window| window.focused_view)
1225 }
1226
1227 pub fn render_view(&self, window_id: usize, view_id: usize) -> Result<ElementBox> {
1228 self.windows
1229 .get(&window_id)
1230 .and_then(|w| w.views.get(&view_id))
1231 .map(|v| v.render(self))
1232 .ok_or(anyhow!("view not found"))
1233 }
1234
1235 pub fn render_views(&self, window_id: usize) -> Result<HashMap<usize, ElementBox>> {
1236 self.windows
1237 .get(&window_id)
1238 .map(|w| {
1239 w.views
1240 .iter()
1241 .map(|(id, view)| (*id, view.render(self)))
1242 .collect::<HashMap<_, ElementBox>>()
1243 })
1244 .ok_or(anyhow!("window not found"))
1245 }
1246
1247 pub fn background_executor(&self) -> &Arc<executor::Background> {
1248 &self.background
1249 }
1250}
1251
1252impl ModelAsRef for AppContext {
1253 fn model<T: Entity>(&self, handle: &ModelHandle<T>) -> &T {
1254 if let Some(model) = self.models.get(&handle.model_id) {
1255 model
1256 .as_any()
1257 .downcast_ref()
1258 .expect("downcast should be type safe")
1259 } else {
1260 panic!("circular model reference");
1261 }
1262 }
1263}
1264
1265impl ViewAsRef for AppContext {
1266 fn view<T: View>(&self, handle: &ViewHandle<T>) -> &T {
1267 if let Some(window) = self.windows.get(&handle.window_id) {
1268 if let Some(view) = window.views.get(&handle.view_id) {
1269 view.as_any()
1270 .downcast_ref()
1271 .expect("downcast should be type safe")
1272 } else {
1273 panic!("circular view reference");
1274 }
1275 } else {
1276 panic!("window does not exist");
1277 }
1278 }
1279}
1280
1281#[derive(Default)]
1282struct Window {
1283 views: HashMap<usize, Box<dyn AnyView>>,
1284 root_view: Option<AnyViewHandle>,
1285 focused_view: Option<usize>,
1286}
1287
1288#[derive(Default, Clone)]
1289pub struct WindowInvalidation {
1290 pub updated: HashSet<usize>,
1291 pub removed: Vec<usize>,
1292}
1293
1294pub enum Effect {
1295 Event {
1296 entity_id: usize,
1297 payload: Box<dyn Any>,
1298 },
1299 ModelNotification {
1300 model_id: usize,
1301 },
1302 ViewNotification {
1303 window_id: usize,
1304 view_id: usize,
1305 },
1306 Focus {
1307 window_id: usize,
1308 view_id: usize,
1309 },
1310}
1311
1312pub trait AnyModel: Send + Sync {
1313 fn as_any(&self) -> &dyn Any;
1314 fn as_any_mut(&mut self) -> &mut dyn Any;
1315}
1316
1317impl<T> AnyModel for T
1318where
1319 T: Entity,
1320{
1321 fn as_any(&self) -> &dyn Any {
1322 self
1323 }
1324
1325 fn as_any_mut(&mut self) -> &mut dyn Any {
1326 self
1327 }
1328}
1329
1330pub trait AnyView: Send + Sync {
1331 fn as_any(&self) -> &dyn Any;
1332 fn as_any_mut(&mut self) -> &mut dyn Any;
1333 fn ui_name(&self) -> &'static str;
1334 fn render<'a>(&self, app: &AppContext) -> ElementBox;
1335 fn on_focus(&mut self, app: &mut MutableAppContext, window_id: usize, view_id: usize);
1336 fn on_blur(&mut self, app: &mut MutableAppContext, window_id: usize, view_id: usize);
1337 fn keymap_context(&self, app: &AppContext) -> keymap::Context;
1338}
1339
1340impl<T> AnyView for T
1341where
1342 T: View,
1343{
1344 fn as_any(&self) -> &dyn Any {
1345 self
1346 }
1347
1348 fn as_any_mut(&mut self) -> &mut dyn Any {
1349 self
1350 }
1351
1352 fn ui_name(&self) -> &'static str {
1353 T::ui_name()
1354 }
1355
1356 fn render<'a>(&self, app: &AppContext) -> ElementBox {
1357 View::render(self, app)
1358 }
1359
1360 fn on_focus(&mut self, app: &mut MutableAppContext, window_id: usize, view_id: usize) {
1361 let mut ctx = ViewContext::new(app, window_id, view_id);
1362 View::on_focus(self, &mut ctx);
1363 }
1364
1365 fn on_blur(&mut self, app: &mut MutableAppContext, window_id: usize, view_id: usize) {
1366 let mut ctx = ViewContext::new(app, window_id, view_id);
1367 View::on_blur(self, &mut ctx);
1368 }
1369
1370 fn keymap_context(&self, app: &AppContext) -> keymap::Context {
1371 View::keymap_context(self, app)
1372 }
1373}
1374
1375pub struct ModelContext<'a, T: ?Sized> {
1376 app: &'a mut MutableAppContext,
1377 model_id: usize,
1378 model_type: PhantomData<T>,
1379 halt_stream: bool,
1380}
1381
1382impl<'a, T: Entity> ModelContext<'a, T> {
1383 fn new(app: &'a mut MutableAppContext, model_id: usize) -> Self {
1384 Self {
1385 app,
1386 model_id,
1387 model_type: PhantomData,
1388 halt_stream: false,
1389 }
1390 }
1391
1392 pub fn app(&self) -> &AppContext {
1393 &self.app.ctx
1394 }
1395
1396 pub fn app_mut(&mut self) -> &mut MutableAppContext {
1397 self.app
1398 }
1399
1400 pub fn background_executor(&self) -> &Arc<executor::Background> {
1401 &self.app.ctx.background
1402 }
1403
1404 pub fn halt_stream(&mut self) {
1405 self.halt_stream = true;
1406 }
1407
1408 pub fn model_id(&self) -> usize {
1409 self.model_id
1410 }
1411
1412 pub fn add_model<S, F>(&mut self, build_model: F) -> ModelHandle<S>
1413 where
1414 S: Entity,
1415 F: FnOnce(&mut ModelContext<S>) -> S,
1416 {
1417 self.app.add_model(build_model)
1418 }
1419
1420 pub fn subscribe<S: Entity, F>(&mut self, handle: &ModelHandle<S>, mut callback: F)
1421 where
1422 S::Event: 'static,
1423 F: 'static + FnMut(&mut T, &S::Event, &mut ModelContext<T>),
1424 {
1425 self.app
1426 .subscriptions
1427 .entry(handle.model_id)
1428 .or_default()
1429 .push(Subscription::FromModel {
1430 model_id: self.model_id,
1431 callback: Box::new(move |model, payload, app, model_id| {
1432 let model = model.downcast_mut().expect("downcast is type safe");
1433 let payload = payload.downcast_ref().expect("downcast is type safe");
1434 let mut ctx = ModelContext::new(app, model_id);
1435 callback(model, payload, &mut ctx);
1436 }),
1437 });
1438 }
1439
1440 pub fn emit(&mut self, payload: T::Event) {
1441 self.app.pending_effects.push_back(Effect::Event {
1442 entity_id: self.model_id,
1443 payload: Box::new(payload),
1444 });
1445 }
1446
1447 pub fn observe<S, F>(&mut self, handle: &ModelHandle<S>, mut callback: F)
1448 where
1449 S: Entity,
1450 F: 'static + FnMut(&mut T, ModelHandle<S>, &mut ModelContext<T>),
1451 {
1452 self.app
1453 .observations
1454 .entry(handle.model_id)
1455 .or_default()
1456 .push(Observation::FromModel {
1457 model_id: self.model_id,
1458 callback: Box::new(move |model, observed_id, app, model_id| {
1459 let model = model.downcast_mut().expect("downcast is type safe");
1460 let observed = ModelHandle::new(observed_id, &app.ctx.ref_counts);
1461 let mut ctx = ModelContext::new(app, model_id);
1462 callback(model, observed, &mut ctx);
1463 }),
1464 });
1465 }
1466
1467 pub fn notify(&mut self) {
1468 self.app
1469 .pending_effects
1470 .push_back(Effect::ModelNotification {
1471 model_id: self.model_id,
1472 });
1473 }
1474
1475 fn handle(&self) -> ModelHandle<T> {
1476 ModelHandle::new(self.model_id, &self.app.ctx.ref_counts)
1477 }
1478
1479 pub fn spawn<S, F, U>(&mut self, future: S, callback: F) -> EntityTask<U>
1480 where
1481 S: 'static + Future,
1482 F: 'static + FnOnce(&mut T, S::Output, &mut ModelContext<T>) -> U,
1483 U: 'static,
1484 {
1485 let handle = self.handle();
1486 let task = self.app.spawn::<S, U>(future);
1487
1488 self.app.future_handlers.borrow_mut().insert(
1489 task.id,
1490 Box::new(move |output, ctx| {
1491 let output = *output.downcast().unwrap();
1492 handle.update(ctx, |model, ctx| Box::new(callback(model, output, ctx)))
1493 }),
1494 );
1495
1496 task
1497 }
1498
1499 pub fn spawn_stream<S, F, G, U>(
1500 &mut self,
1501 stream: S,
1502 mut item_callback: F,
1503 done_callback: G,
1504 ) -> EntityTask<U>
1505 where
1506 S: 'static + Stream + Unpin,
1507 F: 'static + FnMut(&mut T, S::Item, &mut ModelContext<T>),
1508 G: 'static + FnOnce(&mut T, &mut ModelContext<T>) -> U,
1509 U: 'static + Any,
1510 {
1511 let handle = self.handle();
1512 let task = self.app.spawn_stream(stream);
1513
1514 self.app.stream_handlers.borrow_mut().insert(
1515 task.id,
1516 StreamHandler {
1517 item_callback: {
1518 let handle = handle.clone();
1519 Box::new(move |output, app| {
1520 let output = *output.downcast().unwrap();
1521 handle.update(app, |model, ctx| {
1522 item_callback(model, output, ctx);
1523 ctx.halt_stream
1524 })
1525 })
1526 },
1527 done_callback: Box::new(move |app| {
1528 handle.update(app, |model, ctx| Box::new(done_callback(model, ctx)))
1529 }),
1530 },
1531 );
1532
1533 task
1534 }
1535}
1536
1537impl<M> ModelAsRef for ModelContext<'_, M> {
1538 fn model<T: Entity>(&self, handle: &ModelHandle<T>) -> &T {
1539 self.app.model(handle)
1540 }
1541}
1542
1543impl<M> UpdateModel for ModelContext<'_, M> {
1544 fn update_model<T, F, S>(&mut self, handle: &ModelHandle<T>, update: F) -> S
1545 where
1546 T: Entity,
1547 F: FnOnce(&mut T, &mut ModelContext<T>) -> S,
1548 {
1549 self.app.update_model(handle, update)
1550 }
1551}
1552
1553pub struct ViewContext<'a, T: ?Sized> {
1554 app: &'a mut MutableAppContext,
1555 window_id: usize,
1556 view_id: usize,
1557 view_type: PhantomData<T>,
1558 halt_action_dispatch: bool,
1559 halt_stream: bool,
1560}
1561
1562impl<'a, T: View> ViewContext<'a, T> {
1563 fn new(app: &'a mut MutableAppContext, window_id: usize, view_id: usize) -> Self {
1564 Self {
1565 app,
1566 window_id,
1567 view_id,
1568 view_type: PhantomData,
1569 halt_action_dispatch: true,
1570 halt_stream: false,
1571 }
1572 }
1573
1574 pub fn handle(&self) -> ViewHandle<T> {
1575 ViewHandle::new(self.window_id, self.view_id, &self.app.ctx.ref_counts)
1576 }
1577
1578 pub fn window_id(&self) -> usize {
1579 self.window_id
1580 }
1581
1582 pub fn app(&self) -> &AppContext {
1583 &self.app.ctx
1584 }
1585
1586 pub fn app_mut(&mut self) -> &mut MutableAppContext {
1587 self.app
1588 }
1589
1590 pub fn background_executor(&self) -> &Arc<executor::Background> {
1591 &self.app.ctx.background
1592 }
1593
1594 pub fn focus<S>(&mut self, handle: S)
1595 where
1596 S: Into<AnyViewHandle>,
1597 {
1598 let handle = handle.into();
1599 self.app.pending_effects.push_back(Effect::Focus {
1600 window_id: handle.window_id,
1601 view_id: handle.view_id,
1602 });
1603 }
1604
1605 pub fn focus_self(&mut self) {
1606 self.app.pending_effects.push_back(Effect::Focus {
1607 window_id: self.window_id,
1608 view_id: self.view_id,
1609 });
1610 }
1611
1612 pub fn add_model<S, F>(&mut self, build_model: F) -> ModelHandle<S>
1613 where
1614 S: Entity,
1615 F: FnOnce(&mut ModelContext<S>) -> S,
1616 {
1617 self.app.add_model(build_model)
1618 }
1619
1620 pub fn add_view<S, F>(&mut self, build_view: F) -> ViewHandle<S>
1621 where
1622 S: View,
1623 F: FnOnce(&mut ViewContext<S>) -> S,
1624 {
1625 self.app.add_view(self.window_id, build_view)
1626 }
1627
1628 pub fn add_option_view<S, F>(&mut self, build_view: F) -> Option<ViewHandle<S>>
1629 where
1630 S: View,
1631 F: FnOnce(&mut ViewContext<S>) -> Option<S>,
1632 {
1633 self.app.add_option_view(self.window_id, build_view)
1634 }
1635
1636 pub fn subscribe_to_model<E, F>(&mut self, handle: &ModelHandle<E>, mut callback: F)
1637 where
1638 E: Entity,
1639 E::Event: 'static,
1640 F: 'static + FnMut(&mut T, ModelHandle<E>, &E::Event, &mut ViewContext<T>),
1641 {
1642 let emitter_handle = handle.downgrade();
1643 self.app
1644 .subscriptions
1645 .entry(handle.id())
1646 .or_default()
1647 .push(Subscription::FromView {
1648 window_id: self.window_id,
1649 view_id: self.view_id,
1650 callback: Box::new(move |view, payload, app, window_id, view_id| {
1651 if let Some(emitter_handle) = emitter_handle.upgrade(app.downgrade()) {
1652 let model = view.downcast_mut().expect("downcast is type safe");
1653 let payload = payload.downcast_ref().expect("downcast is type safe");
1654 let mut ctx = ViewContext::new(app, window_id, view_id);
1655 callback(model, emitter_handle, payload, &mut ctx);
1656 }
1657 }),
1658 });
1659 }
1660
1661 pub fn subscribe_to_view<V, F>(&mut self, handle: &ViewHandle<V>, mut callback: F)
1662 where
1663 V: View,
1664 V::Event: 'static,
1665 F: 'static + FnMut(&mut T, ViewHandle<V>, &V::Event, &mut ViewContext<T>),
1666 {
1667 let emitter_handle = handle.downgrade();
1668
1669 self.app
1670 .subscriptions
1671 .entry(handle.id())
1672 .or_default()
1673 .push(Subscription::FromView {
1674 window_id: self.window_id,
1675 view_id: self.view_id,
1676 callback: Box::new(move |view, payload, app, window_id, view_id| {
1677 if let Some(emitter_handle) = emitter_handle.upgrade(app.downgrade()) {
1678 let model = view.downcast_mut().expect("downcast is type safe");
1679 let payload = payload.downcast_ref().expect("downcast is type safe");
1680 let mut ctx = ViewContext::new(app, window_id, view_id);
1681 callback(model, emitter_handle, payload, &mut ctx);
1682 }
1683 }),
1684 });
1685 }
1686
1687 pub fn emit(&mut self, payload: T::Event) {
1688 self.app.pending_effects.push_back(Effect::Event {
1689 entity_id: self.view_id,
1690 payload: Box::new(payload),
1691 });
1692 }
1693
1694 pub fn observe<S, F>(&mut self, handle: &ModelHandle<S>, mut callback: F)
1695 where
1696 S: Entity,
1697 F: 'static + FnMut(&mut T, ModelHandle<S>, &mut ViewContext<T>),
1698 {
1699 self.app
1700 .observations
1701 .entry(handle.id())
1702 .or_default()
1703 .push(Observation::FromView {
1704 window_id: self.window_id,
1705 view_id: self.view_id,
1706 callback: Box::new(move |view, observed_id, app, window_id, view_id| {
1707 let view = view.downcast_mut().expect("downcast is type safe");
1708 let observed = ModelHandle::new(observed_id, &app.ctx.ref_counts);
1709 let mut ctx = ViewContext::new(app, window_id, view_id);
1710 callback(view, observed, &mut ctx);
1711 }),
1712 });
1713 }
1714
1715 pub fn notify(&mut self) {
1716 self.app
1717 .pending_effects
1718 .push_back(Effect::ViewNotification {
1719 window_id: self.window_id,
1720 view_id: self.view_id,
1721 });
1722 }
1723
1724 pub fn propagate_action(&mut self) {
1725 self.halt_action_dispatch = false;
1726 }
1727
1728 pub fn halt_stream(&mut self) {
1729 self.halt_stream = true;
1730 }
1731
1732 pub fn spawn<S, F, U>(&mut self, future: S, callback: F) -> EntityTask<U>
1733 where
1734 S: 'static + Future,
1735 F: 'static + FnOnce(&mut T, S::Output, &mut ViewContext<T>) -> U,
1736 U: 'static,
1737 {
1738 let handle = self.handle();
1739 let task = self.app.spawn(future);
1740
1741 self.app.future_handlers.borrow_mut().insert(
1742 task.id,
1743 Box::new(move |output, app| {
1744 let output = *output.downcast().unwrap();
1745 handle.update(app, |view, ctx| Box::new(callback(view, output, ctx)))
1746 }),
1747 );
1748
1749 task
1750 }
1751
1752 pub fn spawn_stream<S, F, G, U>(
1753 &mut self,
1754 stream: S,
1755 mut item_callback: F,
1756 done_callback: G,
1757 ) -> EntityTask<U>
1758 where
1759 S: 'static + Stream + Unpin,
1760 F: 'static + FnMut(&mut T, S::Item, &mut ViewContext<T>),
1761 G: 'static + FnOnce(&mut T, &mut ViewContext<T>) -> U,
1762 U: 'static + Any,
1763 {
1764 let handle = self.handle();
1765 let task = self.app.spawn_stream(stream);
1766 self.app.stream_handlers.borrow_mut().insert(
1767 task.id,
1768 StreamHandler {
1769 item_callback: {
1770 let handle = handle.clone();
1771 Box::new(move |output, app| {
1772 let output = *output.downcast().unwrap();
1773 handle.update(app, |view, ctx| {
1774 item_callback(view, output, ctx);
1775 ctx.halt_stream
1776 })
1777 })
1778 },
1779 done_callback: Box::new(move |app| {
1780 handle.update(app, |view, ctx| Box::new(done_callback(view, ctx)))
1781 }),
1782 },
1783 );
1784 task
1785 }
1786}
1787
1788impl<V> ModelAsRef for ViewContext<'_, V> {
1789 fn model<T: Entity>(&self, handle: &ModelHandle<T>) -> &T {
1790 self.app.model(handle)
1791 }
1792}
1793
1794impl<V: View> UpdateModel for ViewContext<'_, V> {
1795 fn update_model<T, F, S>(&mut self, handle: &ModelHandle<T>, update: F) -> S
1796 where
1797 T: Entity,
1798 F: FnOnce(&mut T, &mut ModelContext<T>) -> S,
1799 {
1800 self.app.update_model(handle, update)
1801 }
1802}
1803
1804impl<V: View> ViewAsRef for ViewContext<'_, V> {
1805 fn view<T: View>(&self, handle: &ViewHandle<T>) -> &T {
1806 self.app.view(handle)
1807 }
1808}
1809
1810impl<V: View> UpdateView for ViewContext<'_, V> {
1811 fn update_view<T, F, S>(&mut self, handle: &ViewHandle<T>, update: F) -> S
1812 where
1813 T: View,
1814 F: FnOnce(&mut T, &mut ViewContext<T>) -> S,
1815 {
1816 self.app.update_view(handle, update)
1817 }
1818}
1819
1820pub trait Handle<T> {
1821 fn id(&self) -> usize;
1822 fn location(&self) -> EntityLocation;
1823}
1824
1825#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
1826pub enum EntityLocation {
1827 Model(usize),
1828 View(usize, usize),
1829}
1830
1831pub struct ModelHandle<T> {
1832 model_id: usize,
1833 model_type: PhantomData<T>,
1834 ref_counts: Weak<Mutex<RefCounts>>,
1835}
1836
1837impl<T: Entity> ModelHandle<T> {
1838 fn new(model_id: usize, ref_counts: &Arc<Mutex<RefCounts>>) -> Self {
1839 ref_counts.lock().inc(model_id);
1840 Self {
1841 model_id,
1842 model_type: PhantomData,
1843 ref_counts: Arc::downgrade(ref_counts),
1844 }
1845 }
1846
1847 fn downgrade(&self) -> WeakModelHandle<T> {
1848 WeakModelHandle::new(self.model_id)
1849 }
1850
1851 pub fn id(&self) -> usize {
1852 self.model_id
1853 }
1854
1855 pub fn as_ref<'a, A: ModelAsRef>(&self, app: &'a A) -> &'a T {
1856 app.model(self)
1857 }
1858
1859 pub fn read<'a, S, F>(&self, app: &'a App, read: F) -> S
1860 where
1861 F: FnOnce(&T, &AppContext) -> S,
1862 {
1863 app.read_model(self, read)
1864 }
1865
1866 pub fn update<A, F, S>(&self, app: &mut A, update: F) -> S
1867 where
1868 A: UpdateModel,
1869 F: FnOnce(&mut T, &mut ModelContext<T>) -> S,
1870 {
1871 app.update_model(self, update)
1872 }
1873}
1874
1875impl<T> Clone for ModelHandle<T> {
1876 fn clone(&self) -> Self {
1877 if let Some(ref_counts) = self.ref_counts.upgrade() {
1878 ref_counts.lock().inc(self.model_id);
1879 }
1880
1881 Self {
1882 model_id: self.model_id,
1883 model_type: PhantomData,
1884 ref_counts: self.ref_counts.clone(),
1885 }
1886 }
1887}
1888
1889impl<T> PartialEq for ModelHandle<T> {
1890 fn eq(&self, other: &Self) -> bool {
1891 self.model_id == other.model_id
1892 }
1893}
1894
1895impl<T> Eq for ModelHandle<T> {}
1896
1897impl<T> Hash for ModelHandle<T> {
1898 fn hash<H: Hasher>(&self, state: &mut H) {
1899 self.model_id.hash(state);
1900 }
1901}
1902
1903impl<T> std::borrow::Borrow<usize> for ModelHandle<T> {
1904 fn borrow(&self) -> &usize {
1905 &self.model_id
1906 }
1907}
1908
1909impl<T> Debug for ModelHandle<T> {
1910 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1911 f.debug_tuple(&format!("ModelHandle<{}>", type_name::<T>()))
1912 .field(&self.model_id)
1913 .finish()
1914 }
1915}
1916
1917unsafe impl<T> Send for ModelHandle<T> {}
1918unsafe impl<T> Sync for ModelHandle<T> {}
1919
1920impl<T> Drop for ModelHandle<T> {
1921 fn drop(&mut self) {
1922 if let Some(ref_counts) = self.ref_counts.upgrade() {
1923 ref_counts.lock().dec_model(self.model_id);
1924 }
1925 }
1926}
1927
1928impl<T> Handle<T> for ModelHandle<T> {
1929 fn id(&self) -> usize {
1930 self.model_id
1931 }
1932
1933 fn location(&self) -> EntityLocation {
1934 EntityLocation::Model(self.model_id)
1935 }
1936}
1937
1938pub struct WeakModelHandle<T> {
1939 model_id: usize,
1940 model_type: PhantomData<T>,
1941}
1942
1943impl<T: Entity> WeakModelHandle<T> {
1944 fn new(model_id: usize) -> Self {
1945 Self {
1946 model_id,
1947 model_type: PhantomData,
1948 }
1949 }
1950
1951 pub fn upgrade(&self, app: &AppContext) -> Option<ModelHandle<T>> {
1952 if app.models.contains_key(&self.model_id) {
1953 Some(ModelHandle::new(self.model_id, &app.ref_counts))
1954 } else {
1955 None
1956 }
1957 }
1958}
1959
1960pub struct ViewHandle<T> {
1961 window_id: usize,
1962 view_id: usize,
1963 view_type: PhantomData<T>,
1964 ref_counts: Weak<Mutex<RefCounts>>,
1965}
1966
1967impl<T: View> ViewHandle<T> {
1968 fn new(window_id: usize, view_id: usize, ref_counts: &Arc<Mutex<RefCounts>>) -> Self {
1969 ref_counts.lock().inc(view_id);
1970 Self {
1971 window_id,
1972 view_id,
1973 view_type: PhantomData,
1974 ref_counts: Arc::downgrade(ref_counts),
1975 }
1976 }
1977
1978 pub fn downgrade(&self) -> WeakViewHandle<T> {
1979 WeakViewHandle::new(self.window_id, self.view_id)
1980 }
1981
1982 pub fn window_id(&self) -> usize {
1983 self.window_id
1984 }
1985
1986 pub fn id(&self) -> usize {
1987 self.view_id
1988 }
1989
1990 pub fn as_ref<'a, A: ViewAsRef>(&self, app: &'a A) -> &'a T {
1991 app.view(self)
1992 }
1993
1994 pub fn read<'a, F, S>(&self, app: &'a App, read: F) -> S
1995 where
1996 F: FnOnce(&T, &AppContext) -> S,
1997 {
1998 app.read_view(self, read)
1999 }
2000
2001 pub fn update<A, F, S>(&self, app: &mut A, update: F) -> S
2002 where
2003 A: UpdateView,
2004 F: FnOnce(&mut T, &mut ViewContext<T>) -> S,
2005 {
2006 app.update_view(self, update)
2007 }
2008
2009 pub fn is_focused(&self, app: &AppContext) -> bool {
2010 app.focused_view_id(self.window_id)
2011 .map_or(false, |focused_id| focused_id == self.view_id)
2012 }
2013}
2014
2015impl<T> Clone for ViewHandle<T> {
2016 fn clone(&self) -> Self {
2017 if let Some(ref_counts) = self.ref_counts.upgrade() {
2018 ref_counts.lock().inc(self.view_id);
2019 }
2020
2021 Self {
2022 window_id: self.window_id,
2023 view_id: self.view_id,
2024 view_type: PhantomData,
2025 ref_counts: self.ref_counts.clone(),
2026 }
2027 }
2028}
2029
2030impl<T> PartialEq for ViewHandle<T> {
2031 fn eq(&self, other: &Self) -> bool {
2032 self.window_id == other.window_id && self.view_id == other.view_id
2033 }
2034}
2035
2036impl<T> Eq for ViewHandle<T> {}
2037
2038impl<T> Debug for ViewHandle<T> {
2039 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2040 f.debug_struct(&format!("ViewHandle<{}>", type_name::<T>()))
2041 .field("window_id", &self.window_id)
2042 .field("view_id", &self.view_id)
2043 .finish()
2044 }
2045}
2046
2047impl<T> Drop for ViewHandle<T> {
2048 fn drop(&mut self) {
2049 if let Some(ref_counts) = self.ref_counts.upgrade() {
2050 ref_counts.lock().dec_view(self.window_id, self.view_id);
2051 }
2052 }
2053}
2054
2055impl<T> Handle<T> for ViewHandle<T> {
2056 fn id(&self) -> usize {
2057 self.view_id
2058 }
2059
2060 fn location(&self) -> EntityLocation {
2061 EntityLocation::View(self.window_id, self.view_id)
2062 }
2063}
2064
2065#[derive(Clone)]
2066pub struct AnyViewHandle {
2067 window_id: usize,
2068 view_id: usize,
2069 view_type: TypeId,
2070 ref_counts: Weak<Mutex<RefCounts>>,
2071}
2072
2073impl AnyViewHandle {
2074 pub fn id(&self) -> usize {
2075 self.view_id
2076 }
2077
2078 pub fn is<T: 'static>(&self) -> bool {
2079 TypeId::of::<T>() == self.view_type
2080 }
2081
2082 pub fn downcast<T: View>(self) -> Option<ViewHandle<T>> {
2083 if self.is::<T>() {
2084 if let Some(ref_counts) = self.ref_counts.upgrade() {
2085 return Some(ViewHandle::new(self.window_id, self.view_id, &ref_counts));
2086 }
2087 }
2088 None
2089 }
2090}
2091
2092impl<T: View> From<&ViewHandle<T>> for AnyViewHandle {
2093 fn from(handle: &ViewHandle<T>) -> Self {
2094 if let Some(ref_counts) = handle.ref_counts.upgrade() {
2095 ref_counts.lock().inc(handle.view_id);
2096 }
2097 AnyViewHandle {
2098 window_id: handle.window_id,
2099 view_id: handle.view_id,
2100 view_type: TypeId::of::<T>(),
2101 ref_counts: handle.ref_counts.clone(),
2102 }
2103 }
2104}
2105
2106impl<T: View> From<ViewHandle<T>> for AnyViewHandle {
2107 fn from(handle: ViewHandle<T>) -> Self {
2108 (&handle).into()
2109 }
2110}
2111
2112pub struct WeakViewHandle<T> {
2113 window_id: usize,
2114 view_id: usize,
2115 view_type: PhantomData<T>,
2116}
2117
2118impl<T: View> WeakViewHandle<T> {
2119 fn new(window_id: usize, view_id: usize) -> Self {
2120 Self {
2121 window_id,
2122 view_id,
2123 view_type: PhantomData,
2124 }
2125 }
2126
2127 pub fn upgrade(&self, app: &AppContext) -> Option<ViewHandle<T>> {
2128 if app
2129 .windows
2130 .get(&self.window_id)
2131 .and_then(|w| w.views.get(&self.view_id))
2132 .is_some()
2133 {
2134 Some(ViewHandle::new(
2135 self.window_id,
2136 self.view_id,
2137 &app.ref_counts,
2138 ))
2139 } else {
2140 None
2141 }
2142 }
2143}
2144
2145impl<T> Clone for WeakViewHandle<T> {
2146 fn clone(&self) -> Self {
2147 Self {
2148 window_id: self.window_id,
2149 view_id: self.view_id,
2150 view_type: PhantomData,
2151 }
2152 }
2153}
2154
2155#[derive(Default)]
2156struct RefCounts {
2157 counts: HashMap<usize, usize>,
2158 dropped_models: HashSet<usize>,
2159 dropped_views: HashSet<(usize, usize)>,
2160}
2161
2162impl RefCounts {
2163 fn inc(&mut self, model_id: usize) {
2164 *self.counts.entry(model_id).or_insert(0) += 1;
2165 }
2166
2167 fn dec_model(&mut self, model_id: usize) {
2168 if let Some(count) = self.counts.get_mut(&model_id) {
2169 *count -= 1;
2170 if *count == 0 {
2171 self.counts.remove(&model_id);
2172 self.dropped_models.insert(model_id);
2173 }
2174 } else {
2175 panic!("Expected ref count to be positive")
2176 }
2177 }
2178
2179 fn dec_view(&mut self, window_id: usize, view_id: usize) {
2180 if let Some(count) = self.counts.get_mut(&view_id) {
2181 *count -= 1;
2182 if *count == 0 {
2183 self.counts.remove(&view_id);
2184 self.dropped_views.insert((window_id, view_id));
2185 }
2186 } else {
2187 panic!("Expected ref count to be positive")
2188 }
2189 }
2190
2191 fn take_dropped(&mut self) -> (HashSet<usize>, HashSet<(usize, usize)>) {
2192 let mut dropped_models = HashSet::new();
2193 let mut dropped_views = HashSet::new();
2194 std::mem::swap(&mut self.dropped_models, &mut dropped_models);
2195 std::mem::swap(&mut self.dropped_views, &mut dropped_views);
2196 (dropped_models, dropped_views)
2197 }
2198}
2199
2200enum Subscription {
2201 FromModel {
2202 model_id: usize,
2203 callback: Box<dyn FnMut(&mut dyn Any, &dyn Any, &mut MutableAppContext, usize)>,
2204 },
2205 FromView {
2206 window_id: usize,
2207 view_id: usize,
2208 callback: Box<dyn FnMut(&mut dyn Any, &dyn Any, &mut MutableAppContext, usize, usize)>,
2209 },
2210}
2211
2212enum Observation {
2213 FromModel {
2214 model_id: usize,
2215 callback: Box<dyn FnMut(&mut dyn Any, usize, &mut MutableAppContext, usize)>,
2216 },
2217 FromView {
2218 window_id: usize,
2219 view_id: usize,
2220 callback: Box<dyn FnMut(&mut dyn Any, usize, &mut MutableAppContext, usize, usize)>,
2221 },
2222}
2223
2224type FutureHandler = Box<dyn FnOnce(Box<dyn Any>, &mut MutableAppContext) -> Box<dyn Any>>;
2225
2226struct StreamHandler {
2227 item_callback: Box<dyn FnMut(Box<dyn Any>, &mut MutableAppContext) -> bool>,
2228 done_callback: Box<dyn FnOnce(&mut MutableAppContext) -> Box<dyn Any>>,
2229}
2230
2231#[must_use]
2232pub struct EntityTask<T> {
2233 id: usize,
2234 task: Option<executor::Task<T>>,
2235 handler_map: TaskHandlerMap,
2236 task_done: Arc<Condvar>,
2237}
2238
2239enum TaskHandlerMap {
2240 Detached,
2241 Future(Rc<RefCell<HashMap<usize, FutureHandler>>>),
2242 Stream(Rc<RefCell<HashMap<usize, StreamHandler>>>),
2243}
2244
2245impl<T> EntityTask<T> {
2246 fn new(
2247 id: usize,
2248 task: executor::Task<T>,
2249 handler_map: TaskHandlerMap,
2250 task_done: Arc<Condvar>,
2251 ) -> Self {
2252 Self {
2253 id,
2254 task: Some(task),
2255 handler_map,
2256 task_done,
2257 }
2258 }
2259
2260 pub fn detach(mut self) {
2261 self.handler_map = TaskHandlerMap::Detached;
2262 self.task.take().unwrap().detach();
2263 }
2264
2265 pub async fn cancel(mut self) -> Option<T> {
2266 let task = self.task.take().unwrap();
2267 task.cancel().await
2268 }
2269}
2270
2271impl<T> Future for EntityTask<T> {
2272 type Output = T;
2273
2274 fn poll(
2275 self: std::pin::Pin<&mut Self>,
2276 ctx: &mut std::task::Context<'_>,
2277 ) -> std::task::Poll<Self::Output> {
2278 let task = unsafe { self.map_unchecked_mut(|task| task.task.as_mut().unwrap()) };
2279 task.poll(ctx)
2280 }
2281}
2282
2283impl<T> Drop for EntityTask<T> {
2284 fn drop(self: &mut Self) {
2285 match &self.handler_map {
2286 TaskHandlerMap::Detached => {
2287 return;
2288 }
2289 TaskHandlerMap::Future(map) => {
2290 map.borrow_mut().remove(&self.id);
2291 }
2292 TaskHandlerMap::Stream(map) => {
2293 map.borrow_mut().remove(&self.id);
2294 }
2295 }
2296 self.task_done.notify_all();
2297 }
2298}
2299
2300#[cfg(test)]
2301mod tests {
2302 use super::*;
2303 use crate::elements::*;
2304
2305 #[test]
2306 fn test_model_handles() {
2307 struct Model {
2308 other: Option<ModelHandle<Model>>,
2309 events: Vec<String>,
2310 }
2311
2312 impl Entity for Model {
2313 type Event = usize;
2314 }
2315
2316 impl Model {
2317 fn new(other: Option<ModelHandle<Self>>, ctx: &mut ModelContext<Self>) -> Self {
2318 if let Some(other) = other.as_ref() {
2319 ctx.observe(other, |me, _, _| {
2320 me.events.push("notified".into());
2321 });
2322 ctx.subscribe(other, |me, event, _| {
2323 me.events.push(format!("observed event {}", event));
2324 });
2325 }
2326
2327 Self {
2328 other,
2329 events: Vec::new(),
2330 }
2331 }
2332 }
2333
2334 App::test((), |mut app| async move {
2335 let app = &mut app;
2336
2337 let handle_1 = app.add_model(|ctx| Model::new(None, ctx));
2338 let handle_2 = app.add_model(|ctx| Model::new(Some(handle_1.clone()), ctx));
2339 assert_eq!(app.0.borrow().ctx.models.len(), 2);
2340
2341 handle_1.update(app, |model, ctx| {
2342 model.events.push("updated".into());
2343 ctx.emit(1);
2344 ctx.notify();
2345 ctx.emit(2);
2346 });
2347 handle_1.read(app, |model, _| {
2348 assert_eq!(model.events, vec!["updated".to_string()]);
2349 });
2350 handle_2.read(app, |model, _| {
2351 assert_eq!(
2352 model.events,
2353 vec![
2354 "observed event 1".to_string(),
2355 "notified".to_string(),
2356 "observed event 2".to_string(),
2357 ]
2358 );
2359 });
2360
2361 handle_2.update(app, |model, _| {
2362 drop(handle_1);
2363 model.other.take();
2364 });
2365
2366 let app_state = app.0.borrow();
2367 assert_eq!(app_state.ctx.models.len(), 1);
2368 assert!(app_state.subscriptions.is_empty());
2369 assert!(app_state.observations.is_empty());
2370 })
2371 }
2372
2373 #[test]
2374 fn test_subscribe_and_emit_from_model() {
2375 #[derive(Default)]
2376 struct Model {
2377 events: Vec<usize>,
2378 }
2379
2380 impl Entity for Model {
2381 type Event = usize;
2382 }
2383
2384 App::test((), |mut app| async move {
2385 let app = &mut app;
2386 let handle_1 = app.add_model(|_| Model::default());
2387 let handle_2 = app.add_model(|_| Model::default());
2388 let handle_2b = handle_2.clone();
2389
2390 handle_1.update(app, |_, c| {
2391 c.subscribe(&handle_2, move |model: &mut Model, event, c| {
2392 model.events.push(*event);
2393
2394 c.subscribe(&handle_2b, |model, event, _| {
2395 model.events.push(*event * 2);
2396 });
2397 });
2398 });
2399
2400 handle_2.update(app, |_, c| c.emit(7));
2401 handle_1.read(app, |model, _| assert_eq!(model.events, vec![7]));
2402
2403 handle_2.update(app, |_, c| c.emit(5));
2404 handle_1.read(app, |model, _| assert_eq!(model.events, vec![7, 10, 5]));
2405 })
2406 }
2407
2408 #[test]
2409 fn test_observe_and_notify_from_model() {
2410 #[derive(Default)]
2411 struct Model {
2412 count: usize,
2413 events: Vec<usize>,
2414 }
2415
2416 impl Entity for Model {
2417 type Event = ();
2418 }
2419
2420 App::test((), |mut app| async move {
2421 let app = &mut app;
2422 let handle_1 = app.add_model(|_| Model::default());
2423 let handle_2 = app.add_model(|_| Model::default());
2424 let handle_2b = handle_2.clone();
2425
2426 handle_1.update(app, |_, c| {
2427 c.observe(&handle_2, move |model, observed, c| {
2428 model.events.push(observed.as_ref(c).count);
2429 c.observe(&handle_2b, |model, observed, c| {
2430 model.events.push(observed.as_ref(c).count * 2);
2431 });
2432 });
2433 });
2434
2435 handle_2.update(app, |model, c| {
2436 model.count = 7;
2437 c.notify()
2438 });
2439 handle_1.read(app, |model, _| assert_eq!(model.events, vec![7]));
2440
2441 handle_2.update(app, |model, c| {
2442 model.count = 5;
2443 c.notify()
2444 });
2445 handle_1.read(app, |model, _| assert_eq!(model.events, vec![7, 10, 5]))
2446 })
2447 }
2448
2449 #[test]
2450 fn test_spawn_from_model() {
2451 #[derive(Default)]
2452 struct Model {
2453 count: usize,
2454 }
2455
2456 impl Entity for Model {
2457 type Event = ();
2458 }
2459
2460 App::test((), |mut app| async move {
2461 let handle = app.add_model(|_| Model::default());
2462 handle
2463 .update(&mut app, |_, c| {
2464 c.spawn(async { 7 }, |model, output, _| {
2465 model.count = output;
2466 })
2467 })
2468 .await;
2469 handle.read(&app, |model, _| assert_eq!(model.count, 7));
2470
2471 handle
2472 .update(&mut app, |_, c| {
2473 c.spawn(async { 14 }, |model, output, _| {
2474 model.count = output;
2475 })
2476 })
2477 .await;
2478 handle.read(&app, |model, _| assert_eq!(model.count, 14));
2479 });
2480 }
2481
2482 #[test]
2483 fn test_spawn_stream_local_from_model() {
2484 #[derive(Default)]
2485 struct Model {
2486 events: Vec<Option<usize>>,
2487 }
2488
2489 impl Entity for Model {
2490 type Event = ();
2491 }
2492
2493 App::test((), |mut app| async move {
2494 let handle = app.add_model(|_| Model::default());
2495 handle
2496 .update(&mut app, |_, c| {
2497 c.spawn_stream(
2498 smol::stream::iter(vec![1, 2, 3]),
2499 |model, output, _| {
2500 model.events.push(Some(output));
2501 },
2502 |model, _| {
2503 model.events.push(None);
2504 },
2505 )
2506 })
2507 .await;
2508
2509 handle.read(&app, |model, _| {
2510 assert_eq!(model.events, [Some(1), Some(2), Some(3), None])
2511 });
2512 })
2513 }
2514
2515 #[test]
2516 fn test_view_handles() {
2517 struct View {
2518 other: Option<ViewHandle<View>>,
2519 events: Vec<String>,
2520 }
2521
2522 impl Entity for View {
2523 type Event = usize;
2524 }
2525
2526 impl super::View for View {
2527 fn render<'a>(&self, _: &AppContext) -> ElementBox {
2528 Empty::new().boxed()
2529 }
2530
2531 fn ui_name() -> &'static str {
2532 "View"
2533 }
2534 }
2535
2536 impl View {
2537 fn new(other: Option<ViewHandle<View>>, ctx: &mut ViewContext<Self>) -> Self {
2538 if let Some(other) = other.as_ref() {
2539 ctx.subscribe_to_view(other, |me, _, event, _| {
2540 me.events.push(format!("observed event {}", event));
2541 });
2542 }
2543 Self {
2544 other,
2545 events: Vec::new(),
2546 }
2547 }
2548 }
2549
2550 App::test((), |mut app| async move {
2551 let app = &mut app;
2552 let (window_id, _) = app.add_window(|ctx| View::new(None, ctx));
2553 let handle_1 = app.add_view(window_id, |ctx| View::new(None, ctx));
2554 let handle_2 = app.add_view(window_id, |ctx| View::new(Some(handle_1.clone()), ctx));
2555 assert_eq!(app.0.borrow().ctx.windows[&window_id].views.len(), 3);
2556
2557 handle_1.update(app, |view, ctx| {
2558 view.events.push("updated".into());
2559 ctx.emit(1);
2560 ctx.emit(2);
2561 });
2562 handle_1.read(app, |view, _| {
2563 assert_eq!(view.events, vec!["updated".to_string()]);
2564 });
2565 handle_2.read(app, |view, _| {
2566 assert_eq!(
2567 view.events,
2568 vec![
2569 "observed event 1".to_string(),
2570 "observed event 2".to_string(),
2571 ]
2572 );
2573 });
2574
2575 handle_2.update(app, |view, _| {
2576 drop(handle_1);
2577 view.other.take();
2578 });
2579
2580 let app_state = app.0.borrow();
2581 assert_eq!(app_state.ctx.windows[&window_id].views.len(), 2);
2582 assert!(app_state.subscriptions.is_empty());
2583 assert!(app_state.observations.is_empty());
2584 })
2585 }
2586
2587 #[test]
2588 fn test_subscribe_and_emit_from_view() {
2589 #[derive(Default)]
2590 struct View {
2591 events: Vec<usize>,
2592 }
2593
2594 impl Entity for View {
2595 type Event = usize;
2596 }
2597
2598 impl super::View for View {
2599 fn render<'a>(&self, _: &AppContext) -> ElementBox {
2600 Empty::new().boxed()
2601 }
2602
2603 fn ui_name() -> &'static str {
2604 "View"
2605 }
2606 }
2607
2608 struct Model;
2609
2610 impl Entity for Model {
2611 type Event = usize;
2612 }
2613
2614 App::test((), |mut app| async move {
2615 let app = &mut app;
2616 let (window_id, handle_1) = app.add_window(|_| View::default());
2617 let handle_2 = app.add_view(window_id, |_| View::default());
2618 let handle_2b = handle_2.clone();
2619 let handle_3 = app.add_model(|_| Model);
2620
2621 handle_1.update(app, |_, c| {
2622 c.subscribe_to_view(&handle_2, move |me, _, event, c| {
2623 me.events.push(*event);
2624
2625 c.subscribe_to_view(&handle_2b, |me, _, event, _| {
2626 me.events.push(*event * 2);
2627 });
2628 });
2629
2630 c.subscribe_to_model(&handle_3, |me, _, event, _| {
2631 me.events.push(*event);
2632 })
2633 });
2634
2635 handle_2.update(app, |_, c| c.emit(7));
2636 handle_1.read(app, |view, _| assert_eq!(view.events, vec![7]));
2637
2638 handle_2.update(app, |_, c| c.emit(5));
2639 handle_1.read(app, |view, _| assert_eq!(view.events, vec![7, 10, 5]));
2640
2641 handle_3.update(app, |_, c| c.emit(9));
2642 handle_1.read(app, |view, _| assert_eq!(view.events, vec![7, 10, 5, 9]));
2643 })
2644 }
2645
2646 #[test]
2647 fn test_dropping_subscribers() {
2648 struct View;
2649
2650 impl Entity for View {
2651 type Event = ();
2652 }
2653
2654 impl super::View for View {
2655 fn render<'a>(&self, _: &AppContext) -> ElementBox {
2656 Empty::new().boxed()
2657 }
2658
2659 fn ui_name() -> &'static str {
2660 "View"
2661 }
2662 }
2663
2664 struct Model;
2665
2666 impl Entity for Model {
2667 type Event = ();
2668 }
2669
2670 App::test((), |mut app| async move {
2671 let app = &mut app;
2672
2673 let (window_id, _) = app.add_window(|_| View);
2674 let observing_view = app.add_view(window_id, |_| View);
2675 let emitting_view = app.add_view(window_id, |_| View);
2676 let observing_model = app.add_model(|_| Model);
2677 let observed_model = app.add_model(|_| Model);
2678
2679 observing_view.update(app, |_, ctx| {
2680 ctx.subscribe_to_view(&emitting_view, |_, _, _, _| {});
2681 ctx.subscribe_to_model(&observed_model, |_, _, _, _| {});
2682 });
2683 observing_model.update(app, |_, ctx| {
2684 ctx.subscribe(&observed_model, |_, _, _| {});
2685 });
2686
2687 app.update(|_| {
2688 drop(observing_view);
2689 drop(observing_model);
2690 });
2691
2692 emitting_view.update(app, |_, ctx| ctx.emit(()));
2693 observed_model.update(app, |_, ctx| ctx.emit(()));
2694 })
2695 }
2696
2697 #[test]
2698 fn test_observe_and_notify_from_view() {
2699 #[derive(Default)]
2700 struct View {
2701 events: Vec<usize>,
2702 }
2703
2704 impl Entity for View {
2705 type Event = usize;
2706 }
2707
2708 impl super::View for View {
2709 fn render<'a>(&self, _: &AppContext) -> ElementBox {
2710 Empty::new().boxed()
2711 }
2712
2713 fn ui_name() -> &'static str {
2714 "View"
2715 }
2716 }
2717
2718 #[derive(Default)]
2719 struct Model {
2720 count: usize,
2721 }
2722
2723 impl Entity for Model {
2724 type Event = ();
2725 }
2726
2727 App::test((), |mut app| async move {
2728 let app = &mut app;
2729 let (_, view) = app.add_window(|_| View::default());
2730 let model = app.add_model(|_| Model::default());
2731
2732 view.update(app, |_, c| {
2733 c.observe(&model, |me, observed, c| {
2734 me.events.push(observed.as_ref(c).count)
2735 });
2736 });
2737
2738 model.update(app, |model, c| {
2739 model.count = 11;
2740 c.notify();
2741 });
2742 view.read(app, |view, _| assert_eq!(view.events, vec![11]));
2743 })
2744 }
2745
2746 #[test]
2747 fn test_dropping_observers() {
2748 struct View;
2749
2750 impl Entity for View {
2751 type Event = ();
2752 }
2753
2754 impl super::View for View {
2755 fn render<'a>(&self, _: &AppContext) -> ElementBox {
2756 Empty::new().boxed()
2757 }
2758
2759 fn ui_name() -> &'static str {
2760 "View"
2761 }
2762 }
2763
2764 struct Model;
2765
2766 impl Entity for Model {
2767 type Event = ();
2768 }
2769
2770 App::test((), |mut app| async move {
2771 let app = &mut app;
2772
2773 let (window_id, _) = app.add_window(|_| View);
2774 let observing_view = app.add_view(window_id, |_| View);
2775 let observing_model = app.add_model(|_| Model);
2776 let observed_model = app.add_model(|_| Model);
2777
2778 observing_view.update(app, |_, ctx| {
2779 ctx.observe(&observed_model, |_, _, _| {});
2780 });
2781 observing_model.update(app, |_, ctx| {
2782 ctx.observe(&observed_model, |_, _, _| {});
2783 });
2784
2785 app.update(|_| {
2786 drop(observing_view);
2787 drop(observing_model);
2788 });
2789
2790 observed_model.update(app, |_, ctx| ctx.notify());
2791 })
2792 }
2793
2794 #[test]
2795 fn test_focus() {
2796 #[derive(Default)]
2797 struct View {
2798 events: Vec<String>,
2799 }
2800
2801 impl Entity for View {
2802 type Event = String;
2803 }
2804
2805 impl super::View for View {
2806 fn render<'a>(&self, _: &AppContext) -> ElementBox {
2807 Empty::new().boxed()
2808 }
2809
2810 fn ui_name() -> &'static str {
2811 "View"
2812 }
2813
2814 fn on_focus(&mut self, ctx: &mut ViewContext<Self>) {
2815 self.events.push("self focused".into());
2816 ctx.emit("focused".into());
2817 }
2818
2819 fn on_blur(&mut self, ctx: &mut ViewContext<Self>) {
2820 self.events.push("self blurred".into());
2821 ctx.emit("blurred".into());
2822 }
2823 }
2824
2825 App::test((), |mut app| async move {
2826 let app = &mut app;
2827 let (window_id, view_1) = app.add_window(|_| View::default());
2828 let view_2 = app.add_view(window_id, |_| View::default());
2829
2830 view_1.update(app, |_, ctx| {
2831 ctx.subscribe_to_view(&view_2, |view_1, _, event, _| {
2832 view_1.events.push(format!("view 2 {}", event));
2833 });
2834 ctx.focus(&view_2);
2835 });
2836
2837 view_1.update(app, |_, ctx| {
2838 ctx.focus(&view_1);
2839 });
2840
2841 view_1.read(app, |view_1, _| {
2842 assert_eq!(
2843 view_1.events,
2844 [
2845 "self focused".to_string(),
2846 "self blurred".to_string(),
2847 "view 2 focused".to_string(),
2848 "self focused".to_string(),
2849 "view 2 blurred".to_string(),
2850 ],
2851 );
2852 });
2853 })
2854 }
2855
2856 #[test]
2857 fn test_spawn_from_view() {
2858 #[derive(Default)]
2859 struct View {
2860 count: usize,
2861 }
2862
2863 impl Entity for View {
2864 type Event = ();
2865 }
2866
2867 impl super::View for View {
2868 fn render<'a>(&self, _: &AppContext) -> ElementBox {
2869 Empty::new().boxed()
2870 }
2871
2872 fn ui_name() -> &'static str {
2873 "View"
2874 }
2875 }
2876
2877 App::test((), |mut app| async move {
2878 let (_, handle) = app.add_window(|_| View::default());
2879 handle
2880 .update(&mut app, |_, c| {
2881 c.spawn(async { 7 }, |me, output, _| {
2882 me.count = output;
2883 })
2884 })
2885 .await;
2886 handle.read(&app, |view, _| assert_eq!(view.count, 7));
2887 handle
2888 .update(&mut app, |_, c| {
2889 c.spawn(async { 14 }, |me, output, _| {
2890 me.count = output;
2891 })
2892 })
2893 .await;
2894 handle.read(&app, |view, _| assert_eq!(view.count, 14));
2895 });
2896 }
2897
2898 #[test]
2899 fn test_spawn_stream_local_from_view() {
2900 #[derive(Default)]
2901 struct View {
2902 events: Vec<Option<usize>>,
2903 }
2904
2905 impl Entity for View {
2906 type Event = ();
2907 }
2908
2909 impl super::View for View {
2910 fn render<'a>(&self, _: &AppContext) -> ElementBox {
2911 Empty::new().boxed()
2912 }
2913
2914 fn ui_name() -> &'static str {
2915 "View"
2916 }
2917 }
2918
2919 App::test((), |mut app| async move {
2920 let (_, handle) = app.add_window(|_| View::default());
2921 handle
2922 .update(&mut app, |_, c| {
2923 c.spawn_stream(
2924 smol::stream::iter(vec![1_usize, 2, 3]),
2925 |me, output, _| {
2926 me.events.push(Some(output));
2927 },
2928 |me, _| {
2929 me.events.push(None);
2930 },
2931 )
2932 })
2933 .await;
2934
2935 handle.read(&app, |view, _| {
2936 assert_eq!(view.events, [Some(1), Some(2), Some(3), None])
2937 });
2938 });
2939 }
2940
2941 #[test]
2942 fn test_dispatch_action() {
2943 struct ViewA {
2944 id: usize,
2945 }
2946
2947 impl Entity for ViewA {
2948 type Event = ();
2949 }
2950
2951 impl View for ViewA {
2952 fn render<'a>(&self, _: &AppContext) -> ElementBox {
2953 Empty::new().boxed()
2954 }
2955
2956 fn ui_name() -> &'static str {
2957 "View"
2958 }
2959 }
2960
2961 struct ViewB {
2962 id: usize,
2963 }
2964
2965 impl Entity for ViewB {
2966 type Event = ();
2967 }
2968
2969 impl View for ViewB {
2970 fn render<'a>(&self, _: &AppContext) -> ElementBox {
2971 Empty::new().boxed()
2972 }
2973
2974 fn ui_name() -> &'static str {
2975 "View"
2976 }
2977 }
2978
2979 struct ActionArg {
2980 foo: String,
2981 }
2982
2983 App::test((), |mut app| async move {
2984 let actions = Rc::new(RefCell::new(Vec::new()));
2985
2986 let actions_clone = actions.clone();
2987 app.add_global_action("action", move |_: &ActionArg, _: &mut MutableAppContext| {
2988 actions_clone.borrow_mut().push("global a".to_string());
2989 });
2990
2991 let actions_clone = actions.clone();
2992 app.add_global_action("action", move |_: &ActionArg, _: &mut MutableAppContext| {
2993 actions_clone.borrow_mut().push("global b".to_string());
2994 });
2995
2996 let actions_clone = actions.clone();
2997 app.add_action("action", move |view: &mut ViewA, arg: &ActionArg, ctx| {
2998 assert_eq!(arg.foo, "bar");
2999 ctx.propagate_action();
3000 actions_clone.borrow_mut().push(format!("{} a", view.id));
3001 });
3002
3003 let actions_clone = actions.clone();
3004 app.add_action("action", move |view: &mut ViewA, _: &ActionArg, ctx| {
3005 if view.id != 1 {
3006 ctx.propagate_action();
3007 }
3008 actions_clone.borrow_mut().push(format!("{} b", view.id));
3009 });
3010
3011 let actions_clone = actions.clone();
3012 app.add_action("action", move |view: &mut ViewB, _: &ActionArg, ctx| {
3013 ctx.propagate_action();
3014 actions_clone.borrow_mut().push(format!("{} c", view.id));
3015 });
3016
3017 let actions_clone = actions.clone();
3018 app.add_action("action", move |view: &mut ViewB, _: &ActionArg, ctx| {
3019 ctx.propagate_action();
3020 actions_clone.borrow_mut().push(format!("{} d", view.id));
3021 });
3022
3023 let (window_id, view_1) = app.add_window(|_| ViewA { id: 1 });
3024 let view_2 = app.add_view(window_id, |_| ViewB { id: 2 });
3025 let view_3 = app.add_view(window_id, |_| ViewA { id: 3 });
3026 let view_4 = app.add_view(window_id, |_| ViewB { id: 4 });
3027
3028 app.dispatch_action(
3029 window_id,
3030 vec![view_1.id(), view_2.id(), view_3.id(), view_4.id()],
3031 "action",
3032 ActionArg { foo: "bar".into() },
3033 );
3034
3035 assert_eq!(
3036 *actions.borrow(),
3037 vec!["4 d", "4 c", "3 b", "3 a", "2 d", "2 c", "1 b"]
3038 );
3039
3040 // Remove view_1, which doesn't propagate the action
3041 actions.borrow_mut().clear();
3042 app.dispatch_action(
3043 window_id,
3044 vec![view_2.id(), view_3.id(), view_4.id()],
3045 "action",
3046 ActionArg { foo: "bar".into() },
3047 );
3048
3049 assert_eq!(
3050 *actions.borrow(),
3051 vec!["4 d", "4 c", "3 b", "3 a", "2 d", "2 c", "global b", "global a"]
3052 );
3053 })
3054 }
3055
3056 #[test]
3057 fn test_dispatch_keystroke() -> Result<()> {
3058 use std::cell::Cell;
3059
3060 #[derive(Clone)]
3061 struct ActionArg {
3062 key: String,
3063 }
3064
3065 struct View {
3066 id: usize,
3067 keymap_context: keymap::Context,
3068 }
3069
3070 impl Entity for View {
3071 type Event = ();
3072 }
3073
3074 impl super::View for View {
3075 fn render<'a>(&self, _: &AppContext) -> ElementBox {
3076 Empty::new().boxed()
3077 }
3078
3079 fn ui_name() -> &'static str {
3080 "View"
3081 }
3082
3083 fn keymap_context(&self, _: &AppContext) -> keymap::Context {
3084 self.keymap_context.clone()
3085 }
3086 }
3087
3088 impl View {
3089 fn new(id: usize) -> Self {
3090 View {
3091 id,
3092 keymap_context: keymap::Context::default(),
3093 }
3094 }
3095 }
3096
3097 App::test((), |mut app| async move {
3098 let mut view_1 = View::new(1);
3099 let mut view_2 = View::new(2);
3100 let mut view_3 = View::new(3);
3101 view_1.keymap_context.set.insert("a".into());
3102 view_2.keymap_context.set.insert("b".into());
3103 view_3.keymap_context.set.insert("c".into());
3104
3105 let (window_id, view_1) = app.add_window(|_| view_1);
3106 let view_2 = app.add_view(window_id, |_| view_2);
3107 let view_3 = app.add_view(window_id, |_| view_3);
3108
3109 // This keymap's only binding dispatches an action on view 2 because that view will have
3110 // "a" and "b" in its context, but not "c".
3111 let binding = keymap::Binding::new("a", "action", Some("a && b && !c"))
3112 .with_arg(ActionArg { key: "a".into() });
3113 app.add_bindings(vec![binding]);
3114
3115 let handled_action = Rc::new(Cell::new(false));
3116 let handled_action_clone = handled_action.clone();
3117 app.add_action("action", move |view: &mut View, arg: &ActionArg, _ctx| {
3118 handled_action_clone.set(true);
3119 assert_eq!(view.id, 2);
3120 assert_eq!(arg.key, "a");
3121 });
3122
3123 app.dispatch_keystroke(
3124 window_id,
3125 vec![view_1.id(), view_2.id(), view_3.id()],
3126 &Keystroke::parse("a")?,
3127 )?;
3128
3129 assert!(handled_action.get());
3130 Ok(())
3131 })
3132 }
3133
3134 // #[test]
3135 // fn test_ui_and_window_updates() {
3136 // struct View {
3137 // count: usize,
3138 // }
3139
3140 // impl Entity for View {
3141 // type Event = ();
3142 // }
3143
3144 // impl super::View for View {
3145 // fn render<'a>(&self, _: &AppContext) -> ElementBox {
3146 // Empty::new().boxed()
3147 // }
3148
3149 // fn ui_name() -> &'static str {
3150 // "View"
3151 // }
3152 // }
3153
3154 // App::test(|mut app| async move {
3155 // let (window_id, _) = app.add_window(|_| View { count: 3 });
3156 // let view_1 = app.add_view(window_id, |_| View { count: 1 });
3157 // let view_2 = app.add_view(window_id, |_| View { count: 2 });
3158
3159 // // Ensure that registering for UI updates after mutating the app still gives us all the
3160 // // updates.
3161 // let ui_updates = Rc::new(RefCell::new(Vec::new()));
3162 // let ui_updates_ = ui_updates.clone();
3163 // app.on_ui_update(move |update, _| ui_updates_.borrow_mut().push(update));
3164
3165 // assert_eq!(
3166 // ui_updates.borrow_mut().drain(..).collect::<Vec<_>>(),
3167 // vec![UiUpdate::OpenWindow {
3168 // window_id,
3169 // width: 1024.0,
3170 // height: 768.0,
3171 // }]
3172 // );
3173
3174 // let window_invalidations = Rc::new(RefCell::new(Vec::new()));
3175 // let window_invalidations_ = window_invalidations.clone();
3176 // app.on_window_invalidated(window_id, move |update, _| {
3177 // window_invalidations_.borrow_mut().push(update)
3178 // });
3179
3180 // let view_2_id = view_2.id();
3181 // view_1.update(&mut app, |view, ctx| {
3182 // view.count = 7;
3183 // ctx.notify();
3184 // drop(view_2);
3185 // });
3186
3187 // let invalidation = window_invalidations.borrow_mut().drain(..).next().unwrap();
3188 // assert_eq!(invalidation.updated.len(), 1);
3189 // assert!(invalidation.updated.contains(&view_1.id()));
3190 // assert_eq!(invalidation.removed, vec![view_2_id]);
3191
3192 // let view_3 = view_1.update(&mut app, |_, ctx| ctx.add_view(|_| View { count: 8 }));
3193
3194 // let invalidation = window_invalidations.borrow_mut().drain(..).next().unwrap();
3195 // assert_eq!(invalidation.updated.len(), 1);
3196 // assert!(invalidation.updated.contains(&view_3.id()));
3197 // assert!(invalidation.removed.is_empty());
3198
3199 // view_3
3200 // .update(&mut app, |_, ctx| {
3201 // ctx.spawn_local(async { 9 }, |me, output, ctx| {
3202 // me.count = output;
3203 // ctx.notify();
3204 // })
3205 // })
3206 // .await;
3207
3208 // let invalidation = window_invalidations.borrow_mut().drain(..).next().unwrap();
3209 // assert_eq!(invalidation.updated.len(), 1);
3210 // assert!(invalidation.updated.contains(&view_3.id()));
3211 // assert!(invalidation.removed.is_empty());
3212 // });
3213 // }
3214
3215 #[test]
3216 fn test_finish_pending_tasks() {
3217 struct View;
3218
3219 impl Entity for View {
3220 type Event = ();
3221 }
3222
3223 impl super::View for View {
3224 fn render<'a>(&self, _: &AppContext) -> ElementBox {
3225 Empty::new().boxed()
3226 }
3227
3228 fn ui_name() -> &'static str {
3229 "View"
3230 }
3231 }
3232
3233 struct Model;
3234
3235 impl Entity for Model {
3236 type Event = ();
3237 }
3238
3239 App::test((), |mut app| async move {
3240 let model = app.add_model(|_| Model);
3241 let (_, view) = app.add_window(|_| View);
3242
3243 model.update(&mut app, |_, ctx| {
3244 ctx.spawn(async {}, |_, _, _| {}).detach();
3245 // Cancel this task
3246 drop(ctx.spawn(async {}, |_, _, _| {}));
3247 });
3248
3249 view.update(&mut app, |_, ctx| {
3250 ctx.spawn(async {}, |_, _, _| {}).detach();
3251 // Cancel this task
3252 drop(ctx.spawn(async {}, |_, _, _| {}));
3253 });
3254
3255 assert!(!app.0.borrow().future_handlers.borrow().is_empty());
3256 app.finish_pending_tasks().await;
3257 assert!(app.0.borrow().future_handlers.borrow().is_empty());
3258 app.finish_pending_tasks().await; // Don't block if there are no tasks
3259
3260 model.update(&mut app, |_, ctx| {
3261 ctx.spawn_stream(smol::stream::iter(vec![1, 2, 3]), |_, _, _| {}, |_, _| {})
3262 .detach();
3263 // Cancel this task
3264 drop(ctx.spawn_stream(smol::stream::iter(vec![1, 2, 3]), |_, _, _| {}, |_, _| {}));
3265 });
3266
3267 view.update(&mut app, |_, ctx| {
3268 ctx.spawn_stream(smol::stream::iter(vec![1, 2, 3]), |_, _, _| {}, |_, _| {})
3269 .detach();
3270 // Cancel this task
3271 drop(ctx.spawn_stream(smol::stream::iter(vec![1, 2, 3]), |_, _, _| {}, |_, _| {}));
3272 });
3273
3274 assert!(!app.0.borrow().stream_handlers.borrow().is_empty());
3275 app.finish_pending_tasks().await;
3276 assert!(app.0.borrow().stream_handlers.borrow().is_empty());
3277 app.finish_pending_tasks().await; // Don't block if there are no tasks
3278
3279 // Tasks are considered finished when we drop handles
3280 let mut tasks = Vec::new();
3281 model.update(&mut app, |_, ctx| {
3282 tasks.push(Box::new(ctx.spawn(async {}, |_, _, _| {})));
3283 tasks.push(Box::new(ctx.spawn_stream(
3284 smol::stream::iter(vec![1, 2, 3]),
3285 |_, _, _| {},
3286 |_, _| {},
3287 )));
3288 });
3289
3290 view.update(&mut app, |_, ctx| {
3291 tasks.push(Box::new(ctx.spawn(async {}, |_, _, _| {})));
3292 tasks.push(Box::new(ctx.spawn_stream(
3293 smol::stream::iter(vec![1, 2, 3]),
3294 |_, _, _| {},
3295 |_, _| {},
3296 )));
3297 });
3298
3299 assert!(!app.0.borrow().stream_handlers.borrow().is_empty());
3300
3301 let finish_pending_tasks = app.finish_pending_tasks();
3302 drop(tasks);
3303 finish_pending_tasks.await;
3304 assert!(app.0.borrow().stream_handlers.borrow().is_empty());
3305 app.finish_pending_tasks().await; // Don't block if there are no tasks
3306 });
3307 }
3308}