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