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