1use crate::{
2 elements::ElementBox,
3 executor,
4 keymap::{self, Keystroke},
5 platform::{self, Platform, PromptLevel, WindowOptions},
6 presenter::Presenter,
7 util::{post_inc, timeout},
8 AssetCache, AssetSource, ClipboardItem, EventContext, FontCache, PathPromptOptions,
9 TextLayoutCache,
10};
11use anyhow::{anyhow, Result};
12use async_task::Task;
13use keymap::MatchResult;
14use parking_lot::{Mutex, RwLock};
15use platform::Event;
16use postage::{mpsc, sink::Sink as _, stream::Stream as _};
17use smol::prelude::*;
18use std::{
19 any::{type_name, Any, TypeId},
20 cell::RefCell,
21 collections::{hash_map::Entry, HashMap, HashSet, VecDeque},
22 fmt::{self, Debug},
23 hash::{Hash, Hasher},
24 marker::PhantomData,
25 ops::{Deref, DerefMut},
26 path::{Path, PathBuf},
27 rc::{self, Rc},
28 sync::{Arc, Weak},
29 time::Duration,
30};
31
32pub trait Entity: 'static {
33 type Event;
34
35 fn release(&mut self, _: &mut MutableAppContext) {}
36}
37
38pub trait View: Entity + Sized {
39 fn ui_name() -> &'static str;
40 fn render(&self, cx: &RenderContext<'_, Self>) -> ElementBox;
41 fn on_focus(&mut self, _: &mut ViewContext<Self>) {}
42 fn on_blur(&mut self, _: &mut ViewContext<Self>) {}
43 fn keymap_context(&self, _: &AppContext) -> keymap::Context {
44 Self::default_keymap_context()
45 }
46 fn default_keymap_context() -> keymap::Context {
47 let mut cx = keymap::Context::default();
48 cx.set.insert(Self::ui_name().into());
49 cx
50 }
51}
52
53pub trait ReadModel {
54 fn read_model<T: Entity>(&self, handle: &ModelHandle<T>) -> &T;
55}
56
57pub trait ReadModelWith {
58 fn read_model_with<E: Entity, F: FnOnce(&E, &AppContext) -> T, T>(
59 &self,
60 handle: &ModelHandle<E>,
61 read: F,
62 ) -> T;
63}
64
65pub trait UpdateModel {
66 fn update_model<T, F, S>(&mut self, handle: &ModelHandle<T>, update: F) -> S
67 where
68 T: Entity,
69 F: FnOnce(&mut T, &mut ModelContext<T>) -> S;
70}
71
72pub trait UpgradeModelHandle {
73 fn upgrade_model_handle<T: Entity>(&self, handle: WeakModelHandle<T>)
74 -> Option<ModelHandle<T>>;
75}
76
77pub trait ReadView {
78 fn read_view<T: View>(&self, handle: &ViewHandle<T>) -> &T;
79}
80
81pub trait ReadViewWith {
82 fn read_view_with<V, F, T>(&self, handle: &ViewHandle<V>, read: F) -> T
83 where
84 V: View,
85 F: FnOnce(&V, &AppContext) -> T;
86}
87
88pub trait UpdateView {
89 fn update_view<T, F, S>(&mut self, handle: &ViewHandle<T>, update: F) -> S
90 where
91 T: View,
92 F: FnOnce(&mut T, &mut ViewContext<T>) -> S;
93}
94
95pub trait Action: 'static + AnyAction {
96 type Argument: 'static + Clone;
97}
98
99pub trait AnyAction {
100 fn id(&self) -> TypeId;
101 fn name(&self) -> &'static str;
102 fn as_any(&self) -> &dyn Any;
103 fn boxed_clone(&self) -> Box<dyn AnyAction>;
104 fn boxed_clone_as_any(&self) -> Box<dyn Any>;
105}
106
107#[macro_export]
108macro_rules! action {
109 ($name:ident, $arg:ty) => {
110 #[derive(Clone)]
111 pub struct $name(pub $arg);
112
113 impl $crate::Action for $name {
114 type Argument = $arg;
115 }
116
117 impl $crate::AnyAction for $name {
118 fn id(&self) -> std::any::TypeId {
119 std::any::TypeId::of::<$name>()
120 }
121
122 fn name(&self) -> &'static str {
123 stringify!($name)
124 }
125
126 fn as_any(&self) -> &dyn std::any::Any {
127 self
128 }
129
130 fn boxed_clone(&self) -> Box<dyn $crate::AnyAction> {
131 Box::new(self.clone())
132 }
133
134 fn boxed_clone_as_any(&self) -> Box<dyn std::any::Any> {
135 Box::new(self.clone())
136 }
137 }
138 };
139
140 ($name:ident) => {
141 #[derive(Clone, Debug, Eq, PartialEq)]
142 pub struct $name;
143
144 impl $crate::Action for $name {
145 type Argument = ();
146 }
147
148 impl $crate::AnyAction for $name {
149 fn id(&self) -> std::any::TypeId {
150 std::any::TypeId::of::<$name>()
151 }
152
153 fn name(&self) -> &'static str {
154 stringify!($name)
155 }
156
157 fn as_any(&self) -> &dyn std::any::Any {
158 self
159 }
160
161 fn boxed_clone(&self) -> Box<dyn $crate::AnyAction> {
162 Box::new(self.clone())
163 }
164
165 fn boxed_clone_as_any(&self) -> Box<dyn std::any::Any> {
166 Box::new(self.clone())
167 }
168 }
169 };
170}
171
172pub struct Menu<'a> {
173 pub name: &'a str,
174 pub items: Vec<MenuItem<'a>>,
175}
176
177pub enum MenuItem<'a> {
178 Action {
179 name: &'a str,
180 keystroke: Option<&'a str>,
181 action: Box<dyn AnyAction>,
182 },
183 Separator,
184}
185
186#[derive(Clone)]
187pub struct App(Rc<RefCell<MutableAppContext>>);
188
189#[derive(Clone)]
190pub struct AsyncAppContext(Rc<RefCell<MutableAppContext>>);
191
192pub struct BackgroundAppContext(*const RefCell<MutableAppContext>);
193
194#[derive(Clone)]
195pub struct TestAppContext {
196 cx: Rc<RefCell<MutableAppContext>>,
197 foreground_platform: Rc<platform::test::ForegroundPlatform>,
198}
199
200impl App {
201 pub fn new(asset_source: impl AssetSource) -> Result<Self> {
202 let platform = platform::current::platform();
203 let foreground_platform = platform::current::foreground_platform();
204 let foreground = Rc::new(executor::Foreground::platform(platform.dispatcher())?);
205 let app = Self(Rc::new(RefCell::new(MutableAppContext::new(
206 foreground,
207 Arc::new(executor::Background::new()),
208 platform.clone(),
209 foreground_platform.clone(),
210 Arc::new(FontCache::new(platform.fonts())),
211 asset_source,
212 ))));
213
214 let cx = app.0.clone();
215 foreground_platform.on_menu_command(Box::new(move |action| {
216 let mut cx = cx.borrow_mut();
217 if let Some(key_window_id) = cx.cx.platform.key_window_id() {
218 if let Some((presenter, _)) = cx.presenters_and_platform_windows.get(&key_window_id)
219 {
220 let presenter = presenter.clone();
221 let path = presenter.borrow().dispatch_path(cx.as_ref());
222 cx.dispatch_action_any(key_window_id, &path, action);
223 } else {
224 cx.dispatch_global_action_any(action);
225 }
226 } else {
227 cx.dispatch_global_action_any(action);
228 }
229 }));
230
231 app.0.borrow_mut().weak_self = Some(Rc::downgrade(&app.0));
232 Ok(app)
233 }
234
235 pub fn on_become_active<F>(self, mut callback: F) -> Self
236 where
237 F: 'static + FnMut(&mut MutableAppContext),
238 {
239 let cx = self.0.clone();
240 self.0
241 .borrow_mut()
242 .foreground_platform
243 .on_become_active(Box::new(move || callback(&mut *cx.borrow_mut())));
244 self
245 }
246
247 pub fn on_resign_active<F>(self, mut callback: F) -> Self
248 where
249 F: 'static + FnMut(&mut MutableAppContext),
250 {
251 let cx = self.0.clone();
252 self.0
253 .borrow_mut()
254 .foreground_platform
255 .on_resign_active(Box::new(move || callback(&mut *cx.borrow_mut())));
256 self
257 }
258
259 pub fn on_event<F>(self, mut callback: F) -> Self
260 where
261 F: 'static + FnMut(Event, &mut MutableAppContext) -> bool,
262 {
263 let cx = self.0.clone();
264 self.0
265 .borrow_mut()
266 .foreground_platform
267 .on_event(Box::new(move |event| {
268 callback(event, &mut *cx.borrow_mut())
269 }));
270 self
271 }
272
273 pub fn on_open_files<F>(self, mut callback: F) -> Self
274 where
275 F: 'static + FnMut(Vec<PathBuf>, &mut MutableAppContext),
276 {
277 let cx = self.0.clone();
278 self.0
279 .borrow_mut()
280 .foreground_platform
281 .on_open_files(Box::new(move |paths| {
282 callback(paths, &mut *cx.borrow_mut())
283 }));
284 self
285 }
286
287 pub fn run<F>(self, on_finish_launching: F)
288 where
289 F: 'static + FnOnce(&mut MutableAppContext),
290 {
291 let platform = self.0.borrow().foreground_platform.clone();
292 platform.run(Box::new(move || {
293 let mut cx = self.0.borrow_mut();
294 on_finish_launching(&mut *cx);
295 }))
296 }
297
298 pub fn font_cache(&self) -> Arc<FontCache> {
299 self.0.borrow().cx.font_cache.clone()
300 }
301
302 fn update<T, F: FnOnce(&mut MutableAppContext) -> T>(&mut self, callback: F) -> T {
303 let mut state = self.0.borrow_mut();
304 state.pending_flushes += 1;
305 let result = callback(&mut *state);
306 state.flush_effects();
307 result
308 }
309}
310
311impl TestAppContext {
312 pub fn new(
313 foreground_platform: Rc<platform::test::ForegroundPlatform>,
314 platform: Arc<dyn Platform>,
315 foreground: Rc<executor::Foreground>,
316 background: Arc<executor::Background>,
317 font_cache: Arc<FontCache>,
318 first_entity_id: usize,
319 ) -> Self {
320 let mut cx = MutableAppContext::new(
321 foreground.clone(),
322 background,
323 platform,
324 foreground_platform.clone(),
325 font_cache,
326 (),
327 );
328 cx.next_entity_id = first_entity_id;
329 let cx = TestAppContext {
330 cx: Rc::new(RefCell::new(cx)),
331 foreground_platform,
332 };
333 cx.cx.borrow_mut().weak_self = Some(Rc::downgrade(&cx.cx));
334 cx
335 }
336
337 pub fn dispatch_action<A: Action>(
338 &self,
339 window_id: usize,
340 responder_chain: Vec<usize>,
341 action: A,
342 ) {
343 self.cx
344 .borrow_mut()
345 .dispatch_action_any(window_id, &responder_chain, &action);
346 }
347
348 pub fn dispatch_global_action<A: Action>(&self, action: A) {
349 self.cx.borrow_mut().dispatch_global_action(action);
350 }
351
352 pub fn dispatch_keystroke(
353 &self,
354 window_id: usize,
355 responder_chain: Vec<usize>,
356 keystroke: &Keystroke,
357 ) -> Result<bool> {
358 let mut state = self.cx.borrow_mut();
359 state.dispatch_keystroke(window_id, responder_chain, keystroke)
360 }
361
362 pub fn add_model<T, F>(&mut self, build_model: F) -> ModelHandle<T>
363 where
364 T: Entity,
365 F: FnOnce(&mut ModelContext<T>) -> T,
366 {
367 let mut state = self.cx.borrow_mut();
368 state.pending_flushes += 1;
369 let handle = state.add_model(build_model);
370 state.flush_effects();
371 handle
372 }
373
374 pub fn add_window<T, F>(&mut self, build_root_view: F) -> (usize, ViewHandle<T>)
375 where
376 T: View,
377 F: FnOnce(&mut ViewContext<T>) -> T,
378 {
379 self.cx
380 .borrow_mut()
381 .add_window(Default::default(), build_root_view)
382 }
383
384 pub fn window_ids(&self) -> Vec<usize> {
385 self.cx.borrow().window_ids().collect()
386 }
387
388 pub fn root_view<T: View>(&self, window_id: usize) -> Option<ViewHandle<T>> {
389 self.cx.borrow().root_view(window_id)
390 }
391
392 pub fn add_view<T, F>(&mut self, window_id: usize, build_view: F) -> ViewHandle<T>
393 where
394 T: View,
395 F: FnOnce(&mut ViewContext<T>) -> T,
396 {
397 let mut state = self.cx.borrow_mut();
398 state.pending_flushes += 1;
399 let handle = state.add_view(window_id, build_view);
400 state.flush_effects();
401 handle
402 }
403
404 pub fn add_option_view<T, F>(
405 &mut self,
406 window_id: usize,
407 build_view: F,
408 ) -> Option<ViewHandle<T>>
409 where
410 T: View,
411 F: FnOnce(&mut ViewContext<T>) -> Option<T>,
412 {
413 let mut state = self.cx.borrow_mut();
414 state.pending_flushes += 1;
415 let handle = state.add_option_view(window_id, build_view);
416 state.flush_effects();
417 handle
418 }
419
420 pub fn read<T, F: FnOnce(&AppContext) -> T>(&self, callback: F) -> T {
421 callback(self.cx.borrow().as_ref())
422 }
423
424 pub fn update<T, F: FnOnce(&mut MutableAppContext) -> T>(&mut self, callback: F) -> T {
425 let mut state = self.cx.borrow_mut();
426 // Don't increment pending flushes in order to effects to be flushed before the callback
427 // completes, which is helpful in tests.
428 let result = callback(&mut *state);
429 // Flush effects after the callback just in case there are any. This can happen in edge
430 // cases such as the closure dropping handles.
431 state.flush_effects();
432 result
433 }
434
435 pub fn to_async(&self) -> AsyncAppContext {
436 AsyncAppContext(self.cx.clone())
437 }
438
439 pub fn font_cache(&self) -> Arc<FontCache> {
440 self.cx.borrow().cx.font_cache.clone()
441 }
442
443 pub fn platform(&self) -> Arc<dyn platform::Platform> {
444 self.cx.borrow().cx.platform.clone()
445 }
446
447 pub fn foreground(&self) -> Rc<executor::Foreground> {
448 self.cx.borrow().foreground().clone()
449 }
450
451 pub fn background(&self) -> Arc<executor::Background> {
452 self.cx.borrow().background().clone()
453 }
454
455 pub fn simulate_new_path_selection(&self, result: impl FnOnce(PathBuf) -> Option<PathBuf>) {
456 self.foreground_platform.simulate_new_path_selection(result);
457 }
458
459 pub fn did_prompt_for_new_path(&self) -> bool {
460 self.foreground_platform.as_ref().did_prompt_for_new_path()
461 }
462
463 pub fn simulate_prompt_answer(&self, window_id: usize, answer: usize) {
464 let mut state = self.cx.borrow_mut();
465 let (_, window) = state
466 .presenters_and_platform_windows
467 .get_mut(&window_id)
468 .unwrap();
469 let test_window = window
470 .as_any_mut()
471 .downcast_mut::<platform::test::Window>()
472 .unwrap();
473 let callback = test_window
474 .last_prompt
475 .take()
476 .expect("prompt was not called");
477 (callback)(answer);
478 }
479}
480
481impl AsyncAppContext {
482 pub fn spawn<F, Fut, T>(&self, f: F) -> Task<T>
483 where
484 F: FnOnce(AsyncAppContext) -> Fut,
485 Fut: 'static + Future<Output = T>,
486 T: 'static,
487 {
488 self.0.borrow().foreground.spawn(f(self.clone()))
489 }
490
491 pub fn read<T, F: FnOnce(&AppContext) -> T>(&mut self, callback: F) -> T {
492 callback(self.0.borrow().as_ref())
493 }
494
495 pub fn update<T, F: FnOnce(&mut MutableAppContext) -> T>(&mut self, callback: F) -> T {
496 let mut state = self.0.borrow_mut();
497 state.pending_flushes += 1;
498 let result = callback(&mut *state);
499 state.flush_effects();
500 result
501 }
502
503 pub fn add_model<T, F>(&mut self, build_model: F) -> ModelHandle<T>
504 where
505 T: Entity,
506 F: FnOnce(&mut ModelContext<T>) -> T,
507 {
508 self.update(|cx| cx.add_model(build_model))
509 }
510
511 pub fn platform(&self) -> Arc<dyn Platform> {
512 self.0.borrow().platform()
513 }
514
515 pub fn foreground(&self) -> Rc<executor::Foreground> {
516 self.0.borrow().foreground.clone()
517 }
518
519 pub fn background(&self) -> Arc<executor::Background> {
520 self.0.borrow().cx.background.clone()
521 }
522}
523
524impl UpdateModel for AsyncAppContext {
525 fn update_model<T, F, S>(&mut self, handle: &ModelHandle<T>, update: F) -> S
526 where
527 T: Entity,
528 F: FnOnce(&mut T, &mut ModelContext<T>) -> S,
529 {
530 let mut state = self.0.borrow_mut();
531 state.pending_flushes += 1;
532 let result = state.update_model(handle, update);
533 state.flush_effects();
534 result
535 }
536}
537
538impl UpgradeModelHandle for AsyncAppContext {
539 fn upgrade_model_handle<T: Entity>(
540 &self,
541 handle: WeakModelHandle<T>,
542 ) -> Option<ModelHandle<T>> {
543 self.0.borrow_mut().upgrade_model_handle(handle)
544 }
545}
546
547impl ReadModelWith for AsyncAppContext {
548 fn read_model_with<E: Entity, F: FnOnce(&E, &AppContext) -> T, T>(
549 &self,
550 handle: &ModelHandle<E>,
551 read: F,
552 ) -> T {
553 let cx = self.0.borrow();
554 let cx = cx.as_ref();
555 read(handle.read(cx), cx)
556 }
557}
558
559impl UpdateView for AsyncAppContext {
560 fn update_view<T, F, S>(&mut self, handle: &ViewHandle<T>, update: F) -> S
561 where
562 T: View,
563 F: FnOnce(&mut T, &mut ViewContext<T>) -> S,
564 {
565 let mut state = self.0.borrow_mut();
566 state.pending_flushes += 1;
567 let result = state.update_view(handle, update);
568 state.flush_effects();
569 result
570 }
571}
572
573impl ReadViewWith for AsyncAppContext {
574 fn read_view_with<V, F, T>(&self, handle: &ViewHandle<V>, read: F) -> T
575 where
576 V: View,
577 F: FnOnce(&V, &AppContext) -> T,
578 {
579 let cx = self.0.borrow();
580 let cx = cx.as_ref();
581 read(handle.read(cx), cx)
582 }
583}
584
585impl UpdateModel for TestAppContext {
586 fn update_model<T, F, S>(&mut self, handle: &ModelHandle<T>, update: F) -> S
587 where
588 T: Entity,
589 F: FnOnce(&mut T, &mut ModelContext<T>) -> S,
590 {
591 let mut state = self.cx.borrow_mut();
592 state.pending_flushes += 1;
593 let result = state.update_model(handle, update);
594 state.flush_effects();
595 result
596 }
597}
598
599impl ReadModelWith for TestAppContext {
600 fn read_model_with<E: Entity, F: FnOnce(&E, &AppContext) -> T, T>(
601 &self,
602 handle: &ModelHandle<E>,
603 read: F,
604 ) -> T {
605 let cx = self.cx.borrow();
606 let cx = cx.as_ref();
607 read(handle.read(cx), cx)
608 }
609}
610
611impl UpdateView for TestAppContext {
612 fn update_view<T, F, S>(&mut self, handle: &ViewHandle<T>, update: F) -> S
613 where
614 T: View,
615 F: FnOnce(&mut T, &mut ViewContext<T>) -> S,
616 {
617 let mut state = self.cx.borrow_mut();
618 state.pending_flushes += 1;
619 let result = state.update_view(handle, update);
620 state.flush_effects();
621 result
622 }
623}
624
625impl ReadViewWith for TestAppContext {
626 fn read_view_with<V, F, T>(&self, handle: &ViewHandle<V>, read: F) -> T
627 where
628 V: View,
629 F: FnOnce(&V, &AppContext) -> T,
630 {
631 let cx = self.cx.borrow();
632 let cx = cx.as_ref();
633 read(handle.read(cx), cx)
634 }
635}
636
637type ActionCallback =
638 dyn FnMut(&mut dyn AnyView, &dyn AnyAction, &mut MutableAppContext, usize, usize) -> bool;
639type GlobalActionCallback = dyn FnMut(&dyn AnyAction, &mut MutableAppContext);
640
641type SubscriptionCallback = Box<dyn FnMut(&dyn Any, &mut MutableAppContext) -> bool>;
642type ObservationCallback = Box<dyn FnMut(&mut MutableAppContext) -> bool>;
643
644pub struct MutableAppContext {
645 weak_self: Option<rc::Weak<RefCell<Self>>>,
646 foreground_platform: Rc<dyn platform::ForegroundPlatform>,
647 assets: Arc<AssetCache>,
648 cx: AppContext,
649 actions: HashMap<TypeId, HashMap<TypeId, Vec<Box<ActionCallback>>>>,
650 global_actions: HashMap<TypeId, Vec<Box<GlobalActionCallback>>>,
651 keystroke_matcher: keymap::Matcher,
652 next_entity_id: usize,
653 next_window_id: usize,
654 next_subscription_id: usize,
655 subscriptions: Arc<Mutex<HashMap<usize, HashMap<usize, SubscriptionCallback>>>>,
656 observations: Arc<Mutex<HashMap<usize, HashMap<usize, ObservationCallback>>>>,
657 presenters_and_platform_windows:
658 HashMap<usize, (Rc<RefCell<Presenter>>, Box<dyn platform::Window>)>,
659 debug_elements_callbacks: HashMap<usize, Box<dyn Fn(&AppContext) -> crate::json::Value>>,
660 foreground: Rc<executor::Foreground>,
661 pending_effects: VecDeque<Effect>,
662 pending_flushes: usize,
663 flushing_effects: bool,
664}
665
666impl MutableAppContext {
667 fn new(
668 foreground: Rc<executor::Foreground>,
669 background: Arc<executor::Background>,
670 platform: Arc<dyn platform::Platform>,
671 foreground_platform: Rc<dyn platform::ForegroundPlatform>,
672 font_cache: Arc<FontCache>,
673 asset_source: impl AssetSource,
674 ) -> Self {
675 Self {
676 weak_self: None,
677 foreground_platform,
678 assets: Arc::new(AssetCache::new(asset_source)),
679 cx: AppContext {
680 models: Default::default(),
681 views: Default::default(),
682 windows: Default::default(),
683 values: Default::default(),
684 ref_counts: Arc::new(Mutex::new(RefCounts::default())),
685 background,
686 font_cache,
687 platform,
688 },
689 actions: HashMap::new(),
690 global_actions: HashMap::new(),
691 keystroke_matcher: keymap::Matcher::default(),
692 next_entity_id: 0,
693 next_window_id: 0,
694 next_subscription_id: 0,
695 subscriptions: Default::default(),
696 observations: Default::default(),
697 presenters_and_platform_windows: HashMap::new(),
698 debug_elements_callbacks: HashMap::new(),
699 foreground,
700 pending_effects: VecDeque::new(),
701 pending_flushes: 0,
702 flushing_effects: false,
703 }
704 }
705
706 pub fn upgrade(&self) -> App {
707 App(self.weak_self.as_ref().unwrap().upgrade().unwrap())
708 }
709
710 pub fn platform(&self) -> Arc<dyn platform::Platform> {
711 self.cx.platform.clone()
712 }
713
714 pub fn font_cache(&self) -> &Arc<FontCache> {
715 &self.cx.font_cache
716 }
717
718 pub fn foreground(&self) -> &Rc<executor::Foreground> {
719 &self.foreground
720 }
721
722 pub fn background(&self) -> &Arc<executor::Background> {
723 &self.cx.background
724 }
725
726 pub fn on_debug_elements<F>(&mut self, window_id: usize, callback: F)
727 where
728 F: 'static + Fn(&AppContext) -> crate::json::Value,
729 {
730 self.debug_elements_callbacks
731 .insert(window_id, Box::new(callback));
732 }
733
734 pub fn debug_elements(&self, window_id: usize) -> Option<crate::json::Value> {
735 self.debug_elements_callbacks
736 .get(&window_id)
737 .map(|debug_elements| debug_elements(&self.cx))
738 }
739
740 pub fn add_action<A, V, F>(&mut self, mut handler: F)
741 where
742 A: Action,
743 V: View,
744 F: 'static + FnMut(&mut V, &A, &mut ViewContext<V>),
745 {
746 let handler = Box::new(
747 move |view: &mut dyn AnyView,
748 action: &dyn AnyAction,
749 cx: &mut MutableAppContext,
750 window_id: usize,
751 view_id: usize| {
752 let action = action.as_any().downcast_ref().unwrap();
753 let mut cx = ViewContext::new(cx, window_id, view_id);
754 handler(
755 view.as_any_mut()
756 .downcast_mut()
757 .expect("downcast is type safe"),
758 action,
759 &mut cx,
760 );
761 cx.halt_action_dispatch
762 },
763 );
764
765 self.actions
766 .entry(TypeId::of::<V>())
767 .or_default()
768 .entry(TypeId::of::<A>())
769 .or_default()
770 .push(handler);
771 }
772
773 pub fn add_global_action<A, F>(&mut self, mut handler: F)
774 where
775 A: Action,
776 F: 'static + FnMut(&A, &mut MutableAppContext),
777 {
778 let handler = Box::new(move |action: &dyn AnyAction, cx: &mut MutableAppContext| {
779 let action = action.as_any().downcast_ref().unwrap();
780 handler(action, cx);
781 });
782
783 self.global_actions
784 .entry(TypeId::of::<A>())
785 .or_default()
786 .push(handler);
787 }
788
789 pub fn window_ids(&self) -> impl Iterator<Item = usize> + '_ {
790 self.cx.windows.keys().cloned()
791 }
792
793 pub fn root_view<T: View>(&self, window_id: usize) -> Option<ViewHandle<T>> {
794 self.cx
795 .windows
796 .get(&window_id)
797 .and_then(|window| window.root_view.clone().downcast::<T>())
798 }
799
800 pub fn root_view_id(&self, window_id: usize) -> Option<usize> {
801 self.cx.root_view_id(window_id)
802 }
803
804 pub fn focused_view_id(&self, window_id: usize) -> Option<usize> {
805 self.cx.focused_view_id(window_id)
806 }
807
808 pub fn render_views(
809 &self,
810 window_id: usize,
811 titlebar_height: f32,
812 ) -> HashMap<usize, ElementBox> {
813 self.cx.render_views(window_id, titlebar_height)
814 }
815
816 pub fn update<T, F: FnOnce() -> T>(&mut self, callback: F) -> T {
817 self.pending_flushes += 1;
818 let result = callback();
819 self.flush_effects();
820 result
821 }
822
823 pub fn set_menus(&mut self, menus: Vec<Menu>) {
824 self.foreground_platform.set_menus(menus);
825 }
826
827 fn prompt<F>(
828 &self,
829 window_id: usize,
830 level: PromptLevel,
831 msg: &str,
832 answers: &[&str],
833 done_fn: F,
834 ) where
835 F: 'static + FnOnce(usize, &mut MutableAppContext),
836 {
837 let app = self.weak_self.as_ref().unwrap().upgrade().unwrap();
838 let foreground = self.foreground.clone();
839 let (_, window) = &self.presenters_and_platform_windows[&window_id];
840 window.prompt(
841 level,
842 msg,
843 answers,
844 Box::new(move |answer| {
845 foreground
846 .spawn(async move { (done_fn)(answer, &mut *app.borrow_mut()) })
847 .detach();
848 }),
849 );
850 }
851
852 pub fn prompt_for_paths<F>(&self, options: PathPromptOptions, done_fn: F)
853 where
854 F: 'static + FnOnce(Option<Vec<PathBuf>>, &mut MutableAppContext),
855 {
856 let app = self.weak_self.as_ref().unwrap().upgrade().unwrap();
857 let foreground = self.foreground.clone();
858 self.foreground_platform.prompt_for_paths(
859 options,
860 Box::new(move |paths| {
861 foreground
862 .spawn(async move { (done_fn)(paths, &mut *app.borrow_mut()) })
863 .detach();
864 }),
865 );
866 }
867
868 pub fn prompt_for_new_path<F>(&self, directory: &Path, done_fn: F)
869 where
870 F: 'static + FnOnce(Option<PathBuf>, &mut MutableAppContext),
871 {
872 let app = self.weak_self.as_ref().unwrap().upgrade().unwrap();
873 let foreground = self.foreground.clone();
874 self.foreground_platform.prompt_for_new_path(
875 directory,
876 Box::new(move |path| {
877 foreground
878 .spawn(async move { (done_fn)(path, &mut *app.borrow_mut()) })
879 .detach();
880 }),
881 );
882 }
883
884 pub fn subscribe<E, H, F>(&mut self, handle: &H, mut callback: F) -> Subscription
885 where
886 E: Entity,
887 E::Event: 'static,
888 H: Handle<E>,
889 F: 'static + FnMut(H, &E::Event, &mut Self),
890 {
891 self.subscribe_internal(handle, move |handle, event, cx| {
892 callback(handle, event, cx);
893 true
894 })
895 }
896
897 fn observe<E, H, F>(&mut self, handle: &H, mut callback: F) -> Subscription
898 where
899 E: Entity,
900 E::Event: 'static,
901 H: Handle<E>,
902 F: 'static + FnMut(H, &mut Self),
903 {
904 self.observe_internal(handle, move |handle, cx| {
905 callback(handle, cx);
906 true
907 })
908 }
909
910 pub fn subscribe_internal<E, H, F>(&mut self, handle: &H, mut callback: F) -> Subscription
911 where
912 E: Entity,
913 E::Event: 'static,
914 H: Handle<E>,
915 F: 'static + FnMut(H, &E::Event, &mut Self) -> bool,
916 {
917 let id = post_inc(&mut self.next_subscription_id);
918 let emitter = handle.downgrade();
919 self.subscriptions
920 .lock()
921 .entry(handle.id())
922 .or_default()
923 .insert(
924 id,
925 Box::new(move |payload, cx| {
926 if let Some(emitter) = H::upgrade_from(&emitter, cx.as_ref()) {
927 let payload = payload.downcast_ref().expect("downcast is type safe");
928 callback(emitter, payload, cx)
929 } else {
930 false
931 }
932 }),
933 );
934 Subscription::Subscription {
935 id,
936 entity_id: handle.id(),
937 subscriptions: Some(Arc::downgrade(&self.subscriptions)),
938 }
939 }
940
941 fn observe_internal<E, H, F>(&mut self, handle: &H, mut callback: F) -> Subscription
942 where
943 E: Entity,
944 E::Event: 'static,
945 H: Handle<E>,
946 F: 'static + FnMut(H, &mut Self) -> bool,
947 {
948 let id = post_inc(&mut self.next_subscription_id);
949 let observed = handle.downgrade();
950 self.observations
951 .lock()
952 .entry(handle.id())
953 .or_default()
954 .insert(
955 id,
956 Box::new(move |cx| {
957 if let Some(observed) = H::upgrade_from(&observed, cx) {
958 callback(observed, cx)
959 } else {
960 false
961 }
962 }),
963 );
964 Subscription::Observation {
965 id,
966 entity_id: handle.id(),
967 observations: Some(Arc::downgrade(&self.observations)),
968 }
969 }
970
971 pub(crate) fn notify_view(&mut self, window_id: usize, view_id: usize) {
972 self.pending_effects
973 .push_back(Effect::ViewNotification { window_id, view_id });
974 }
975
976 pub(crate) fn notify_all_views(&mut self) {
977 let notifications = self
978 .views
979 .keys()
980 .copied()
981 .map(|(window_id, view_id)| Effect::ViewNotification { window_id, view_id })
982 .collect::<Vec<_>>();
983 self.pending_effects.extend(notifications);
984 }
985
986 pub fn dispatch_action<A: Action>(
987 &mut self,
988 window_id: usize,
989 responder_chain: Vec<usize>,
990 action: &A,
991 ) {
992 self.dispatch_action_any(window_id, &responder_chain, action);
993 }
994
995 pub(crate) fn dispatch_action_any(
996 &mut self,
997 window_id: usize,
998 path: &[usize],
999 action: &dyn AnyAction,
1000 ) -> bool {
1001 self.pending_flushes += 1;
1002 let mut halted_dispatch = false;
1003
1004 for view_id in path.iter().rev() {
1005 if let Some(mut view) = self.cx.views.remove(&(window_id, *view_id)) {
1006 let type_id = view.as_any().type_id();
1007
1008 if let Some((name, mut handlers)) = self
1009 .actions
1010 .get_mut(&type_id)
1011 .and_then(|h| h.remove_entry(&action.id()))
1012 {
1013 for handler in handlers.iter_mut().rev() {
1014 let halt_dispatch =
1015 handler(view.as_mut(), action, self, window_id, *view_id);
1016 if halt_dispatch {
1017 halted_dispatch = true;
1018 break;
1019 }
1020 }
1021 self.actions
1022 .get_mut(&type_id)
1023 .unwrap()
1024 .insert(name, handlers);
1025 }
1026
1027 self.cx.views.insert((window_id, *view_id), view);
1028
1029 if halted_dispatch {
1030 break;
1031 }
1032 }
1033 }
1034
1035 if !halted_dispatch {
1036 self.dispatch_global_action_any(action);
1037 }
1038
1039 self.flush_effects();
1040 halted_dispatch
1041 }
1042
1043 pub fn dispatch_global_action<A: Action>(&mut self, action: A) {
1044 self.dispatch_global_action_any(&action);
1045 }
1046
1047 fn dispatch_global_action_any(&mut self, action: &dyn AnyAction) {
1048 if let Some((name, mut handlers)) = self.global_actions.remove_entry(&action.id()) {
1049 self.pending_flushes += 1;
1050 for handler in handlers.iter_mut().rev() {
1051 handler(action, self);
1052 }
1053 self.global_actions.insert(name, handlers);
1054 self.flush_effects();
1055 }
1056 }
1057
1058 pub fn add_bindings<T: IntoIterator<Item = keymap::Binding>>(&mut self, bindings: T) {
1059 self.keystroke_matcher.add_bindings(bindings);
1060 }
1061
1062 pub fn dispatch_keystroke(
1063 &mut self,
1064 window_id: usize,
1065 responder_chain: Vec<usize>,
1066 keystroke: &Keystroke,
1067 ) -> Result<bool> {
1068 let mut context_chain = Vec::new();
1069 let mut context = keymap::Context::default();
1070 for view_id in &responder_chain {
1071 if let Some(view) = self.cx.views.get(&(window_id, *view_id)) {
1072 context.extend(view.keymap_context(self.as_ref()));
1073 context_chain.push(context.clone());
1074 } else {
1075 return Err(anyhow!(
1076 "View {} in responder chain does not exist",
1077 view_id
1078 ));
1079 }
1080 }
1081
1082 let mut pending = false;
1083 for (i, cx) in context_chain.iter().enumerate().rev() {
1084 match self
1085 .keystroke_matcher
1086 .push_keystroke(keystroke.clone(), responder_chain[i], cx)
1087 {
1088 MatchResult::None => {}
1089 MatchResult::Pending => pending = true,
1090 MatchResult::Action(action) => {
1091 if self.dispatch_action_any(window_id, &responder_chain[0..=i], action.as_ref())
1092 {
1093 return Ok(true);
1094 }
1095 }
1096 }
1097 }
1098
1099 Ok(pending)
1100 }
1101
1102 pub fn add_model<T, F>(&mut self, build_model: F) -> ModelHandle<T>
1103 where
1104 T: Entity,
1105 F: FnOnce(&mut ModelContext<T>) -> T,
1106 {
1107 self.pending_flushes += 1;
1108 let model_id = post_inc(&mut self.next_entity_id);
1109 let handle = ModelHandle::new(model_id, &self.cx.ref_counts);
1110 let mut cx = ModelContext::new(self, model_id);
1111 let model = build_model(&mut cx);
1112 self.cx.models.insert(model_id, Box::new(model));
1113 self.flush_effects();
1114 handle
1115 }
1116
1117 pub fn add_window<T, F>(
1118 &mut self,
1119 window_options: WindowOptions,
1120 build_root_view: F,
1121 ) -> (usize, ViewHandle<T>)
1122 where
1123 T: View,
1124 F: FnOnce(&mut ViewContext<T>) -> T,
1125 {
1126 self.pending_flushes += 1;
1127 let window_id = post_inc(&mut self.next_window_id);
1128 let root_view = self.add_view(window_id, build_root_view);
1129
1130 self.cx.windows.insert(
1131 window_id,
1132 Window {
1133 root_view: root_view.clone().into(),
1134 focused_view_id: root_view.id(),
1135 invalidation: None,
1136 },
1137 );
1138 self.open_platform_window(window_id, window_options);
1139 root_view.update(self, |view, cx| {
1140 view.on_focus(cx);
1141 cx.notify();
1142 });
1143 self.flush_effects();
1144
1145 (window_id, root_view)
1146 }
1147
1148 pub fn remove_window(&mut self, window_id: usize) {
1149 self.cx.windows.remove(&window_id);
1150 self.presenters_and_platform_windows.remove(&window_id);
1151 self.remove_dropped_entities();
1152 }
1153
1154 fn open_platform_window(&mut self, window_id: usize, window_options: WindowOptions) {
1155 let mut window =
1156 self.cx
1157 .platform
1158 .open_window(window_id, window_options, self.foreground.clone());
1159 let presenter = Rc::new(RefCell::new(
1160 self.build_presenter(window_id, window.titlebar_height()),
1161 ));
1162
1163 {
1164 let mut app = self.upgrade();
1165 let presenter = presenter.clone();
1166 window.on_event(Box::new(move |event| {
1167 app.update(|cx| {
1168 if let Event::KeyDown { keystroke, .. } = &event {
1169 if cx
1170 .dispatch_keystroke(
1171 window_id,
1172 presenter.borrow().dispatch_path(cx.as_ref()),
1173 keystroke,
1174 )
1175 .unwrap()
1176 {
1177 return;
1178 }
1179 }
1180
1181 presenter.borrow_mut().dispatch_event(event, cx);
1182 })
1183 }));
1184 }
1185
1186 {
1187 let mut app = self.upgrade();
1188 let presenter = presenter.clone();
1189 window.on_resize(Box::new(move |window| {
1190 app.update(|cx| {
1191 let scene = presenter.borrow_mut().build_scene(
1192 window.size(),
1193 window.scale_factor(),
1194 cx,
1195 );
1196 window.present_scene(scene);
1197 })
1198 }));
1199 }
1200
1201 {
1202 let mut app = self.upgrade();
1203 window.on_close(Box::new(move || {
1204 app.update(|cx| cx.remove_window(window_id));
1205 }));
1206 }
1207
1208 self.presenters_and_platform_windows
1209 .insert(window_id, (presenter.clone(), window));
1210
1211 self.on_debug_elements(window_id, move |cx| {
1212 presenter.borrow().debug_elements(cx).unwrap()
1213 });
1214 }
1215
1216 pub fn build_presenter(&self, window_id: usize, titlebar_height: f32) -> Presenter {
1217 Presenter::new(
1218 window_id,
1219 titlebar_height,
1220 self.cx.font_cache.clone(),
1221 TextLayoutCache::new(self.cx.platform.fonts()),
1222 self.assets.clone(),
1223 self,
1224 )
1225 }
1226
1227 pub fn add_view<T, F>(&mut self, window_id: usize, build_view: F) -> ViewHandle<T>
1228 where
1229 T: View,
1230 F: FnOnce(&mut ViewContext<T>) -> T,
1231 {
1232 self.add_option_view(window_id, |cx| Some(build_view(cx)))
1233 .unwrap()
1234 }
1235
1236 pub fn add_option_view<T, F>(
1237 &mut self,
1238 window_id: usize,
1239 build_view: F,
1240 ) -> Option<ViewHandle<T>>
1241 where
1242 T: View,
1243 F: FnOnce(&mut ViewContext<T>) -> Option<T>,
1244 {
1245 let view_id = post_inc(&mut self.next_entity_id);
1246 self.pending_flushes += 1;
1247 let handle = ViewHandle::new(window_id, view_id, &self.cx.ref_counts);
1248 let mut cx = ViewContext::new(self, window_id, view_id);
1249 let handle = if let Some(view) = build_view(&mut cx) {
1250 self.cx.views.insert((window_id, view_id), Box::new(view));
1251 if let Some(window) = self.cx.windows.get_mut(&window_id) {
1252 window
1253 .invalidation
1254 .get_or_insert_with(Default::default)
1255 .updated
1256 .insert(view_id);
1257 }
1258 Some(handle)
1259 } else {
1260 None
1261 };
1262 self.flush_effects();
1263 handle
1264 }
1265
1266 fn remove_dropped_entities(&mut self) {
1267 loop {
1268 let (dropped_models, dropped_views, dropped_values) =
1269 self.cx.ref_counts.lock().take_dropped();
1270 if dropped_models.is_empty() && dropped_views.is_empty() && dropped_values.is_empty() {
1271 break;
1272 }
1273
1274 for model_id in dropped_models {
1275 self.subscriptions.lock().remove(&model_id);
1276 self.observations.lock().remove(&model_id);
1277 let mut model = self.cx.models.remove(&model_id).unwrap();
1278 model.release(self);
1279 }
1280
1281 for (window_id, view_id) in dropped_views {
1282 self.subscriptions.lock().remove(&view_id);
1283 self.observations.lock().remove(&view_id);
1284 let mut view = self.cx.views.remove(&(window_id, view_id)).unwrap();
1285 view.release(self);
1286 let change_focus_to = self.cx.windows.get_mut(&window_id).and_then(|window| {
1287 window
1288 .invalidation
1289 .get_or_insert_with(Default::default)
1290 .removed
1291 .push(view_id);
1292 if window.focused_view_id == view_id {
1293 Some(window.root_view.id())
1294 } else {
1295 None
1296 }
1297 });
1298
1299 if let Some(view_id) = change_focus_to {
1300 self.focus(window_id, view_id);
1301 }
1302 }
1303
1304 let mut values = self.cx.values.write();
1305 for key in dropped_values {
1306 values.remove(&key);
1307 }
1308 }
1309 }
1310
1311 fn flush_effects(&mut self) {
1312 self.pending_flushes = self.pending_flushes.saturating_sub(1);
1313
1314 if !self.flushing_effects && self.pending_flushes == 0 {
1315 self.flushing_effects = true;
1316
1317 loop {
1318 if let Some(effect) = self.pending_effects.pop_front() {
1319 match effect {
1320 Effect::Event { entity_id, payload } => self.emit_event(entity_id, payload),
1321 Effect::ModelNotification { model_id } => {
1322 self.notify_model_observers(model_id)
1323 }
1324 Effect::ViewNotification { window_id, view_id } => {
1325 self.notify_view_observers(window_id, view_id)
1326 }
1327 Effect::Focus { window_id, view_id } => {
1328 self.focus(window_id, view_id);
1329 }
1330 }
1331 self.remove_dropped_entities();
1332 } else {
1333 self.remove_dropped_entities();
1334 self.update_windows();
1335
1336 if self.pending_effects.is_empty() {
1337 self.flushing_effects = false;
1338 break;
1339 }
1340 }
1341 }
1342 }
1343 }
1344
1345 fn update_windows(&mut self) {
1346 let mut invalidations = HashMap::new();
1347 for (window_id, window) in &mut self.cx.windows {
1348 if let Some(invalidation) = window.invalidation.take() {
1349 invalidations.insert(*window_id, invalidation);
1350 }
1351 }
1352
1353 for (window_id, invalidation) in invalidations {
1354 if let Some((presenter, mut window)) =
1355 self.presenters_and_platform_windows.remove(&window_id)
1356 {
1357 {
1358 let mut presenter = presenter.borrow_mut();
1359 presenter.invalidate(invalidation, self.as_ref());
1360 let scene = presenter.build_scene(window.size(), window.scale_factor(), self);
1361 window.present_scene(scene);
1362 }
1363 self.presenters_and_platform_windows
1364 .insert(window_id, (presenter, window));
1365 }
1366 }
1367 }
1368
1369 fn emit_event(&mut self, entity_id: usize, payload: Box<dyn Any>) {
1370 let callbacks = self.subscriptions.lock().remove(&entity_id);
1371 if let Some(callbacks) = callbacks {
1372 for (id, mut callback) in callbacks {
1373 let alive = callback(payload.as_ref(), self);
1374 if alive {
1375 self.subscriptions
1376 .lock()
1377 .entry(entity_id)
1378 .or_default()
1379 .insert(id, callback);
1380 }
1381 }
1382 }
1383 }
1384
1385 fn notify_model_observers(&mut self, observed_id: usize) {
1386 let callbacks = self.observations.lock().remove(&observed_id);
1387 if let Some(callbacks) = callbacks {
1388 if self.cx.models.contains_key(&observed_id) {
1389 for (id, mut callback) in callbacks {
1390 let alive = callback(self);
1391 if alive {
1392 self.observations
1393 .lock()
1394 .entry(observed_id)
1395 .or_default()
1396 .insert(id, callback);
1397 }
1398 }
1399 }
1400 }
1401 }
1402
1403 fn notify_view_observers(&mut self, observed_window_id: usize, observed_view_id: usize) {
1404 if let Some(window) = self.cx.windows.get_mut(&observed_window_id) {
1405 window
1406 .invalidation
1407 .get_or_insert_with(Default::default)
1408 .updated
1409 .insert(observed_view_id);
1410 }
1411
1412 let callbacks = self.observations.lock().remove(&observed_view_id);
1413 if let Some(callbacks) = callbacks {
1414 if self
1415 .cx
1416 .views
1417 .contains_key(&(observed_window_id, observed_view_id))
1418 {
1419 for (id, mut callback) in callbacks {
1420 let alive = callback(self);
1421 if alive {
1422 self.observations
1423 .lock()
1424 .entry(observed_view_id)
1425 .or_default()
1426 .insert(id, callback);
1427 }
1428 }
1429 }
1430 }
1431 }
1432
1433 fn focus(&mut self, window_id: usize, focused_id: usize) {
1434 if self
1435 .cx
1436 .windows
1437 .get(&window_id)
1438 .map(|w| w.focused_view_id)
1439 .map_or(false, |cur_focused| cur_focused == focused_id)
1440 {
1441 return;
1442 }
1443
1444 self.pending_flushes += 1;
1445
1446 let blurred_id = self.cx.windows.get_mut(&window_id).map(|window| {
1447 let blurred_id = window.focused_view_id;
1448 window.focused_view_id = focused_id;
1449 blurred_id
1450 });
1451
1452 if let Some(blurred_id) = blurred_id {
1453 if let Some(mut blurred_view) = self.cx.views.remove(&(window_id, blurred_id)) {
1454 blurred_view.on_blur(self, window_id, blurred_id);
1455 self.cx.views.insert((window_id, blurred_id), blurred_view);
1456 }
1457 }
1458
1459 if let Some(mut focused_view) = self.cx.views.remove(&(window_id, focused_id)) {
1460 focused_view.on_focus(self, window_id, focused_id);
1461 self.cx.views.insert((window_id, focused_id), focused_view);
1462 }
1463
1464 self.flush_effects();
1465 }
1466
1467 pub fn spawn<F, Fut, T>(&self, f: F) -> Task<T>
1468 where
1469 F: FnOnce(AsyncAppContext) -> Fut,
1470 Fut: 'static + Future<Output = T>,
1471 T: 'static,
1472 {
1473 let cx = self.to_async();
1474 self.foreground.spawn(f(cx))
1475 }
1476
1477 pub fn to_async(&self) -> AsyncAppContext {
1478 AsyncAppContext(self.weak_self.as_ref().unwrap().upgrade().unwrap())
1479 }
1480
1481 pub fn write_to_clipboard(&self, item: ClipboardItem) {
1482 self.cx.platform.write_to_clipboard(item);
1483 }
1484
1485 pub fn read_from_clipboard(&self) -> Option<ClipboardItem> {
1486 self.cx.platform.read_from_clipboard()
1487 }
1488}
1489
1490impl ReadModel for MutableAppContext {
1491 fn read_model<T: Entity>(&self, handle: &ModelHandle<T>) -> &T {
1492 if let Some(model) = self.cx.models.get(&handle.model_id) {
1493 model
1494 .as_any()
1495 .downcast_ref()
1496 .expect("downcast is type safe")
1497 } else {
1498 panic!("circular model reference");
1499 }
1500 }
1501}
1502
1503impl UpdateModel for MutableAppContext {
1504 fn update_model<T, F, S>(&mut self, handle: &ModelHandle<T>, update: F) -> S
1505 where
1506 T: Entity,
1507 F: FnOnce(&mut T, &mut ModelContext<T>) -> S,
1508 {
1509 if let Some(mut model) = self.cx.models.remove(&handle.model_id) {
1510 self.pending_flushes += 1;
1511 let mut cx = ModelContext::new(self, handle.model_id);
1512 let result = update(
1513 model
1514 .as_any_mut()
1515 .downcast_mut()
1516 .expect("downcast is type safe"),
1517 &mut cx,
1518 );
1519 self.cx.models.insert(handle.model_id, model);
1520 self.flush_effects();
1521 result
1522 } else {
1523 panic!("circular model update");
1524 }
1525 }
1526}
1527
1528impl UpgradeModelHandle for MutableAppContext {
1529 fn upgrade_model_handle<T: Entity>(
1530 &self,
1531 handle: WeakModelHandle<T>,
1532 ) -> Option<ModelHandle<T>> {
1533 self.cx.upgrade_model_handle(handle)
1534 }
1535}
1536
1537impl ReadView for MutableAppContext {
1538 fn read_view<T: View>(&self, handle: &ViewHandle<T>) -> &T {
1539 if let Some(view) = self.cx.views.get(&(handle.window_id, handle.view_id)) {
1540 view.as_any().downcast_ref().expect("downcast is type safe")
1541 } else {
1542 panic!("circular view reference");
1543 }
1544 }
1545}
1546
1547impl UpdateView for MutableAppContext {
1548 fn update_view<T, F, S>(&mut self, handle: &ViewHandle<T>, update: F) -> S
1549 where
1550 T: View,
1551 F: FnOnce(&mut T, &mut ViewContext<T>) -> S,
1552 {
1553 self.pending_flushes += 1;
1554 let mut view = self
1555 .cx
1556 .views
1557 .remove(&(handle.window_id, handle.view_id))
1558 .expect("circular view update");
1559
1560 let mut cx = ViewContext::new(self, handle.window_id, handle.view_id);
1561 let result = update(
1562 view.as_any_mut()
1563 .downcast_mut()
1564 .expect("downcast is type safe"),
1565 &mut cx,
1566 );
1567 self.cx
1568 .views
1569 .insert((handle.window_id, handle.view_id), view);
1570 self.flush_effects();
1571 result
1572 }
1573}
1574
1575impl AsRef<AppContext> for MutableAppContext {
1576 fn as_ref(&self) -> &AppContext {
1577 &self.cx
1578 }
1579}
1580
1581impl Deref for MutableAppContext {
1582 type Target = AppContext;
1583
1584 fn deref(&self) -> &Self::Target {
1585 &self.cx
1586 }
1587}
1588
1589pub struct AppContext {
1590 models: HashMap<usize, Box<dyn AnyModel>>,
1591 views: HashMap<(usize, usize), Box<dyn AnyView>>,
1592 windows: HashMap<usize, Window>,
1593 values: RwLock<HashMap<(TypeId, usize), Box<dyn Any>>>,
1594 background: Arc<executor::Background>,
1595 ref_counts: Arc<Mutex<RefCounts>>,
1596 font_cache: Arc<FontCache>,
1597 platform: Arc<dyn Platform>,
1598}
1599
1600impl AppContext {
1601 pub fn root_view_id(&self, window_id: usize) -> Option<usize> {
1602 self.windows
1603 .get(&window_id)
1604 .map(|window| window.root_view.id())
1605 }
1606
1607 pub fn focused_view_id(&self, window_id: usize) -> Option<usize> {
1608 self.windows
1609 .get(&window_id)
1610 .map(|window| window.focused_view_id)
1611 }
1612
1613 pub fn render_view(
1614 &self,
1615 window_id: usize,
1616 view_id: usize,
1617 titlebar_height: f32,
1618 ) -> Result<ElementBox> {
1619 self.views
1620 .get(&(window_id, view_id))
1621 .map(|v| v.render(window_id, view_id, titlebar_height, self))
1622 .ok_or(anyhow!("view not found"))
1623 }
1624
1625 pub fn render_views(
1626 &self,
1627 window_id: usize,
1628 titlebar_height: f32,
1629 ) -> HashMap<usize, ElementBox> {
1630 self.views
1631 .iter()
1632 .filter_map(|((win_id, view_id), view)| {
1633 if *win_id == window_id {
1634 Some((
1635 *view_id,
1636 view.render(*win_id, *view_id, titlebar_height, self),
1637 ))
1638 } else {
1639 None
1640 }
1641 })
1642 .collect::<HashMap<_, ElementBox>>()
1643 }
1644
1645 pub fn background(&self) -> &Arc<executor::Background> {
1646 &self.background
1647 }
1648
1649 pub fn font_cache(&self) -> &Arc<FontCache> {
1650 &self.font_cache
1651 }
1652
1653 pub fn platform(&self) -> &Arc<dyn Platform> {
1654 &self.platform
1655 }
1656
1657 pub fn value<Tag: 'static, T: 'static + Default>(&self, id: usize) -> ValueHandle<T> {
1658 let key = (TypeId::of::<Tag>(), id);
1659 self.values
1660 .write()
1661 .entry(key)
1662 .or_insert_with(|| Box::new(T::default()));
1663 ValueHandle::new(TypeId::of::<Tag>(), id, &self.ref_counts)
1664 }
1665}
1666
1667impl ReadModel for AppContext {
1668 fn read_model<T: Entity>(&self, handle: &ModelHandle<T>) -> &T {
1669 if let Some(model) = self.models.get(&handle.model_id) {
1670 model
1671 .as_any()
1672 .downcast_ref()
1673 .expect("downcast should be type safe")
1674 } else {
1675 panic!("circular model reference");
1676 }
1677 }
1678}
1679
1680impl UpgradeModelHandle for AppContext {
1681 fn upgrade_model_handle<T: Entity>(
1682 &self,
1683 handle: WeakModelHandle<T>,
1684 ) -> Option<ModelHandle<T>> {
1685 if self.models.contains_key(&handle.model_id) {
1686 Some(ModelHandle::new(handle.model_id, &self.ref_counts))
1687 } else {
1688 None
1689 }
1690 }
1691}
1692
1693impl ReadView for AppContext {
1694 fn read_view<T: View>(&self, handle: &ViewHandle<T>) -> &T {
1695 if let Some(view) = self.views.get(&(handle.window_id, handle.view_id)) {
1696 view.as_any()
1697 .downcast_ref()
1698 .expect("downcast should be type safe")
1699 } else {
1700 panic!("circular view reference");
1701 }
1702 }
1703}
1704
1705struct Window {
1706 root_view: AnyViewHandle,
1707 focused_view_id: usize,
1708 invalidation: Option<WindowInvalidation>,
1709}
1710
1711#[derive(Default, Clone)]
1712pub struct WindowInvalidation {
1713 pub updated: HashSet<usize>,
1714 pub removed: Vec<usize>,
1715}
1716
1717pub enum Effect {
1718 Event {
1719 entity_id: usize,
1720 payload: Box<dyn Any>,
1721 },
1722 ModelNotification {
1723 model_id: usize,
1724 },
1725 ViewNotification {
1726 window_id: usize,
1727 view_id: usize,
1728 },
1729 Focus {
1730 window_id: usize,
1731 view_id: usize,
1732 },
1733}
1734
1735impl Debug for Effect {
1736 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1737 match self {
1738 Effect::Event { entity_id, .. } => f
1739 .debug_struct("Effect::Event")
1740 .field("entity_id", entity_id)
1741 .finish(),
1742 Effect::ModelNotification { model_id } => f
1743 .debug_struct("Effect::ModelNotification")
1744 .field("model_id", model_id)
1745 .finish(),
1746 Effect::ViewNotification { window_id, view_id } => f
1747 .debug_struct("Effect::ViewNotification")
1748 .field("window_id", window_id)
1749 .field("view_id", view_id)
1750 .finish(),
1751 Effect::Focus { window_id, view_id } => f
1752 .debug_struct("Effect::Focus")
1753 .field("window_id", window_id)
1754 .field("view_id", view_id)
1755 .finish(),
1756 }
1757 }
1758}
1759
1760pub trait AnyModel {
1761 fn as_any(&self) -> &dyn Any;
1762 fn as_any_mut(&mut self) -> &mut dyn Any;
1763 fn release(&mut self, cx: &mut MutableAppContext);
1764}
1765
1766impl<T> AnyModel for T
1767where
1768 T: Entity,
1769{
1770 fn as_any(&self) -> &dyn Any {
1771 self
1772 }
1773
1774 fn as_any_mut(&mut self) -> &mut dyn Any {
1775 self
1776 }
1777
1778 fn release(&mut self, cx: &mut MutableAppContext) {
1779 self.release(cx);
1780 }
1781}
1782
1783pub trait AnyView {
1784 fn as_any(&self) -> &dyn Any;
1785 fn as_any_mut(&mut self) -> &mut dyn Any;
1786 fn release(&mut self, cx: &mut MutableAppContext);
1787 fn ui_name(&self) -> &'static str;
1788 fn render<'a>(
1789 &self,
1790 window_id: usize,
1791 view_id: usize,
1792 titlebar_height: f32,
1793 cx: &AppContext,
1794 ) -> ElementBox;
1795 fn on_focus(&mut self, cx: &mut MutableAppContext, window_id: usize, view_id: usize);
1796 fn on_blur(&mut self, cx: &mut MutableAppContext, window_id: usize, view_id: usize);
1797 fn keymap_context(&self, cx: &AppContext) -> keymap::Context;
1798}
1799
1800impl<T> AnyView for T
1801where
1802 T: View,
1803{
1804 fn as_any(&self) -> &dyn Any {
1805 self
1806 }
1807
1808 fn as_any_mut(&mut self) -> &mut dyn Any {
1809 self
1810 }
1811
1812 fn release(&mut self, cx: &mut MutableAppContext) {
1813 self.release(cx);
1814 }
1815
1816 fn ui_name(&self) -> &'static str {
1817 T::ui_name()
1818 }
1819
1820 fn render<'a>(
1821 &self,
1822 window_id: usize,
1823 view_id: usize,
1824 titlebar_height: f32,
1825 cx: &AppContext,
1826 ) -> ElementBox {
1827 View::render(
1828 self,
1829 &RenderContext {
1830 window_id,
1831 view_id,
1832 app: cx,
1833 view_type: PhantomData::<T>,
1834 titlebar_height,
1835 },
1836 )
1837 }
1838
1839 fn on_focus(&mut self, cx: &mut MutableAppContext, window_id: usize, view_id: usize) {
1840 let mut cx = ViewContext::new(cx, window_id, view_id);
1841 View::on_focus(self, &mut cx);
1842 }
1843
1844 fn on_blur(&mut self, cx: &mut MutableAppContext, window_id: usize, view_id: usize) {
1845 let mut cx = ViewContext::new(cx, window_id, view_id);
1846 View::on_blur(self, &mut cx);
1847 }
1848
1849 fn keymap_context(&self, cx: &AppContext) -> keymap::Context {
1850 View::keymap_context(self, cx)
1851 }
1852}
1853
1854pub struct ModelContext<'a, T: ?Sized> {
1855 app: &'a mut MutableAppContext,
1856 model_id: usize,
1857 model_type: PhantomData<T>,
1858 halt_stream: bool,
1859}
1860
1861impl<'a, T: Entity> ModelContext<'a, T> {
1862 fn new(app: &'a mut MutableAppContext, model_id: usize) -> Self {
1863 Self {
1864 app,
1865 model_id,
1866 model_type: PhantomData,
1867 halt_stream: false,
1868 }
1869 }
1870
1871 pub fn background(&self) -> &Arc<executor::Background> {
1872 &self.app.cx.background
1873 }
1874
1875 pub fn halt_stream(&mut self) {
1876 self.halt_stream = true;
1877 }
1878
1879 pub fn model_id(&self) -> usize {
1880 self.model_id
1881 }
1882
1883 pub fn add_model<S, F>(&mut self, build_model: F) -> ModelHandle<S>
1884 where
1885 S: Entity,
1886 F: FnOnce(&mut ModelContext<S>) -> S,
1887 {
1888 self.app.add_model(build_model)
1889 }
1890
1891 pub fn emit(&mut self, payload: T::Event) {
1892 self.app.pending_effects.push_back(Effect::Event {
1893 entity_id: self.model_id,
1894 payload: Box::new(payload),
1895 });
1896 }
1897
1898 pub fn notify(&mut self) {
1899 self.app
1900 .pending_effects
1901 .push_back(Effect::ModelNotification {
1902 model_id: self.model_id,
1903 });
1904 }
1905
1906 pub fn subscribe<S: Entity, F>(
1907 &mut self,
1908 handle: &ModelHandle<S>,
1909 mut callback: F,
1910 ) -> Subscription
1911 where
1912 S::Event: 'static,
1913 F: 'static + FnMut(&mut T, ModelHandle<S>, &S::Event, &mut ModelContext<T>),
1914 {
1915 let subscriber = self.handle().downgrade();
1916 self.app
1917 .subscribe_internal(handle, move |emitter, event, cx| {
1918 if let Some(subscriber) = subscriber.upgrade(cx) {
1919 subscriber.update(cx, |subscriber, cx| {
1920 callback(subscriber, emitter, event, cx);
1921 });
1922 true
1923 } else {
1924 false
1925 }
1926 })
1927 }
1928
1929 pub fn observe<S, F>(&mut self, handle: &ModelHandle<S>, mut callback: F) -> Subscription
1930 where
1931 S: Entity,
1932 F: 'static + FnMut(&mut T, ModelHandle<S>, &mut ModelContext<T>),
1933 {
1934 let observer = self.handle().downgrade();
1935 self.app.observe_internal(handle, move |observed, cx| {
1936 if let Some(observer) = observer.upgrade(cx) {
1937 observer.update(cx, |observer, cx| {
1938 callback(observer, observed, cx);
1939 });
1940 true
1941 } else {
1942 false
1943 }
1944 })
1945 }
1946
1947 pub fn handle(&self) -> ModelHandle<T> {
1948 ModelHandle::new(self.model_id, &self.app.cx.ref_counts)
1949 }
1950
1951 pub fn spawn<F, Fut, S>(&self, f: F) -> Task<S>
1952 where
1953 F: FnOnce(ModelHandle<T>, AsyncAppContext) -> Fut,
1954 Fut: 'static + Future<Output = S>,
1955 S: 'static,
1956 {
1957 let handle = self.handle();
1958 self.app.spawn(|cx| f(handle, cx))
1959 }
1960
1961 pub fn spawn_weak<F, Fut, S>(&self, f: F) -> Task<S>
1962 where
1963 F: FnOnce(WeakModelHandle<T>, AsyncAppContext) -> Fut,
1964 Fut: 'static + Future<Output = S>,
1965 S: 'static,
1966 {
1967 let handle = self.handle().downgrade();
1968 self.app.spawn(|cx| f(handle, cx))
1969 }
1970}
1971
1972impl<M> AsRef<AppContext> for ModelContext<'_, M> {
1973 fn as_ref(&self) -> &AppContext {
1974 &self.app.cx
1975 }
1976}
1977
1978impl<M> AsMut<MutableAppContext> for ModelContext<'_, M> {
1979 fn as_mut(&mut self) -> &mut MutableAppContext {
1980 self.app
1981 }
1982}
1983
1984impl<M> ReadModel for ModelContext<'_, M> {
1985 fn read_model<T: Entity>(&self, handle: &ModelHandle<T>) -> &T {
1986 self.app.read_model(handle)
1987 }
1988}
1989
1990impl<M> UpdateModel for ModelContext<'_, M> {
1991 fn update_model<T, F, S>(&mut self, handle: &ModelHandle<T>, update: F) -> S
1992 where
1993 T: Entity,
1994 F: FnOnce(&mut T, &mut ModelContext<T>) -> S,
1995 {
1996 self.app.update_model(handle, update)
1997 }
1998}
1999
2000impl<M> UpgradeModelHandle for ModelContext<'_, M> {
2001 fn upgrade_model_handle<T: Entity>(
2002 &self,
2003 handle: WeakModelHandle<T>,
2004 ) -> Option<ModelHandle<T>> {
2005 self.cx.upgrade_model_handle(handle)
2006 }
2007}
2008
2009impl<M> Deref for ModelContext<'_, M> {
2010 type Target = MutableAppContext;
2011
2012 fn deref(&self) -> &Self::Target {
2013 &self.app
2014 }
2015}
2016
2017impl<M> DerefMut for ModelContext<'_, M> {
2018 fn deref_mut(&mut self) -> &mut Self::Target {
2019 &mut self.app
2020 }
2021}
2022
2023pub struct ViewContext<'a, T: ?Sized> {
2024 app: &'a mut MutableAppContext,
2025 window_id: usize,
2026 view_id: usize,
2027 view_type: PhantomData<T>,
2028 halt_action_dispatch: bool,
2029}
2030
2031impl<'a, T: View> ViewContext<'a, T> {
2032 fn new(app: &'a mut MutableAppContext, window_id: usize, view_id: usize) -> Self {
2033 Self {
2034 app,
2035 window_id,
2036 view_id,
2037 view_type: PhantomData,
2038 halt_action_dispatch: true,
2039 }
2040 }
2041
2042 pub fn handle(&self) -> ViewHandle<T> {
2043 ViewHandle::new(self.window_id, self.view_id, &self.app.cx.ref_counts)
2044 }
2045
2046 pub fn window_id(&self) -> usize {
2047 self.window_id
2048 }
2049
2050 pub fn view_id(&self) -> usize {
2051 self.view_id
2052 }
2053
2054 pub fn foreground(&self) -> &Rc<executor::Foreground> {
2055 self.app.foreground()
2056 }
2057
2058 pub fn background_executor(&self) -> &Arc<executor::Background> {
2059 &self.app.cx.background
2060 }
2061
2062 pub fn platform(&self) -> Arc<dyn Platform> {
2063 self.app.platform()
2064 }
2065
2066 pub fn prompt<F>(&self, level: PromptLevel, msg: &str, answers: &[&str], done_fn: F)
2067 where
2068 F: 'static + FnOnce(usize, &mut MutableAppContext),
2069 {
2070 self.app
2071 .prompt(self.window_id, level, msg, answers, done_fn)
2072 }
2073
2074 pub fn prompt_for_paths<F>(&self, options: PathPromptOptions, done_fn: F)
2075 where
2076 F: 'static + FnOnce(Option<Vec<PathBuf>>, &mut MutableAppContext),
2077 {
2078 self.app.prompt_for_paths(options, done_fn)
2079 }
2080
2081 pub fn prompt_for_new_path<F>(&self, directory: &Path, done_fn: F)
2082 where
2083 F: 'static + FnOnce(Option<PathBuf>, &mut MutableAppContext),
2084 {
2085 self.app.prompt_for_new_path(directory, done_fn)
2086 }
2087
2088 pub fn debug_elements(&self) -> crate::json::Value {
2089 self.app.debug_elements(self.window_id).unwrap()
2090 }
2091
2092 pub fn focus<S>(&mut self, handle: S)
2093 where
2094 S: Into<AnyViewHandle>,
2095 {
2096 let handle = handle.into();
2097 self.app.pending_effects.push_back(Effect::Focus {
2098 window_id: handle.window_id,
2099 view_id: handle.view_id,
2100 });
2101 }
2102
2103 pub fn focus_self(&mut self) {
2104 self.app.pending_effects.push_back(Effect::Focus {
2105 window_id: self.window_id,
2106 view_id: self.view_id,
2107 });
2108 }
2109
2110 pub fn add_model<S, F>(&mut self, build_model: F) -> ModelHandle<S>
2111 where
2112 S: Entity,
2113 F: FnOnce(&mut ModelContext<S>) -> S,
2114 {
2115 self.app.add_model(build_model)
2116 }
2117
2118 pub fn add_view<S, F>(&mut self, build_view: F) -> ViewHandle<S>
2119 where
2120 S: View,
2121 F: FnOnce(&mut ViewContext<S>) -> S,
2122 {
2123 self.app.add_view(self.window_id, build_view)
2124 }
2125
2126 pub fn add_option_view<S, F>(&mut self, build_view: F) -> Option<ViewHandle<S>>
2127 where
2128 S: View,
2129 F: FnOnce(&mut ViewContext<S>) -> Option<S>,
2130 {
2131 self.app.add_option_view(self.window_id, build_view)
2132 }
2133
2134 pub fn subscribe<E, H, F>(&mut self, handle: &H, mut callback: F) -> Subscription
2135 where
2136 E: Entity,
2137 E::Event: 'static,
2138 H: Handle<E>,
2139 F: 'static + FnMut(&mut T, H, &E::Event, &mut ViewContext<T>),
2140 {
2141 let subscriber = self.handle().downgrade();
2142 self.app
2143 .subscribe_internal(handle, move |emitter, event, cx| {
2144 if let Some(subscriber) = subscriber.upgrade(cx) {
2145 subscriber.update(cx, |subscriber, cx| {
2146 callback(subscriber, emitter, event, cx);
2147 });
2148 true
2149 } else {
2150 false
2151 }
2152 })
2153 }
2154
2155 pub fn observe<E, F, H>(&mut self, handle: &H, mut callback: F) -> Subscription
2156 where
2157 E: Entity,
2158 H: Handle<E>,
2159 F: 'static + FnMut(&mut T, H, &mut ViewContext<T>),
2160 {
2161 let observer = self.handle().downgrade();
2162 self.app.observe_internal(handle, move |observed, cx| {
2163 if let Some(observer) = observer.upgrade(cx) {
2164 observer.update(cx, |observer, cx| {
2165 callback(observer, observed, cx);
2166 });
2167 true
2168 } else {
2169 false
2170 }
2171 })
2172 }
2173
2174 pub fn emit(&mut self, payload: T::Event) {
2175 self.app.pending_effects.push_back(Effect::Event {
2176 entity_id: self.view_id,
2177 payload: Box::new(payload),
2178 });
2179 }
2180
2181 pub fn notify(&mut self) {
2182 self.app.notify_view(self.window_id, self.view_id);
2183 }
2184
2185 pub fn notify_all(&mut self) {
2186 self.app.notify_all_views();
2187 }
2188
2189 pub fn propagate_action(&mut self) {
2190 self.halt_action_dispatch = false;
2191 }
2192
2193 pub fn spawn<F, Fut, S>(&self, f: F) -> Task<S>
2194 where
2195 F: FnOnce(ViewHandle<T>, AsyncAppContext) -> Fut,
2196 Fut: 'static + Future<Output = S>,
2197 S: 'static,
2198 {
2199 let handle = self.handle();
2200 self.app.spawn(|cx| f(handle, cx))
2201 }
2202}
2203
2204pub struct RenderContext<'a, T: View> {
2205 pub app: &'a AppContext,
2206 pub titlebar_height: f32,
2207 window_id: usize,
2208 view_id: usize,
2209 view_type: PhantomData<T>,
2210}
2211
2212impl<'a, T: View> RenderContext<'a, T> {
2213 pub fn handle(&self) -> WeakViewHandle<T> {
2214 WeakViewHandle::new(self.window_id, self.view_id)
2215 }
2216}
2217
2218impl AsRef<AppContext> for &AppContext {
2219 fn as_ref(&self) -> &AppContext {
2220 self
2221 }
2222}
2223
2224impl<V: View> Deref for RenderContext<'_, V> {
2225 type Target = AppContext;
2226
2227 fn deref(&self) -> &Self::Target {
2228 &self.app
2229 }
2230}
2231
2232impl<M> AsRef<AppContext> for ViewContext<'_, M> {
2233 fn as_ref(&self) -> &AppContext {
2234 &self.app.cx
2235 }
2236}
2237
2238impl<M> Deref for ViewContext<'_, M> {
2239 type Target = MutableAppContext;
2240
2241 fn deref(&self) -> &Self::Target {
2242 &self.app
2243 }
2244}
2245
2246impl<M> DerefMut for ViewContext<'_, M> {
2247 fn deref_mut(&mut self) -> &mut Self::Target {
2248 &mut self.app
2249 }
2250}
2251
2252impl<M> AsMut<MutableAppContext> for ViewContext<'_, M> {
2253 fn as_mut(&mut self) -> &mut MutableAppContext {
2254 self.app
2255 }
2256}
2257
2258impl<V> ReadModel for ViewContext<'_, V> {
2259 fn read_model<T: Entity>(&self, handle: &ModelHandle<T>) -> &T {
2260 self.app.read_model(handle)
2261 }
2262}
2263
2264impl<V> UpgradeModelHandle for ViewContext<'_, V> {
2265 fn upgrade_model_handle<T: Entity>(
2266 &self,
2267 handle: WeakModelHandle<T>,
2268 ) -> Option<ModelHandle<T>> {
2269 self.cx.upgrade_model_handle(handle)
2270 }
2271}
2272
2273impl<V: View> UpdateModel for ViewContext<'_, V> {
2274 fn update_model<T, F, S>(&mut self, handle: &ModelHandle<T>, update: F) -> S
2275 where
2276 T: Entity,
2277 F: FnOnce(&mut T, &mut ModelContext<T>) -> S,
2278 {
2279 self.app.update_model(handle, update)
2280 }
2281}
2282
2283impl<V: View> ReadView for ViewContext<'_, V> {
2284 fn read_view<T: View>(&self, handle: &ViewHandle<T>) -> &T {
2285 self.app.read_view(handle)
2286 }
2287}
2288
2289impl<V: View> UpdateView for ViewContext<'_, V> {
2290 fn update_view<T, F, S>(&mut self, handle: &ViewHandle<T>, update: F) -> S
2291 where
2292 T: View,
2293 F: FnOnce(&mut T, &mut ViewContext<T>) -> S,
2294 {
2295 self.app.update_view(handle, update)
2296 }
2297}
2298
2299pub trait Handle<T> {
2300 type Weak: 'static;
2301 fn id(&self) -> usize;
2302 fn location(&self) -> EntityLocation;
2303 fn downgrade(&self) -> Self::Weak;
2304 fn upgrade_from(weak: &Self::Weak, cx: &AppContext) -> Option<Self>
2305 where
2306 Self: Sized;
2307}
2308
2309#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
2310pub enum EntityLocation {
2311 Model(usize),
2312 View(usize, usize),
2313}
2314
2315pub struct ModelHandle<T> {
2316 model_id: usize,
2317 model_type: PhantomData<T>,
2318 ref_counts: Arc<Mutex<RefCounts>>,
2319}
2320
2321impl<T: Entity> ModelHandle<T> {
2322 fn new(model_id: usize, ref_counts: &Arc<Mutex<RefCounts>>) -> Self {
2323 ref_counts.lock().inc_model(model_id);
2324 Self {
2325 model_id,
2326 model_type: PhantomData,
2327 ref_counts: ref_counts.clone(),
2328 }
2329 }
2330
2331 pub fn downgrade(&self) -> WeakModelHandle<T> {
2332 WeakModelHandle::new(self.model_id)
2333 }
2334
2335 pub fn id(&self) -> usize {
2336 self.model_id
2337 }
2338
2339 pub fn read<'a, C: ReadModel>(&self, cx: &'a C) -> &'a T {
2340 cx.read_model(self)
2341 }
2342
2343 pub fn read_with<'a, C, F, S>(&self, cx: &C, read: F) -> S
2344 where
2345 C: ReadModelWith,
2346 F: FnOnce(&T, &AppContext) -> S,
2347 {
2348 cx.read_model_with(self, read)
2349 }
2350
2351 pub fn update<C, F, S>(&self, cx: &mut C, update: F) -> S
2352 where
2353 C: UpdateModel,
2354 F: FnOnce(&mut T, &mut ModelContext<T>) -> S,
2355 {
2356 cx.update_model(self, update)
2357 }
2358
2359 pub fn next_notification(&self, cx: &TestAppContext) -> impl Future<Output = ()> {
2360 let (mut tx, mut rx) = mpsc::channel(1);
2361 let mut cx = cx.cx.borrow_mut();
2362 let subscription = cx.observe(self, move |_, _| {
2363 tx.blocking_send(()).ok();
2364 });
2365
2366 let duration = if std::env::var("CI").is_ok() {
2367 Duration::from_secs(5)
2368 } else {
2369 Duration::from_secs(1)
2370 };
2371
2372 async move {
2373 let notification = timeout(duration, rx.recv())
2374 .await
2375 .expect("next notification timed out");
2376 drop(subscription);
2377 notification.expect("model dropped while test was waiting for its next notification")
2378 }
2379 }
2380
2381 pub fn next_event(&self, cx: &TestAppContext) -> impl Future<Output = T::Event>
2382 where
2383 T::Event: Clone,
2384 {
2385 let (mut tx, mut rx) = mpsc::channel(1);
2386 let mut cx = cx.cx.borrow_mut();
2387 let subscription = cx.subscribe(self, move |_, event, _| {
2388 tx.blocking_send(event.clone()).ok();
2389 });
2390
2391 let duration = if std::env::var("CI").is_ok() {
2392 Duration::from_secs(5)
2393 } else {
2394 Duration::from_secs(1)
2395 };
2396
2397 async move {
2398 let event = timeout(duration, rx.recv())
2399 .await
2400 .expect("next event timed out");
2401 drop(subscription);
2402 event.expect("model dropped while test was waiting for its next event")
2403 }
2404 }
2405
2406 pub fn condition(
2407 &self,
2408 cx: &TestAppContext,
2409 mut predicate: impl FnMut(&T, &AppContext) -> bool,
2410 ) -> impl Future<Output = ()> {
2411 let (tx, mut rx) = mpsc::channel(1024);
2412
2413 let mut cx = cx.cx.borrow_mut();
2414 let subscriptions = (
2415 cx.observe(self, {
2416 let mut tx = tx.clone();
2417 move |_, _| {
2418 tx.blocking_send(()).ok();
2419 }
2420 }),
2421 cx.subscribe(self, {
2422 let mut tx = tx.clone();
2423 move |_, _, _| {
2424 tx.blocking_send(()).ok();
2425 }
2426 }),
2427 );
2428
2429 let cx = cx.weak_self.as_ref().unwrap().upgrade().unwrap();
2430 let handle = self.downgrade();
2431 let duration = if std::env::var("CI").is_ok() {
2432 Duration::from_secs(5)
2433 } else {
2434 Duration::from_secs(1)
2435 };
2436
2437 async move {
2438 timeout(duration, async move {
2439 loop {
2440 {
2441 let cx = cx.borrow();
2442 let cx = cx.as_ref();
2443 if predicate(
2444 handle
2445 .upgrade(cx)
2446 .expect("model dropped with pending condition")
2447 .read(cx),
2448 cx,
2449 ) {
2450 break;
2451 }
2452 }
2453
2454 rx.recv()
2455 .await
2456 .expect("model dropped with pending condition");
2457 }
2458 })
2459 .await
2460 .expect("condition timed out");
2461 drop(subscriptions);
2462 }
2463 }
2464}
2465
2466impl<T> Clone for ModelHandle<T> {
2467 fn clone(&self) -> Self {
2468 self.ref_counts.lock().inc_model(self.model_id);
2469 Self {
2470 model_id: self.model_id,
2471 model_type: PhantomData,
2472 ref_counts: self.ref_counts.clone(),
2473 }
2474 }
2475}
2476
2477impl<T> PartialEq for ModelHandle<T> {
2478 fn eq(&self, other: &Self) -> bool {
2479 self.model_id == other.model_id
2480 }
2481}
2482
2483impl<T> Eq for ModelHandle<T> {}
2484
2485impl<T> Hash for ModelHandle<T> {
2486 fn hash<H: Hasher>(&self, state: &mut H) {
2487 self.model_id.hash(state);
2488 }
2489}
2490
2491impl<T> std::borrow::Borrow<usize> for ModelHandle<T> {
2492 fn borrow(&self) -> &usize {
2493 &self.model_id
2494 }
2495}
2496
2497impl<T> Debug for ModelHandle<T> {
2498 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2499 f.debug_tuple(&format!("ModelHandle<{}>", type_name::<T>()))
2500 .field(&self.model_id)
2501 .finish()
2502 }
2503}
2504
2505unsafe impl<T> Send for ModelHandle<T> {}
2506unsafe impl<T> Sync for ModelHandle<T> {}
2507
2508impl<T> Drop for ModelHandle<T> {
2509 fn drop(&mut self) {
2510 self.ref_counts.lock().dec_model(self.model_id);
2511 }
2512}
2513
2514impl<T: Entity> Handle<T> for ModelHandle<T> {
2515 type Weak = WeakModelHandle<T>;
2516
2517 fn id(&self) -> usize {
2518 self.model_id
2519 }
2520
2521 fn location(&self) -> EntityLocation {
2522 EntityLocation::Model(self.model_id)
2523 }
2524
2525 fn downgrade(&self) -> Self::Weak {
2526 self.downgrade()
2527 }
2528
2529 fn upgrade_from(weak: &Self::Weak, cx: &AppContext) -> Option<Self>
2530 where
2531 Self: Sized,
2532 {
2533 weak.upgrade(cx)
2534 }
2535}
2536
2537pub struct WeakModelHandle<T> {
2538 model_id: usize,
2539 model_type: PhantomData<T>,
2540}
2541
2542unsafe impl<T> Send for WeakModelHandle<T> {}
2543unsafe impl<T> Sync for WeakModelHandle<T> {}
2544
2545impl<T: Entity> WeakModelHandle<T> {
2546 fn new(model_id: usize) -> Self {
2547 Self {
2548 model_id,
2549 model_type: PhantomData,
2550 }
2551 }
2552
2553 pub fn upgrade(self, cx: &impl UpgradeModelHandle) -> Option<ModelHandle<T>> {
2554 cx.upgrade_model_handle(self)
2555 }
2556}
2557
2558impl<T> Hash for WeakModelHandle<T> {
2559 fn hash<H: Hasher>(&self, state: &mut H) {
2560 self.model_id.hash(state)
2561 }
2562}
2563
2564impl<T> PartialEq for WeakModelHandle<T> {
2565 fn eq(&self, other: &Self) -> bool {
2566 self.model_id == other.model_id
2567 }
2568}
2569
2570impl<T> Eq for WeakModelHandle<T> {}
2571
2572impl<T> Clone for WeakModelHandle<T> {
2573 fn clone(&self) -> Self {
2574 Self {
2575 model_id: self.model_id,
2576 model_type: PhantomData,
2577 }
2578 }
2579}
2580
2581impl<T> Copy for WeakModelHandle<T> {}
2582
2583pub struct ViewHandle<T> {
2584 window_id: usize,
2585 view_id: usize,
2586 view_type: PhantomData<T>,
2587 ref_counts: Arc<Mutex<RefCounts>>,
2588}
2589
2590impl<T: View> ViewHandle<T> {
2591 fn new(window_id: usize, view_id: usize, ref_counts: &Arc<Mutex<RefCounts>>) -> Self {
2592 ref_counts.lock().inc_view(window_id, view_id);
2593 Self {
2594 window_id,
2595 view_id,
2596 view_type: PhantomData,
2597 ref_counts: ref_counts.clone(),
2598 }
2599 }
2600
2601 pub fn downgrade(&self) -> WeakViewHandle<T> {
2602 WeakViewHandle::new(self.window_id, self.view_id)
2603 }
2604
2605 pub fn window_id(&self) -> usize {
2606 self.window_id
2607 }
2608
2609 pub fn id(&self) -> usize {
2610 self.view_id
2611 }
2612
2613 pub fn read<'a, C: ReadView>(&self, cx: &'a C) -> &'a T {
2614 cx.read_view(self)
2615 }
2616
2617 pub fn read_with<C, F, S>(&self, cx: &C, read: F) -> S
2618 where
2619 C: ReadViewWith,
2620 F: FnOnce(&T, &AppContext) -> S,
2621 {
2622 cx.read_view_with(self, read)
2623 }
2624
2625 pub fn update<C, F, S>(&self, cx: &mut C, update: F) -> S
2626 where
2627 C: UpdateView,
2628 F: FnOnce(&mut T, &mut ViewContext<T>) -> S,
2629 {
2630 cx.update_view(self, update)
2631 }
2632
2633 pub fn is_focused(&self, cx: &AppContext) -> bool {
2634 cx.focused_view_id(self.window_id)
2635 .map_or(false, |focused_id| focused_id == self.view_id)
2636 }
2637
2638 pub fn condition(
2639 &self,
2640 cx: &TestAppContext,
2641 mut predicate: impl FnMut(&T, &AppContext) -> bool,
2642 ) -> impl Future<Output = ()> {
2643 let (tx, mut rx) = mpsc::channel(1024);
2644
2645 let mut cx = cx.cx.borrow_mut();
2646 let subscriptions = self.update(&mut *cx, |_, cx| {
2647 (
2648 cx.observe(self, {
2649 let mut tx = tx.clone();
2650 move |_, _, _| {
2651 tx.blocking_send(()).ok();
2652 }
2653 }),
2654 cx.subscribe(self, {
2655 let mut tx = tx.clone();
2656 move |_, _, _, _| {
2657 tx.blocking_send(()).ok();
2658 }
2659 }),
2660 )
2661 });
2662
2663 let cx = cx.weak_self.as_ref().unwrap().upgrade().unwrap();
2664 let handle = self.downgrade();
2665 let duration = if std::env::var("CI").is_ok() {
2666 Duration::from_secs(2)
2667 } else {
2668 Duration::from_millis(500)
2669 };
2670
2671 async move {
2672 timeout(duration, async move {
2673 loop {
2674 {
2675 let cx = cx.borrow();
2676 let cx = cx.as_ref();
2677 if predicate(
2678 handle
2679 .upgrade(cx)
2680 .expect("view dropped with pending condition")
2681 .read(cx),
2682 cx,
2683 ) {
2684 break;
2685 }
2686 }
2687
2688 rx.recv()
2689 .await
2690 .expect("view dropped with pending condition");
2691 }
2692 })
2693 .await
2694 .expect("condition timed out");
2695 drop(subscriptions);
2696 }
2697 }
2698}
2699
2700impl<T> Clone for ViewHandle<T> {
2701 fn clone(&self) -> Self {
2702 self.ref_counts
2703 .lock()
2704 .inc_view(self.window_id, self.view_id);
2705 Self {
2706 window_id: self.window_id,
2707 view_id: self.view_id,
2708 view_type: PhantomData,
2709 ref_counts: self.ref_counts.clone(),
2710 }
2711 }
2712}
2713
2714impl<T> PartialEq for ViewHandle<T> {
2715 fn eq(&self, other: &Self) -> bool {
2716 self.window_id == other.window_id && self.view_id == other.view_id
2717 }
2718}
2719
2720impl<T> Eq for ViewHandle<T> {}
2721
2722impl<T> Debug for ViewHandle<T> {
2723 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2724 f.debug_struct(&format!("ViewHandle<{}>", type_name::<T>()))
2725 .field("window_id", &self.window_id)
2726 .field("view_id", &self.view_id)
2727 .finish()
2728 }
2729}
2730
2731impl<T> Drop for ViewHandle<T> {
2732 fn drop(&mut self) {
2733 self.ref_counts
2734 .lock()
2735 .dec_view(self.window_id, self.view_id);
2736 }
2737}
2738
2739impl<T: View> Handle<T> for ViewHandle<T> {
2740 type Weak = WeakViewHandle<T>;
2741
2742 fn id(&self) -> usize {
2743 self.view_id
2744 }
2745
2746 fn location(&self) -> EntityLocation {
2747 EntityLocation::View(self.window_id, self.view_id)
2748 }
2749
2750 fn downgrade(&self) -> Self::Weak {
2751 self.downgrade()
2752 }
2753
2754 fn upgrade_from(weak: &Self::Weak, cx: &AppContext) -> Option<Self>
2755 where
2756 Self: Sized,
2757 {
2758 weak.upgrade(cx)
2759 }
2760}
2761
2762pub struct AnyViewHandle {
2763 window_id: usize,
2764 view_id: usize,
2765 view_type: TypeId,
2766 ref_counts: Arc<Mutex<RefCounts>>,
2767}
2768
2769impl AnyViewHandle {
2770 pub fn id(&self) -> usize {
2771 self.view_id
2772 }
2773
2774 pub fn is<T: 'static>(&self) -> bool {
2775 TypeId::of::<T>() == self.view_type
2776 }
2777
2778 pub fn downcast<T: View>(self) -> Option<ViewHandle<T>> {
2779 if self.is::<T>() {
2780 let result = Some(ViewHandle {
2781 window_id: self.window_id,
2782 view_id: self.view_id,
2783 ref_counts: self.ref_counts.clone(),
2784 view_type: PhantomData,
2785 });
2786 unsafe {
2787 Arc::decrement_strong_count(&self.ref_counts);
2788 }
2789 std::mem::forget(self);
2790 result
2791 } else {
2792 None
2793 }
2794 }
2795}
2796
2797impl Clone for AnyViewHandle {
2798 fn clone(&self) -> Self {
2799 self.ref_counts
2800 .lock()
2801 .inc_view(self.window_id, self.view_id);
2802 Self {
2803 window_id: self.window_id,
2804 view_id: self.view_id,
2805 view_type: self.view_type,
2806 ref_counts: self.ref_counts.clone(),
2807 }
2808 }
2809}
2810
2811impl<T: View> From<&ViewHandle<T>> for AnyViewHandle {
2812 fn from(handle: &ViewHandle<T>) -> Self {
2813 handle
2814 .ref_counts
2815 .lock()
2816 .inc_view(handle.window_id, handle.view_id);
2817 AnyViewHandle {
2818 window_id: handle.window_id,
2819 view_id: handle.view_id,
2820 view_type: TypeId::of::<T>(),
2821 ref_counts: handle.ref_counts.clone(),
2822 }
2823 }
2824}
2825
2826impl<T: View> From<ViewHandle<T>> for AnyViewHandle {
2827 fn from(handle: ViewHandle<T>) -> Self {
2828 let any_handle = AnyViewHandle {
2829 window_id: handle.window_id,
2830 view_id: handle.view_id,
2831 view_type: TypeId::of::<T>(),
2832 ref_counts: handle.ref_counts.clone(),
2833 };
2834 unsafe {
2835 Arc::decrement_strong_count(&handle.ref_counts);
2836 }
2837 std::mem::forget(handle);
2838 any_handle
2839 }
2840}
2841
2842impl Drop for AnyViewHandle {
2843 fn drop(&mut self) {
2844 self.ref_counts
2845 .lock()
2846 .dec_view(self.window_id, self.view_id);
2847 }
2848}
2849
2850pub struct AnyModelHandle {
2851 model_id: usize,
2852 ref_counts: Arc<Mutex<RefCounts>>,
2853}
2854
2855impl<T: Entity> From<ModelHandle<T>> for AnyModelHandle {
2856 fn from(handle: ModelHandle<T>) -> Self {
2857 handle.ref_counts.lock().inc_model(handle.model_id);
2858 Self {
2859 model_id: handle.model_id,
2860 ref_counts: handle.ref_counts.clone(),
2861 }
2862 }
2863}
2864
2865impl Drop for AnyModelHandle {
2866 fn drop(&mut self) {
2867 self.ref_counts.lock().dec_model(self.model_id);
2868 }
2869}
2870pub struct WeakViewHandle<T> {
2871 window_id: usize,
2872 view_id: usize,
2873 view_type: PhantomData<T>,
2874}
2875
2876impl<T: View> WeakViewHandle<T> {
2877 fn new(window_id: usize, view_id: usize) -> Self {
2878 Self {
2879 window_id,
2880 view_id,
2881 view_type: PhantomData,
2882 }
2883 }
2884
2885 pub fn upgrade(&self, cx: &AppContext) -> Option<ViewHandle<T>> {
2886 if cx.ref_counts.lock().is_entity_alive(self.view_id) {
2887 Some(ViewHandle::new(
2888 self.window_id,
2889 self.view_id,
2890 &cx.ref_counts,
2891 ))
2892 } else {
2893 None
2894 }
2895 }
2896}
2897
2898impl<T> Clone for WeakViewHandle<T> {
2899 fn clone(&self) -> Self {
2900 Self {
2901 window_id: self.window_id,
2902 view_id: self.view_id,
2903 view_type: PhantomData,
2904 }
2905 }
2906}
2907
2908pub struct ValueHandle<T> {
2909 value_type: PhantomData<T>,
2910 tag_type_id: TypeId,
2911 id: usize,
2912 ref_counts: Weak<Mutex<RefCounts>>,
2913}
2914
2915impl<T: 'static> ValueHandle<T> {
2916 fn new(tag_type_id: TypeId, id: usize, ref_counts: &Arc<Mutex<RefCounts>>) -> Self {
2917 ref_counts.lock().inc_value(tag_type_id, id);
2918 Self {
2919 value_type: PhantomData,
2920 tag_type_id,
2921 id,
2922 ref_counts: Arc::downgrade(ref_counts),
2923 }
2924 }
2925
2926 pub fn read<R>(&self, cx: &AppContext, f: impl FnOnce(&T) -> R) -> R {
2927 f(cx.values
2928 .read()
2929 .get(&(self.tag_type_id, self.id))
2930 .unwrap()
2931 .downcast_ref()
2932 .unwrap())
2933 }
2934
2935 pub fn update<R>(
2936 &self,
2937 cx: &mut EventContext,
2938 f: impl FnOnce(&mut T, &mut EventContext) -> R,
2939 ) -> R {
2940 let mut value = cx
2941 .app
2942 .cx
2943 .values
2944 .write()
2945 .remove(&(self.tag_type_id, self.id))
2946 .unwrap();
2947 let result = f(value.downcast_mut().unwrap(), cx);
2948 cx.app
2949 .cx
2950 .values
2951 .write()
2952 .insert((self.tag_type_id, self.id), value);
2953 result
2954 }
2955}
2956
2957impl<T> Drop for ValueHandle<T> {
2958 fn drop(&mut self) {
2959 if let Some(ref_counts) = self.ref_counts.upgrade() {
2960 ref_counts.lock().dec_value(self.tag_type_id, self.id);
2961 }
2962 }
2963}
2964
2965#[must_use]
2966pub enum Subscription {
2967 Subscription {
2968 id: usize,
2969 entity_id: usize,
2970 subscriptions: Option<Weak<Mutex<HashMap<usize, HashMap<usize, SubscriptionCallback>>>>>,
2971 },
2972 Observation {
2973 id: usize,
2974 entity_id: usize,
2975 observations: Option<Weak<Mutex<HashMap<usize, HashMap<usize, ObservationCallback>>>>>,
2976 },
2977}
2978
2979impl Subscription {
2980 pub fn detach(&mut self) {
2981 match self {
2982 Subscription::Subscription { subscriptions, .. } => {
2983 subscriptions.take();
2984 }
2985 Subscription::Observation { observations, .. } => {
2986 observations.take();
2987 }
2988 }
2989 }
2990}
2991
2992impl Drop for Subscription {
2993 fn drop(&mut self) {
2994 match self {
2995 Subscription::Observation {
2996 id,
2997 entity_id,
2998 observations,
2999 } => {
3000 if let Some(observations) = observations.as_ref().and_then(Weak::upgrade) {
3001 if let Some(observations) = observations.lock().get_mut(entity_id) {
3002 observations.remove(id);
3003 }
3004 }
3005 }
3006 Subscription::Subscription {
3007 id,
3008 entity_id,
3009 subscriptions,
3010 } => {
3011 if let Some(subscriptions) = subscriptions.as_ref().and_then(Weak::upgrade) {
3012 if let Some(subscriptions) = subscriptions.lock().get_mut(entity_id) {
3013 subscriptions.remove(id);
3014 }
3015 }
3016 }
3017 }
3018 }
3019}
3020
3021#[derive(Default)]
3022struct RefCounts {
3023 entity_counts: HashMap<usize, usize>,
3024 value_counts: HashMap<(TypeId, usize), usize>,
3025 dropped_models: HashSet<usize>,
3026 dropped_views: HashSet<(usize, usize)>,
3027 dropped_values: HashSet<(TypeId, usize)>,
3028}
3029
3030impl RefCounts {
3031 fn inc_model(&mut self, model_id: usize) {
3032 match self.entity_counts.entry(model_id) {
3033 Entry::Occupied(mut entry) => *entry.get_mut() += 1,
3034 Entry::Vacant(entry) => {
3035 entry.insert(1);
3036 self.dropped_models.remove(&model_id);
3037 }
3038 }
3039 }
3040
3041 fn inc_view(&mut self, window_id: usize, view_id: usize) {
3042 match self.entity_counts.entry(view_id) {
3043 Entry::Occupied(mut entry) => *entry.get_mut() += 1,
3044 Entry::Vacant(entry) => {
3045 entry.insert(1);
3046 self.dropped_views.remove(&(window_id, view_id));
3047 }
3048 }
3049 }
3050
3051 fn inc_value(&mut self, tag_type_id: TypeId, id: usize) {
3052 *self.value_counts.entry((tag_type_id, id)).or_insert(0) += 1;
3053 }
3054
3055 fn dec_model(&mut self, model_id: usize) {
3056 let count = self.entity_counts.get_mut(&model_id).unwrap();
3057 *count -= 1;
3058 if *count == 0 {
3059 self.entity_counts.remove(&model_id);
3060 self.dropped_models.insert(model_id);
3061 }
3062 }
3063
3064 fn dec_view(&mut self, window_id: usize, view_id: usize) {
3065 let count = self.entity_counts.get_mut(&view_id).unwrap();
3066 *count -= 1;
3067 if *count == 0 {
3068 self.entity_counts.remove(&view_id);
3069 self.dropped_views.insert((window_id, view_id));
3070 }
3071 }
3072
3073 fn dec_value(&mut self, tag_type_id: TypeId, id: usize) {
3074 let key = (tag_type_id, id);
3075 let count = self.value_counts.get_mut(&key).unwrap();
3076 *count -= 1;
3077 if *count == 0 {
3078 self.value_counts.remove(&key);
3079 self.dropped_values.insert(key);
3080 }
3081 }
3082
3083 fn is_entity_alive(&self, entity_id: usize) -> bool {
3084 self.entity_counts.contains_key(&entity_id)
3085 }
3086
3087 fn take_dropped(
3088 &mut self,
3089 ) -> (
3090 HashSet<usize>,
3091 HashSet<(usize, usize)>,
3092 HashSet<(TypeId, usize)>,
3093 ) {
3094 let mut dropped_models = HashSet::new();
3095 let mut dropped_views = HashSet::new();
3096 let mut dropped_values = HashSet::new();
3097 std::mem::swap(&mut self.dropped_models, &mut dropped_models);
3098 std::mem::swap(&mut self.dropped_views, &mut dropped_views);
3099 std::mem::swap(&mut self.dropped_values, &mut dropped_values);
3100 (dropped_models, dropped_views, dropped_values)
3101 }
3102}
3103
3104#[cfg(test)]
3105mod tests {
3106 use super::*;
3107 use crate::elements::*;
3108 use smol::future::poll_once;
3109 use std::sync::atomic::{AtomicUsize, Ordering::SeqCst};
3110
3111 #[crate::test(self)]
3112 fn test_model_handles(cx: &mut MutableAppContext) {
3113 struct Model {
3114 other: Option<ModelHandle<Model>>,
3115 events: Vec<String>,
3116 }
3117
3118 impl Entity for Model {
3119 type Event = usize;
3120 }
3121
3122 impl Model {
3123 fn new(other: Option<ModelHandle<Self>>, cx: &mut ModelContext<Self>) -> Self {
3124 if let Some(other) = other.as_ref() {
3125 cx.observe(other, |me, _, _| {
3126 me.events.push("notified".into());
3127 })
3128 .detach();
3129 cx.subscribe(other, |me, _, event, _| {
3130 me.events.push(format!("observed event {}", event));
3131 })
3132 .detach();
3133 }
3134
3135 Self {
3136 other,
3137 events: Vec::new(),
3138 }
3139 }
3140 }
3141
3142 let handle_1 = cx.add_model(|cx| Model::new(None, cx));
3143 let handle_2 = cx.add_model(|cx| Model::new(Some(handle_1.clone()), cx));
3144 assert_eq!(cx.cx.models.len(), 2);
3145
3146 handle_1.update(cx, |model, cx| {
3147 model.events.push("updated".into());
3148 cx.emit(1);
3149 cx.notify();
3150 cx.emit(2);
3151 });
3152 assert_eq!(handle_1.read(cx).events, vec!["updated".to_string()]);
3153 assert_eq!(
3154 handle_2.read(cx).events,
3155 vec![
3156 "observed event 1".to_string(),
3157 "notified".to_string(),
3158 "observed event 2".to_string(),
3159 ]
3160 );
3161
3162 handle_2.update(cx, |model, _| {
3163 drop(handle_1);
3164 model.other.take();
3165 });
3166
3167 assert_eq!(cx.cx.models.len(), 1);
3168 assert!(cx.subscriptions.lock().is_empty());
3169 assert!(cx.observations.lock().is_empty());
3170 }
3171
3172 #[crate::test(self)]
3173 fn test_subscribe_and_emit_from_model(cx: &mut MutableAppContext) {
3174 #[derive(Default)]
3175 struct Model {
3176 events: Vec<usize>,
3177 }
3178
3179 impl Entity for Model {
3180 type Event = usize;
3181 }
3182
3183 let handle_1 = cx.add_model(|_| Model::default());
3184 let handle_2 = cx.add_model(|_| Model::default());
3185 let handle_2b = handle_2.clone();
3186
3187 handle_1.update(cx, |_, c| {
3188 c.subscribe(&handle_2, move |model: &mut Model, _, event, c| {
3189 model.events.push(*event);
3190
3191 c.subscribe(&handle_2b, |model, _, event, _| {
3192 model.events.push(*event * 2);
3193 })
3194 .detach();
3195 })
3196 .detach();
3197 });
3198
3199 handle_2.update(cx, |_, c| c.emit(7));
3200 assert_eq!(handle_1.read(cx).events, vec![7]);
3201
3202 handle_2.update(cx, |_, c| c.emit(5));
3203 assert_eq!(handle_1.read(cx).events, vec![7, 10, 5]);
3204 }
3205
3206 #[crate::test(self)]
3207 fn test_observe_and_notify_from_model(cx: &mut MutableAppContext) {
3208 #[derive(Default)]
3209 struct Model {
3210 count: usize,
3211 events: Vec<usize>,
3212 }
3213
3214 impl Entity for Model {
3215 type Event = ();
3216 }
3217
3218 let handle_1 = cx.add_model(|_| Model::default());
3219 let handle_2 = cx.add_model(|_| Model::default());
3220 let handle_2b = handle_2.clone();
3221
3222 handle_1.update(cx, |_, c| {
3223 c.observe(&handle_2, move |model, observed, c| {
3224 model.events.push(observed.read(c).count);
3225 c.observe(&handle_2b, |model, observed, c| {
3226 model.events.push(observed.read(c).count * 2);
3227 })
3228 .detach();
3229 })
3230 .detach();
3231 });
3232
3233 handle_2.update(cx, |model, c| {
3234 model.count = 7;
3235 c.notify()
3236 });
3237 assert_eq!(handle_1.read(cx).events, vec![7]);
3238
3239 handle_2.update(cx, |model, c| {
3240 model.count = 5;
3241 c.notify()
3242 });
3243 assert_eq!(handle_1.read(cx).events, vec![7, 10, 5])
3244 }
3245
3246 #[crate::test(self)]
3247 fn test_view_handles(cx: &mut MutableAppContext) {
3248 struct View {
3249 other: Option<ViewHandle<View>>,
3250 events: Vec<String>,
3251 }
3252
3253 impl Entity for View {
3254 type Event = usize;
3255 }
3256
3257 impl super::View for View {
3258 fn render<'a>(&self, _: &RenderContext<Self>) -> ElementBox {
3259 Empty::new().boxed()
3260 }
3261
3262 fn ui_name() -> &'static str {
3263 "View"
3264 }
3265 }
3266
3267 impl View {
3268 fn new(other: Option<ViewHandle<View>>, cx: &mut ViewContext<Self>) -> Self {
3269 if let Some(other) = other.as_ref() {
3270 cx.subscribe(other, |me, _, event, _| {
3271 me.events.push(format!("observed event {}", event));
3272 })
3273 .detach();
3274 }
3275 Self {
3276 other,
3277 events: Vec::new(),
3278 }
3279 }
3280 }
3281
3282 let (window_id, _) = cx.add_window(Default::default(), |cx| View::new(None, cx));
3283 let handle_1 = cx.add_view(window_id, |cx| View::new(None, cx));
3284 let handle_2 = cx.add_view(window_id, |cx| View::new(Some(handle_1.clone()), cx));
3285 assert_eq!(cx.cx.views.len(), 3);
3286
3287 handle_1.update(cx, |view, cx| {
3288 view.events.push("updated".into());
3289 cx.emit(1);
3290 cx.emit(2);
3291 });
3292 assert_eq!(handle_1.read(cx).events, vec!["updated".to_string()]);
3293 assert_eq!(
3294 handle_2.read(cx).events,
3295 vec![
3296 "observed event 1".to_string(),
3297 "observed event 2".to_string(),
3298 ]
3299 );
3300
3301 handle_2.update(cx, |view, _| {
3302 drop(handle_1);
3303 view.other.take();
3304 });
3305
3306 assert_eq!(cx.cx.views.len(), 2);
3307 assert!(cx.subscriptions.lock().is_empty());
3308 assert!(cx.observations.lock().is_empty());
3309 }
3310
3311 #[crate::test(self)]
3312 fn test_add_window(cx: &mut MutableAppContext) {
3313 struct View {
3314 mouse_down_count: Arc<AtomicUsize>,
3315 }
3316
3317 impl Entity for View {
3318 type Event = ();
3319 }
3320
3321 impl super::View for View {
3322 fn render<'a>(&self, _: &RenderContext<Self>) -> ElementBox {
3323 let mouse_down_count = self.mouse_down_count.clone();
3324 EventHandler::new(Empty::new().boxed())
3325 .on_mouse_down(move |_| {
3326 mouse_down_count.fetch_add(1, SeqCst);
3327 true
3328 })
3329 .boxed()
3330 }
3331
3332 fn ui_name() -> &'static str {
3333 "View"
3334 }
3335 }
3336
3337 let mouse_down_count = Arc::new(AtomicUsize::new(0));
3338 let (window_id, _) = cx.add_window(Default::default(), |_| View {
3339 mouse_down_count: mouse_down_count.clone(),
3340 });
3341 let presenter = cx.presenters_and_platform_windows[&window_id].0.clone();
3342 // Ensure window's root element is in a valid lifecycle state.
3343 presenter.borrow_mut().dispatch_event(
3344 Event::LeftMouseDown {
3345 position: Default::default(),
3346 cmd: false,
3347 },
3348 cx,
3349 );
3350 assert_eq!(mouse_down_count.load(SeqCst), 1);
3351 }
3352
3353 #[crate::test(self)]
3354 fn test_entity_release_hooks(cx: &mut MutableAppContext) {
3355 struct Model {
3356 released: Arc<Mutex<bool>>,
3357 }
3358
3359 struct View {
3360 released: Arc<Mutex<bool>>,
3361 }
3362
3363 impl Entity for Model {
3364 type Event = ();
3365
3366 fn release(&mut self, _: &mut MutableAppContext) {
3367 *self.released.lock() = true;
3368 }
3369 }
3370
3371 impl Entity for View {
3372 type Event = ();
3373
3374 fn release(&mut self, _: &mut MutableAppContext) {
3375 *self.released.lock() = true;
3376 }
3377 }
3378
3379 impl super::View for View {
3380 fn ui_name() -> &'static str {
3381 "View"
3382 }
3383
3384 fn render<'a>(&self, _: &RenderContext<Self>) -> ElementBox {
3385 Empty::new().boxed()
3386 }
3387 }
3388
3389 let model_released = Arc::new(Mutex::new(false));
3390 let view_released = Arc::new(Mutex::new(false));
3391
3392 let model = cx.add_model(|_| Model {
3393 released: model_released.clone(),
3394 });
3395
3396 let (window_id, _) = cx.add_window(Default::default(), |_| View {
3397 released: view_released.clone(),
3398 });
3399
3400 assert!(!*model_released.lock());
3401 assert!(!*view_released.lock());
3402
3403 cx.update(move || {
3404 drop(model);
3405 });
3406 assert!(*model_released.lock());
3407
3408 drop(cx.remove_window(window_id));
3409 assert!(*view_released.lock());
3410 }
3411
3412 #[crate::test(self)]
3413 fn test_subscribe_and_emit_from_view(cx: &mut MutableAppContext) {
3414 #[derive(Default)]
3415 struct View {
3416 events: Vec<usize>,
3417 }
3418
3419 impl Entity for View {
3420 type Event = usize;
3421 }
3422
3423 impl super::View for View {
3424 fn render<'a>(&self, _: &RenderContext<Self>) -> ElementBox {
3425 Empty::new().boxed()
3426 }
3427
3428 fn ui_name() -> &'static str {
3429 "View"
3430 }
3431 }
3432
3433 struct Model;
3434
3435 impl Entity for Model {
3436 type Event = usize;
3437 }
3438
3439 let (window_id, handle_1) = cx.add_window(Default::default(), |_| View::default());
3440 let handle_2 = cx.add_view(window_id, |_| View::default());
3441 let handle_2b = handle_2.clone();
3442 let handle_3 = cx.add_model(|_| Model);
3443
3444 handle_1.update(cx, |_, c| {
3445 c.subscribe(&handle_2, move |me, _, event, c| {
3446 me.events.push(*event);
3447
3448 c.subscribe(&handle_2b, |me, _, event, _| {
3449 me.events.push(*event * 2);
3450 })
3451 .detach();
3452 })
3453 .detach();
3454
3455 c.subscribe(&handle_3, |me, _, event, _| {
3456 me.events.push(*event);
3457 })
3458 .detach();
3459 });
3460
3461 handle_2.update(cx, |_, c| c.emit(7));
3462 assert_eq!(handle_1.read(cx).events, vec![7]);
3463
3464 handle_2.update(cx, |_, c| c.emit(5));
3465 assert_eq!(handle_1.read(cx).events, vec![7, 10, 5]);
3466
3467 handle_3.update(cx, |_, c| c.emit(9));
3468 assert_eq!(handle_1.read(cx).events, vec![7, 10, 5, 9]);
3469 }
3470
3471 #[crate::test(self)]
3472 fn test_dropping_subscribers(cx: &mut MutableAppContext) {
3473 struct View;
3474
3475 impl Entity for View {
3476 type Event = ();
3477 }
3478
3479 impl super::View for View {
3480 fn render<'a>(&self, _: &RenderContext<Self>) -> ElementBox {
3481 Empty::new().boxed()
3482 }
3483
3484 fn ui_name() -> &'static str {
3485 "View"
3486 }
3487 }
3488
3489 struct Model;
3490
3491 impl Entity for Model {
3492 type Event = ();
3493 }
3494
3495 let (window_id, _) = cx.add_window(Default::default(), |_| View);
3496 let observing_view = cx.add_view(window_id, |_| View);
3497 let emitting_view = cx.add_view(window_id, |_| View);
3498 let observing_model = cx.add_model(|_| Model);
3499 let observed_model = cx.add_model(|_| Model);
3500
3501 observing_view.update(cx, |_, cx| {
3502 cx.subscribe(&emitting_view, |_, _, _, _| {}).detach();
3503 cx.subscribe(&observed_model, |_, _, _, _| {}).detach();
3504 });
3505 observing_model.update(cx, |_, cx| {
3506 cx.subscribe(&observed_model, |_, _, _, _| {}).detach();
3507 });
3508
3509 cx.update(|| {
3510 drop(observing_view);
3511 drop(observing_model);
3512 });
3513
3514 emitting_view.update(cx, |_, cx| cx.emit(()));
3515 observed_model.update(cx, |_, cx| cx.emit(()));
3516 }
3517
3518 #[crate::test(self)]
3519 fn test_observe_and_notify_from_view(cx: &mut MutableAppContext) {
3520 #[derive(Default)]
3521 struct View {
3522 events: Vec<usize>,
3523 }
3524
3525 impl Entity for View {
3526 type Event = usize;
3527 }
3528
3529 impl super::View for View {
3530 fn render<'a>(&self, _: &RenderContext<Self>) -> ElementBox {
3531 Empty::new().boxed()
3532 }
3533
3534 fn ui_name() -> &'static str {
3535 "View"
3536 }
3537 }
3538
3539 #[derive(Default)]
3540 struct Model {
3541 count: usize,
3542 }
3543
3544 impl Entity for Model {
3545 type Event = ();
3546 }
3547
3548 let (_, view) = cx.add_window(Default::default(), |_| View::default());
3549 let model = cx.add_model(|_| Model::default());
3550
3551 view.update(cx, |_, c| {
3552 c.observe(&model, |me, observed, c| {
3553 me.events.push(observed.read(c).count)
3554 })
3555 .detach();
3556 });
3557
3558 model.update(cx, |model, c| {
3559 model.count = 11;
3560 c.notify();
3561 });
3562 assert_eq!(view.read(cx).events, vec![11]);
3563 }
3564
3565 #[crate::test(self)]
3566 fn test_dropping_observers(cx: &mut MutableAppContext) {
3567 struct View;
3568
3569 impl Entity for View {
3570 type Event = ();
3571 }
3572
3573 impl super::View for View {
3574 fn render<'a>(&self, _: &RenderContext<Self>) -> ElementBox {
3575 Empty::new().boxed()
3576 }
3577
3578 fn ui_name() -> &'static str {
3579 "View"
3580 }
3581 }
3582
3583 struct Model;
3584
3585 impl Entity for Model {
3586 type Event = ();
3587 }
3588
3589 let (window_id, _) = cx.add_window(Default::default(), |_| View);
3590 let observing_view = cx.add_view(window_id, |_| View);
3591 let observing_model = cx.add_model(|_| Model);
3592 let observed_model = cx.add_model(|_| Model);
3593
3594 observing_view.update(cx, |_, cx| {
3595 cx.observe(&observed_model, |_, _, _| {}).detach();
3596 });
3597 observing_model.update(cx, |_, cx| {
3598 cx.observe(&observed_model, |_, _, _| {}).detach();
3599 });
3600
3601 cx.update(|| {
3602 drop(observing_view);
3603 drop(observing_model);
3604 });
3605
3606 observed_model.update(cx, |_, cx| cx.notify());
3607 }
3608
3609 #[crate::test(self)]
3610 fn test_focus(cx: &mut MutableAppContext) {
3611 struct View {
3612 name: String,
3613 events: Arc<Mutex<Vec<String>>>,
3614 }
3615
3616 impl Entity for View {
3617 type Event = ();
3618 }
3619
3620 impl super::View for View {
3621 fn render<'a>(&self, _: &RenderContext<Self>) -> ElementBox {
3622 Empty::new().boxed()
3623 }
3624
3625 fn ui_name() -> &'static str {
3626 "View"
3627 }
3628
3629 fn on_focus(&mut self, _: &mut ViewContext<Self>) {
3630 self.events.lock().push(format!("{} focused", &self.name));
3631 }
3632
3633 fn on_blur(&mut self, _: &mut ViewContext<Self>) {
3634 self.events.lock().push(format!("{} blurred", &self.name));
3635 }
3636 }
3637
3638 let events: Arc<Mutex<Vec<String>>> = Default::default();
3639 let (window_id, view_1) = cx.add_window(Default::default(), |_| View {
3640 events: events.clone(),
3641 name: "view 1".to_string(),
3642 });
3643 let view_2 = cx.add_view(window_id, |_| View {
3644 events: events.clone(),
3645 name: "view 2".to_string(),
3646 });
3647
3648 view_1.update(cx, |_, cx| cx.focus(&view_2));
3649 view_1.update(cx, |_, cx| cx.focus(&view_1));
3650 view_1.update(cx, |_, cx| cx.focus(&view_2));
3651 view_1.update(cx, |_, _| drop(view_2));
3652
3653 assert_eq!(
3654 *events.lock(),
3655 [
3656 "view 1 focused".to_string(),
3657 "view 1 blurred".to_string(),
3658 "view 2 focused".to_string(),
3659 "view 2 blurred".to_string(),
3660 "view 1 focused".to_string(),
3661 "view 1 blurred".to_string(),
3662 "view 2 focused".to_string(),
3663 "view 1 focused".to_string(),
3664 ],
3665 );
3666 }
3667
3668 #[crate::test(self)]
3669 fn test_dispatch_action(cx: &mut MutableAppContext) {
3670 struct ViewA {
3671 id: usize,
3672 }
3673
3674 impl Entity for ViewA {
3675 type Event = ();
3676 }
3677
3678 impl View for ViewA {
3679 fn render<'a>(&self, _: &RenderContext<Self>) -> ElementBox {
3680 Empty::new().boxed()
3681 }
3682
3683 fn ui_name() -> &'static str {
3684 "View"
3685 }
3686 }
3687
3688 struct ViewB {
3689 id: usize,
3690 }
3691
3692 impl Entity for ViewB {
3693 type Event = ();
3694 }
3695
3696 impl View for ViewB {
3697 fn render<'a>(&self, _: &RenderContext<Self>) -> ElementBox {
3698 Empty::new().boxed()
3699 }
3700
3701 fn ui_name() -> &'static str {
3702 "View"
3703 }
3704 }
3705
3706 action!(Action, &'static str);
3707
3708 let actions = Rc::new(RefCell::new(Vec::new()));
3709
3710 let actions_clone = actions.clone();
3711 cx.add_global_action(move |_: &Action, _: &mut MutableAppContext| {
3712 actions_clone.borrow_mut().push("global a".to_string());
3713 });
3714
3715 let actions_clone = actions.clone();
3716 cx.add_global_action(move |_: &Action, _: &mut MutableAppContext| {
3717 actions_clone.borrow_mut().push("global b".to_string());
3718 });
3719
3720 let actions_clone = actions.clone();
3721 cx.add_action(move |view: &mut ViewA, action: &Action, cx| {
3722 assert_eq!(action.0, "bar");
3723 cx.propagate_action();
3724 actions_clone.borrow_mut().push(format!("{} a", view.id));
3725 });
3726
3727 let actions_clone = actions.clone();
3728 cx.add_action(move |view: &mut ViewA, _: &Action, cx| {
3729 if view.id != 1 {
3730 cx.propagate_action();
3731 }
3732 actions_clone.borrow_mut().push(format!("{} b", view.id));
3733 });
3734
3735 let actions_clone = actions.clone();
3736 cx.add_action(move |view: &mut ViewB, _: &Action, cx| {
3737 cx.propagate_action();
3738 actions_clone.borrow_mut().push(format!("{} c", view.id));
3739 });
3740
3741 let actions_clone = actions.clone();
3742 cx.add_action(move |view: &mut ViewB, _: &Action, cx| {
3743 cx.propagate_action();
3744 actions_clone.borrow_mut().push(format!("{} d", view.id));
3745 });
3746
3747 let (window_id, view_1) = cx.add_window(Default::default(), |_| ViewA { id: 1 });
3748 let view_2 = cx.add_view(window_id, |_| ViewB { id: 2 });
3749 let view_3 = cx.add_view(window_id, |_| ViewA { id: 3 });
3750 let view_4 = cx.add_view(window_id, |_| ViewB { id: 4 });
3751
3752 cx.dispatch_action(
3753 window_id,
3754 vec![view_1.id(), view_2.id(), view_3.id(), view_4.id()],
3755 &Action("bar"),
3756 );
3757
3758 assert_eq!(
3759 *actions.borrow(),
3760 vec!["4 d", "4 c", "3 b", "3 a", "2 d", "2 c", "1 b"]
3761 );
3762
3763 // Remove view_1, which doesn't propagate the action
3764 actions.borrow_mut().clear();
3765 cx.dispatch_action(
3766 window_id,
3767 vec![view_2.id(), view_3.id(), view_4.id()],
3768 &Action("bar"),
3769 );
3770
3771 assert_eq!(
3772 *actions.borrow(),
3773 vec!["4 d", "4 c", "3 b", "3 a", "2 d", "2 c", "global b", "global a"]
3774 );
3775 }
3776
3777 #[crate::test(self)]
3778 fn test_dispatch_keystroke(cx: &mut MutableAppContext) {
3779 use std::cell::Cell;
3780
3781 action!(Action, &'static str);
3782
3783 struct View {
3784 id: usize,
3785 keymap_context: keymap::Context,
3786 }
3787
3788 impl Entity for View {
3789 type Event = ();
3790 }
3791
3792 impl super::View for View {
3793 fn render<'a>(&self, _: &RenderContext<Self>) -> ElementBox {
3794 Empty::new().boxed()
3795 }
3796
3797 fn ui_name() -> &'static str {
3798 "View"
3799 }
3800
3801 fn keymap_context(&self, _: &AppContext) -> keymap::Context {
3802 self.keymap_context.clone()
3803 }
3804 }
3805
3806 impl View {
3807 fn new(id: usize) -> Self {
3808 View {
3809 id,
3810 keymap_context: keymap::Context::default(),
3811 }
3812 }
3813 }
3814
3815 let mut view_1 = View::new(1);
3816 let mut view_2 = View::new(2);
3817 let mut view_3 = View::new(3);
3818 view_1.keymap_context.set.insert("a".into());
3819 view_2.keymap_context.set.insert("b".into());
3820 view_3.keymap_context.set.insert("c".into());
3821
3822 let (window_id, view_1) = cx.add_window(Default::default(), |_| view_1);
3823 let view_2 = cx.add_view(window_id, |_| view_2);
3824 let view_3 = cx.add_view(window_id, |_| view_3);
3825
3826 // This keymap's only binding dispatches an action on view 2 because that view will have
3827 // "a" and "b" in its context, but not "c".
3828 cx.add_bindings(vec![keymap::Binding::new(
3829 "a",
3830 Action("a"),
3831 Some("a && b && !c"),
3832 )]);
3833
3834 let handled_action = Rc::new(Cell::new(false));
3835 let handled_action_clone = handled_action.clone();
3836 cx.add_action(move |view: &mut View, action: &Action, _| {
3837 handled_action_clone.set(true);
3838 assert_eq!(view.id, 2);
3839 assert_eq!(action.0, "a");
3840 });
3841
3842 cx.dispatch_keystroke(
3843 window_id,
3844 vec![view_1.id(), view_2.id(), view_3.id()],
3845 &Keystroke::parse("a").unwrap(),
3846 )
3847 .unwrap();
3848
3849 assert!(handled_action.get());
3850 }
3851
3852 #[crate::test(self)]
3853 async fn test_model_condition(mut cx: TestAppContext) {
3854 struct Counter(usize);
3855
3856 impl super::Entity for Counter {
3857 type Event = ();
3858 }
3859
3860 impl Counter {
3861 fn inc(&mut self, cx: &mut ModelContext<Self>) {
3862 self.0 += 1;
3863 cx.notify();
3864 }
3865 }
3866
3867 let model = cx.add_model(|_| Counter(0));
3868
3869 let condition1 = model.condition(&cx, |model, _| model.0 == 2);
3870 let condition2 = model.condition(&cx, |model, _| model.0 == 3);
3871 smol::pin!(condition1, condition2);
3872
3873 model.update(&mut cx, |model, cx| model.inc(cx));
3874 assert_eq!(poll_once(&mut condition1).await, None);
3875 assert_eq!(poll_once(&mut condition2).await, None);
3876
3877 model.update(&mut cx, |model, cx| model.inc(cx));
3878 assert_eq!(poll_once(&mut condition1).await, Some(()));
3879 assert_eq!(poll_once(&mut condition2).await, None);
3880
3881 model.update(&mut cx, |model, cx| model.inc(cx));
3882 assert_eq!(poll_once(&mut condition2).await, Some(()));
3883
3884 model.update(&mut cx, |_, cx| cx.notify());
3885 }
3886
3887 #[crate::test(self)]
3888 #[should_panic]
3889 async fn test_model_condition_timeout(mut cx: TestAppContext) {
3890 struct Model;
3891
3892 impl super::Entity for Model {
3893 type Event = ();
3894 }
3895
3896 let model = cx.add_model(|_| Model);
3897 model.condition(&cx, |_, _| false).await;
3898 }
3899
3900 #[crate::test(self)]
3901 #[should_panic(expected = "model dropped with pending condition")]
3902 async fn test_model_condition_panic_on_drop(mut cx: TestAppContext) {
3903 struct Model;
3904
3905 impl super::Entity for Model {
3906 type Event = ();
3907 }
3908
3909 let model = cx.add_model(|_| Model);
3910 let condition = model.condition(&cx, |_, _| false);
3911 cx.update(|_| drop(model));
3912 condition.await;
3913 }
3914
3915 #[crate::test(self)]
3916 async fn test_view_condition(mut cx: TestAppContext) {
3917 struct Counter(usize);
3918
3919 impl super::Entity for Counter {
3920 type Event = ();
3921 }
3922
3923 impl super::View for Counter {
3924 fn ui_name() -> &'static str {
3925 "test view"
3926 }
3927
3928 fn render(&self, _: &RenderContext<Self>) -> ElementBox {
3929 Empty::new().boxed()
3930 }
3931 }
3932
3933 impl Counter {
3934 fn inc(&mut self, cx: &mut ViewContext<Self>) {
3935 self.0 += 1;
3936 cx.notify();
3937 }
3938 }
3939
3940 let (_, view) = cx.add_window(|_| Counter(0));
3941
3942 let condition1 = view.condition(&cx, |view, _| view.0 == 2);
3943 let condition2 = view.condition(&cx, |view, _| view.0 == 3);
3944 smol::pin!(condition1, condition2);
3945
3946 view.update(&mut cx, |view, cx| view.inc(cx));
3947 assert_eq!(poll_once(&mut condition1).await, None);
3948 assert_eq!(poll_once(&mut condition2).await, None);
3949
3950 view.update(&mut cx, |view, cx| view.inc(cx));
3951 assert_eq!(poll_once(&mut condition1).await, Some(()));
3952 assert_eq!(poll_once(&mut condition2).await, None);
3953
3954 view.update(&mut cx, |view, cx| view.inc(cx));
3955 assert_eq!(poll_once(&mut condition2).await, Some(()));
3956 view.update(&mut cx, |_, cx| cx.notify());
3957 }
3958
3959 #[crate::test(self)]
3960 #[should_panic]
3961 async fn test_view_condition_timeout(mut cx: TestAppContext) {
3962 struct View;
3963
3964 impl super::Entity for View {
3965 type Event = ();
3966 }
3967
3968 impl super::View for View {
3969 fn ui_name() -> &'static str {
3970 "test view"
3971 }
3972
3973 fn render(&self, _: &RenderContext<Self>) -> ElementBox {
3974 Empty::new().boxed()
3975 }
3976 }
3977
3978 let (_, view) = cx.add_window(|_| View);
3979 view.condition(&cx, |_, _| false).await;
3980 }
3981
3982 #[crate::test(self)]
3983 #[should_panic(expected = "view dropped with pending condition")]
3984 async fn test_view_condition_panic_on_drop(mut cx: TestAppContext) {
3985 struct View;
3986
3987 impl super::Entity for View {
3988 type Event = ();
3989 }
3990
3991 impl super::View for View {
3992 fn ui_name() -> &'static str {
3993 "test view"
3994 }
3995
3996 fn render(&self, _: &RenderContext<Self>) -> ElementBox {
3997 Empty::new().boxed()
3998 }
3999 }
4000
4001 let window_id = cx.add_window(|_| View).0;
4002 let view = cx.add_view(window_id, |_| View);
4003
4004 let condition = view.condition(&cx, |_, _| false);
4005 cx.update(|_| drop(view));
4006 condition.await;
4007 }
4008}