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: Weak<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: Arc::downgrade(ref_counts),
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 if let Some(ref_counts) = self.ref_counts.upgrade() {
2149 ref_counts.lock().inc_entity(self.model_id);
2150 }
2151
2152 Self {
2153 model_id: self.model_id,
2154 model_type: PhantomData,
2155 ref_counts: self.ref_counts.clone(),
2156 }
2157 }
2158}
2159
2160impl<T> PartialEq for ModelHandle<T> {
2161 fn eq(&self, other: &Self) -> bool {
2162 self.model_id == other.model_id
2163 }
2164}
2165
2166impl<T> Eq for ModelHandle<T> {}
2167
2168impl<T> Hash for ModelHandle<T> {
2169 fn hash<H: Hasher>(&self, state: &mut H) {
2170 self.model_id.hash(state);
2171 }
2172}
2173
2174impl<T> std::borrow::Borrow<usize> for ModelHandle<T> {
2175 fn borrow(&self) -> &usize {
2176 &self.model_id
2177 }
2178}
2179
2180impl<T> Debug for ModelHandle<T> {
2181 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2182 f.debug_tuple(&format!("ModelHandle<{}>", type_name::<T>()))
2183 .field(&self.model_id)
2184 .finish()
2185 }
2186}
2187
2188unsafe impl<T> Send for ModelHandle<T> {}
2189unsafe impl<T> Sync for ModelHandle<T> {}
2190
2191impl<T> Drop for ModelHandle<T> {
2192 fn drop(&mut self) {
2193 if let Some(ref_counts) = self.ref_counts.upgrade() {
2194 ref_counts.lock().dec_model(self.model_id);
2195 }
2196 }
2197}
2198
2199impl<T> Handle<T> for ModelHandle<T> {
2200 fn id(&self) -> usize {
2201 self.model_id
2202 }
2203
2204 fn location(&self) -> EntityLocation {
2205 EntityLocation::Model(self.model_id)
2206 }
2207}
2208
2209pub struct WeakModelHandle<T> {
2210 model_id: usize,
2211 model_type: PhantomData<T>,
2212}
2213
2214impl<T: Entity> WeakModelHandle<T> {
2215 fn new(model_id: usize) -> Self {
2216 Self {
2217 model_id,
2218 model_type: PhantomData,
2219 }
2220 }
2221
2222 pub fn upgrade(&self, app: &AppContext) -> Option<ModelHandle<T>> {
2223 if app.models.contains_key(&self.model_id) {
2224 Some(ModelHandle::new(self.model_id, &app.ref_counts))
2225 } else {
2226 None
2227 }
2228 }
2229}
2230
2231impl<T> Clone for WeakModelHandle<T> {
2232 fn clone(&self) -> Self {
2233 Self {
2234 model_id: self.model_id,
2235 model_type: PhantomData,
2236 }
2237 }
2238}
2239
2240pub struct AnyModelHandle {
2241 model_id: usize,
2242 ref_counts: Weak<Mutex<RefCounts>>,
2243}
2244
2245impl<T: Entity> From<ModelHandle<T>> for AnyModelHandle {
2246 fn from(handle: ModelHandle<T>) -> Self {
2247 if let Some(ref_counts) = handle.ref_counts.upgrade() {
2248 ref_counts.lock().inc_entity(handle.model_id);
2249 }
2250 Self {
2251 model_id: handle.model_id,
2252 ref_counts: handle.ref_counts.clone(),
2253 }
2254 }
2255}
2256
2257impl Drop for AnyModelHandle {
2258 fn drop(&mut self) {
2259 if let Some(ref_counts) = self.ref_counts.upgrade() {
2260 ref_counts.lock().dec_model(self.model_id);
2261 }
2262 }
2263}
2264
2265pub struct ViewHandle<T> {
2266 window_id: usize,
2267 view_id: usize,
2268 view_type: PhantomData<T>,
2269 ref_counts: Weak<Mutex<RefCounts>>,
2270}
2271
2272impl<T: View> ViewHandle<T> {
2273 fn new(window_id: usize, view_id: usize, ref_counts: &Arc<Mutex<RefCounts>>) -> Self {
2274 ref_counts.lock().inc_entity(view_id);
2275 Self {
2276 window_id,
2277 view_id,
2278 view_type: PhantomData,
2279 ref_counts: Arc::downgrade(ref_counts),
2280 }
2281 }
2282
2283 pub fn downgrade(&self) -> WeakViewHandle<T> {
2284 WeakViewHandle::new(self.window_id, self.view_id)
2285 }
2286
2287 pub fn window_id(&self) -> usize {
2288 self.window_id
2289 }
2290
2291 pub fn id(&self) -> usize {
2292 self.view_id
2293 }
2294
2295 pub fn read<'a, A: ReadView>(&self, app: &'a A) -> &'a T {
2296 app.read_view(self)
2297 }
2298
2299 pub fn update<A, F, S>(&self, app: &mut A, update: F) -> S
2300 where
2301 A: UpdateView,
2302 F: FnOnce(&mut T, &mut ViewContext<T>) -> S,
2303 {
2304 app.update_view(self, update)
2305 }
2306
2307 pub fn is_focused(&self, app: &AppContext) -> bool {
2308 app.focused_view_id(self.window_id)
2309 .map_or(false, |focused_id| focused_id == self.view_id)
2310 }
2311
2312 pub fn condition(
2313 &self,
2314 ctx: &TestAppContext,
2315 mut predicate: impl 'static + FnMut(&T, &AppContext) -> bool,
2316 ) -> impl 'static + Future<Output = ()> {
2317 let mut ctx = ctx.0.borrow_mut();
2318 let tx = ctx
2319 .async_observations
2320 .entry(self.id())
2321 .or_insert_with(|| postage::broadcast::channel(128).0);
2322 let mut rx = tx.subscribe();
2323 let ctx = ctx.weak_self.as_ref().unwrap().upgrade().unwrap();
2324 let handle = self.downgrade();
2325
2326 async move {
2327 timeout(Duration::from_millis(200), async move {
2328 loop {
2329 {
2330 let ctx = ctx.borrow();
2331 let ctx = ctx.as_ref();
2332 if predicate(
2333 handle
2334 .upgrade(ctx)
2335 .expect("model dropped with pending condition")
2336 .read(ctx),
2337 ctx,
2338 ) {
2339 break;
2340 }
2341 }
2342
2343 rx.recv()
2344 .await
2345 .expect("model dropped with pending condition");
2346 }
2347 })
2348 .await
2349 .expect("condition timed out");
2350 }
2351 }
2352}
2353
2354impl<T> Clone for ViewHandle<T> {
2355 fn clone(&self) -> Self {
2356 if let Some(ref_counts) = self.ref_counts.upgrade() {
2357 ref_counts.lock().inc_entity(self.view_id);
2358 }
2359
2360 Self {
2361 window_id: self.window_id,
2362 view_id: self.view_id,
2363 view_type: PhantomData,
2364 ref_counts: self.ref_counts.clone(),
2365 }
2366 }
2367}
2368
2369impl<T> PartialEq for ViewHandle<T> {
2370 fn eq(&self, other: &Self) -> bool {
2371 self.window_id == other.window_id && self.view_id == other.view_id
2372 }
2373}
2374
2375impl<T> Eq for ViewHandle<T> {}
2376
2377impl<T> Debug for ViewHandle<T> {
2378 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2379 f.debug_struct(&format!("ViewHandle<{}>", type_name::<T>()))
2380 .field("window_id", &self.window_id)
2381 .field("view_id", &self.view_id)
2382 .finish()
2383 }
2384}
2385
2386impl<T> Drop for ViewHandle<T> {
2387 fn drop(&mut self) {
2388 if let Some(ref_counts) = self.ref_counts.upgrade() {
2389 ref_counts.lock().dec_view(self.window_id, self.view_id);
2390 }
2391 }
2392}
2393
2394impl<T> Handle<T> for ViewHandle<T> {
2395 fn id(&self) -> usize {
2396 self.view_id
2397 }
2398
2399 fn location(&self) -> EntityLocation {
2400 EntityLocation::View(self.window_id, self.view_id)
2401 }
2402}
2403
2404#[derive(Clone)]
2405pub struct AnyViewHandle {
2406 window_id: usize,
2407 view_id: usize,
2408 view_type: TypeId,
2409 ref_counts: Weak<Mutex<RefCounts>>,
2410}
2411
2412impl AnyViewHandle {
2413 pub fn id(&self) -> usize {
2414 self.view_id
2415 }
2416
2417 pub fn is<T: 'static>(&self) -> bool {
2418 TypeId::of::<T>() == self.view_type
2419 }
2420
2421 pub fn downcast<T: View>(self) -> Option<ViewHandle<T>> {
2422 if self.is::<T>() {
2423 if let Some(ref_counts) = self.ref_counts.upgrade() {
2424 return Some(ViewHandle::new(self.window_id, self.view_id, &ref_counts));
2425 }
2426 }
2427 None
2428 }
2429}
2430
2431impl<T: View> From<&ViewHandle<T>> for AnyViewHandle {
2432 fn from(handle: &ViewHandle<T>) -> Self {
2433 if let Some(ref_counts) = handle.ref_counts.upgrade() {
2434 ref_counts.lock().inc_entity(handle.view_id);
2435 }
2436 AnyViewHandle {
2437 window_id: handle.window_id,
2438 view_id: handle.view_id,
2439 view_type: TypeId::of::<T>(),
2440 ref_counts: handle.ref_counts.clone(),
2441 }
2442 }
2443}
2444
2445impl<T: View> From<ViewHandle<T>> for AnyViewHandle {
2446 fn from(handle: ViewHandle<T>) -> Self {
2447 (&handle).into()
2448 }
2449}
2450
2451impl Drop for AnyViewHandle {
2452 fn drop(&mut self) {
2453 if let Some(ref_counts) = self.ref_counts.upgrade() {
2454 ref_counts.lock().dec_view(self.window_id, self.view_id);
2455 }
2456 }
2457}
2458
2459pub struct WeakViewHandle<T> {
2460 window_id: usize,
2461 view_id: usize,
2462 view_type: PhantomData<T>,
2463}
2464
2465impl<T: View> WeakViewHandle<T> {
2466 fn new(window_id: usize, view_id: usize) -> Self {
2467 Self {
2468 window_id,
2469 view_id,
2470 view_type: PhantomData,
2471 }
2472 }
2473
2474 pub fn upgrade(&self, ctx: impl AsRef<AppContext>) -> Option<ViewHandle<T>> {
2475 let ctx = ctx.as_ref();
2476 if ctx.views.get(&(self.window_id, self.view_id)).is_some() {
2477 Some(ViewHandle::new(
2478 self.window_id,
2479 self.view_id,
2480 &ctx.ref_counts,
2481 ))
2482 } else {
2483 None
2484 }
2485 }
2486}
2487
2488impl<T> Clone for WeakViewHandle<T> {
2489 fn clone(&self) -> Self {
2490 Self {
2491 window_id: self.window_id,
2492 view_id: self.view_id,
2493 view_type: PhantomData,
2494 }
2495 }
2496}
2497
2498pub struct ValueHandle<T> {
2499 value_type: PhantomData<T>,
2500 tag_type_id: TypeId,
2501 id: usize,
2502 ref_counts: Weak<Mutex<RefCounts>>,
2503}
2504
2505impl<T: 'static> ValueHandle<T> {
2506 fn new(tag_type_id: TypeId, id: usize, ref_counts: &Arc<Mutex<RefCounts>>) -> Self {
2507 ref_counts.lock().inc_value(tag_type_id, id);
2508 Self {
2509 value_type: PhantomData,
2510 tag_type_id,
2511 id,
2512 ref_counts: Arc::downgrade(ref_counts),
2513 }
2514 }
2515
2516 pub fn read<R>(&self, ctx: &AppContext, f: impl FnOnce(&T) -> R) -> R {
2517 f(ctx
2518 .values
2519 .read()
2520 .get(&(self.tag_type_id, self.id))
2521 .unwrap()
2522 .downcast_ref()
2523 .unwrap())
2524 }
2525
2526 pub fn update<R>(&self, ctx: &AppContext, f: impl FnOnce(&mut T) -> R) -> R {
2527 f(ctx
2528 .values
2529 .write()
2530 .get_mut(&(self.tag_type_id, self.id))
2531 .unwrap()
2532 .downcast_mut()
2533 .unwrap())
2534 }
2535}
2536
2537impl<T> Drop for ValueHandle<T> {
2538 fn drop(&mut self) {
2539 if let Some(ref_counts) = self.ref_counts.upgrade() {
2540 ref_counts.lock().dec_value(self.tag_type_id, self.id);
2541 }
2542 }
2543}
2544
2545#[derive(Default)]
2546struct RefCounts {
2547 entity_counts: HashMap<usize, usize>,
2548 value_counts: HashMap<(TypeId, usize), usize>,
2549 dropped_models: HashSet<usize>,
2550 dropped_views: HashSet<(usize, usize)>,
2551 dropped_values: HashSet<(TypeId, usize)>,
2552}
2553
2554impl RefCounts {
2555 fn inc_entity(&mut self, model_id: usize) {
2556 *self.entity_counts.entry(model_id).or_insert(0) += 1;
2557 }
2558
2559 fn inc_value(&mut self, tag_type_id: TypeId, id: usize) {
2560 *self.value_counts.entry((tag_type_id, id)).or_insert(0) += 1;
2561 }
2562
2563 fn dec_model(&mut self, model_id: usize) {
2564 let count = self.entity_counts.get_mut(&model_id).unwrap();
2565 *count -= 1;
2566 if *count == 0 {
2567 self.entity_counts.remove(&model_id);
2568 self.dropped_models.insert(model_id);
2569 }
2570 }
2571
2572 fn dec_view(&mut self, window_id: usize, view_id: usize) {
2573 let count = self.entity_counts.get_mut(&view_id).unwrap();
2574 *count -= 1;
2575 if *count == 0 {
2576 self.entity_counts.remove(&view_id);
2577 self.dropped_views.insert((window_id, view_id));
2578 }
2579 }
2580
2581 fn dec_value(&mut self, tag_type_id: TypeId, id: usize) {
2582 let key = (tag_type_id, id);
2583 let count = self.value_counts.get_mut(&key).unwrap();
2584 *count -= 1;
2585 if *count == 0 {
2586 self.value_counts.remove(&key);
2587 self.dropped_values.insert(key);
2588 }
2589 }
2590
2591 fn take_dropped(
2592 &mut self,
2593 ) -> (
2594 HashSet<usize>,
2595 HashSet<(usize, usize)>,
2596 HashSet<(TypeId, usize)>,
2597 ) {
2598 let mut dropped_models = HashSet::new();
2599 let mut dropped_views = HashSet::new();
2600 let mut dropped_values = HashSet::new();
2601 std::mem::swap(&mut self.dropped_models, &mut dropped_models);
2602 std::mem::swap(&mut self.dropped_views, &mut dropped_views);
2603 std::mem::swap(&mut self.dropped_values, &mut dropped_values);
2604 (dropped_models, dropped_views, dropped_values)
2605 }
2606}
2607
2608enum Subscription {
2609 FromModel {
2610 model_id: usize,
2611 callback: Box<dyn FnMut(&mut dyn Any, &dyn Any, &mut MutableAppContext, usize)>,
2612 },
2613 FromView {
2614 window_id: usize,
2615 view_id: usize,
2616 callback: Box<dyn FnMut(&mut dyn Any, &dyn Any, &mut MutableAppContext, usize, usize)>,
2617 },
2618}
2619
2620enum ModelObservation {
2621 FromModel {
2622 model_id: usize,
2623 callback: Box<dyn FnMut(&mut dyn Any, usize, &mut MutableAppContext, usize)>,
2624 },
2625 FromView {
2626 window_id: usize,
2627 view_id: usize,
2628 callback: Box<dyn FnMut(&mut dyn Any, usize, &mut MutableAppContext, usize, usize)>,
2629 },
2630}
2631
2632struct ViewObservation {
2633 window_id: usize,
2634 view_id: usize,
2635 callback: Box<dyn FnMut(&mut dyn Any, usize, usize, &mut MutableAppContext, usize, usize)>,
2636}
2637
2638type FutureHandler = Box<dyn FnOnce(Box<dyn Any>, &mut MutableAppContext) -> Option<Box<dyn Any>>>;
2639
2640struct StreamHandler {
2641 item_callback: Box<dyn FnMut(Box<dyn Any>, &mut MutableAppContext) -> bool>,
2642 done_callback: Box<dyn FnOnce(&mut MutableAppContext) -> Option<Box<dyn Any>>>,
2643}
2644
2645#[must_use]
2646pub struct EntityTask<T> {
2647 id: usize,
2648 task: Option<executor::Task<Option<T>>>,
2649 _spawner: Spawner, // Keeps the spawning entity alive for as long as the task exists
2650 handler_map: TaskHandlerMap,
2651}
2652
2653pub enum Spawner {
2654 Model(AnyModelHandle),
2655 View(AnyViewHandle),
2656}
2657
2658enum TaskHandlerMap {
2659 Detached,
2660 Future(Rc<RefCell<HashMap<usize, FutureHandler>>>),
2661 Stream(Rc<RefCell<HashMap<usize, StreamHandler>>>),
2662}
2663
2664impl<T> EntityTask<T> {
2665 fn new(
2666 id: usize,
2667 task: executor::Task<Option<T>>,
2668 spawner: Spawner,
2669 handler_map: TaskHandlerMap,
2670 ) -> Self {
2671 Self {
2672 id,
2673 task: Some(task),
2674 _spawner: spawner,
2675 handler_map,
2676 }
2677 }
2678
2679 pub fn detach(mut self) {
2680 self.handler_map = TaskHandlerMap::Detached;
2681 self.task.take().unwrap().detach();
2682 }
2683
2684 pub async fn cancel(mut self) -> Option<T> {
2685 let task = self.task.take().unwrap();
2686 task.cancel().await.unwrap()
2687 }
2688}
2689
2690impl<T> Future for EntityTask<T> {
2691 type Output = T;
2692
2693 fn poll(
2694 self: std::pin::Pin<&mut Self>,
2695 ctx: &mut std::task::Context<'_>,
2696 ) -> std::task::Poll<Self::Output> {
2697 let task = unsafe { self.map_unchecked_mut(|task| task.task.as_mut().unwrap()) };
2698 task.poll(ctx).map(|output| output.unwrap())
2699 }
2700}
2701
2702impl<T> Drop for EntityTask<T> {
2703 fn drop(self: &mut Self) {
2704 match &self.handler_map {
2705 TaskHandlerMap::Detached => {
2706 return;
2707 }
2708 TaskHandlerMap::Future(map) => {
2709 map.borrow_mut().remove(&self.id);
2710 }
2711 TaskHandlerMap::Stream(map) => {
2712 map.borrow_mut().remove(&self.id);
2713 }
2714 }
2715 }
2716}
2717
2718#[cfg(test)]
2719mod tests {
2720 use super::*;
2721 use crate::elements::*;
2722 use smol::future::poll_once;
2723
2724 #[test]
2725 fn test_model_handles() {
2726 struct Model {
2727 other: Option<ModelHandle<Model>>,
2728 events: Vec<String>,
2729 }
2730
2731 impl Entity for Model {
2732 type Event = usize;
2733 }
2734
2735 impl Model {
2736 fn new(other: Option<ModelHandle<Self>>, ctx: &mut ModelContext<Self>) -> Self {
2737 if let Some(other) = other.as_ref() {
2738 ctx.observe(other, |me, _, _| {
2739 me.events.push("notified".into());
2740 });
2741 ctx.subscribe(other, |me, event, _| {
2742 me.events.push(format!("observed event {}", event));
2743 });
2744 }
2745
2746 Self {
2747 other,
2748 events: Vec::new(),
2749 }
2750 }
2751 }
2752
2753 App::test((), |app| {
2754 let handle_1 = app.add_model(|ctx| Model::new(None, ctx));
2755 let handle_2 = app.add_model(|ctx| Model::new(Some(handle_1.clone()), ctx));
2756 assert_eq!(app.ctx.models.len(), 2);
2757
2758 handle_1.update(app, |model, ctx| {
2759 model.events.push("updated".into());
2760 ctx.emit(1);
2761 ctx.notify();
2762 ctx.emit(2);
2763 });
2764 assert_eq!(handle_1.read(app).events, vec!["updated".to_string()]);
2765 assert_eq!(
2766 handle_2.read(app).events,
2767 vec![
2768 "observed event 1".to_string(),
2769 "notified".to_string(),
2770 "observed event 2".to_string(),
2771 ]
2772 );
2773
2774 handle_2.update(app, |model, _| {
2775 drop(handle_1);
2776 model.other.take();
2777 });
2778
2779 assert_eq!(app.ctx.models.len(), 1);
2780 assert!(app.subscriptions.is_empty());
2781 assert!(app.model_observations.is_empty());
2782 });
2783 }
2784
2785 #[test]
2786 fn test_subscribe_and_emit_from_model() {
2787 #[derive(Default)]
2788 struct Model {
2789 events: Vec<usize>,
2790 }
2791
2792 impl Entity for Model {
2793 type Event = usize;
2794 }
2795
2796 App::test((), |app| {
2797 let handle_1 = app.add_model(|_| Model::default());
2798 let handle_2 = app.add_model(|_| Model::default());
2799 let handle_2b = handle_2.clone();
2800
2801 handle_1.update(app, |_, c| {
2802 c.subscribe(&handle_2, move |model: &mut Model, event, c| {
2803 model.events.push(*event);
2804
2805 c.subscribe(&handle_2b, |model, event, _| {
2806 model.events.push(*event * 2);
2807 });
2808 });
2809 });
2810
2811 handle_2.update(app, |_, c| c.emit(7));
2812 assert_eq!(handle_1.read(app).events, vec![7]);
2813
2814 handle_2.update(app, |_, c| c.emit(5));
2815 assert_eq!(handle_1.read(app).events, vec![7, 10, 5]);
2816 })
2817 }
2818
2819 #[test]
2820 fn test_observe_and_notify_from_model() {
2821 #[derive(Default)]
2822 struct Model {
2823 count: usize,
2824 events: Vec<usize>,
2825 }
2826
2827 impl Entity for Model {
2828 type Event = ();
2829 }
2830
2831 App::test((), |app| {
2832 let handle_1 = app.add_model(|_| Model::default());
2833 let handle_2 = app.add_model(|_| Model::default());
2834 let handle_2b = handle_2.clone();
2835
2836 handle_1.update(app, |_, c| {
2837 c.observe(&handle_2, move |model, observed, c| {
2838 model.events.push(observed.read(c).count);
2839 c.observe(&handle_2b, |model, observed, c| {
2840 model.events.push(observed.read(c).count * 2);
2841 });
2842 });
2843 });
2844
2845 handle_2.update(app, |model, c| {
2846 model.count = 7;
2847 c.notify()
2848 });
2849 assert_eq!(handle_1.read(app).events, vec![7]);
2850
2851 handle_2.update(app, |model, c| {
2852 model.count = 5;
2853 c.notify()
2854 });
2855 assert_eq!(handle_1.read(app).events, vec![7, 10, 5])
2856 })
2857 }
2858
2859 #[test]
2860 fn test_spawn_from_model() {
2861 #[derive(Default)]
2862 struct Model {
2863 count: usize,
2864 }
2865
2866 impl Entity for Model {
2867 type Event = ();
2868 }
2869
2870 App::test_async((), |mut app| async move {
2871 let handle = app.add_model(|_| Model::default());
2872 handle
2873 .update(&mut app, |_, c| {
2874 c.spawn(async { 7 }, |model, output, _| {
2875 model.count = output;
2876 })
2877 })
2878 .await;
2879 app.read(|ctx| assert_eq!(handle.read(ctx).count, 7));
2880
2881 handle
2882 .update(&mut app, |_, c| {
2883 c.spawn(async { 14 }, |model, output, _| {
2884 model.count = output;
2885 })
2886 })
2887 .await;
2888 app.read(|ctx| assert_eq!(handle.read(ctx).count, 14));
2889 });
2890 }
2891
2892 #[test]
2893 fn test_spawn_stream_local_from_model() {
2894 #[derive(Default)]
2895 struct Model {
2896 events: Vec<Option<usize>>,
2897 }
2898
2899 impl Entity for Model {
2900 type Event = ();
2901 }
2902
2903 App::test_async((), |mut app| async move {
2904 let handle = app.add_model(|_| Model::default());
2905 handle
2906 .update(&mut app, |_, c| {
2907 c.spawn_stream(
2908 smol::stream::iter(vec![1, 2, 3]),
2909 |model, output, _| {
2910 model.events.push(Some(output));
2911 },
2912 |model, _| {
2913 model.events.push(None);
2914 },
2915 )
2916 })
2917 .await;
2918 app.read(|ctx| assert_eq!(handle.read(ctx).events, [Some(1), Some(2), Some(3), None]));
2919 })
2920 }
2921
2922 #[test]
2923 fn test_view_handles() {
2924 struct View {
2925 other: Option<ViewHandle<View>>,
2926 events: Vec<String>,
2927 }
2928
2929 impl Entity for View {
2930 type Event = usize;
2931 }
2932
2933 impl super::View for View {
2934 fn render<'a>(&self, _: &AppContext) -> ElementBox {
2935 Empty::new().boxed()
2936 }
2937
2938 fn ui_name() -> &'static str {
2939 "View"
2940 }
2941 }
2942
2943 impl View {
2944 fn new(other: Option<ViewHandle<View>>, ctx: &mut ViewContext<Self>) -> Self {
2945 if let Some(other) = other.as_ref() {
2946 ctx.subscribe_to_view(other, |me, _, event, _| {
2947 me.events.push(format!("observed event {}", event));
2948 });
2949 }
2950 Self {
2951 other,
2952 events: Vec::new(),
2953 }
2954 }
2955 }
2956
2957 App::test((), |app| {
2958 let (window_id, _) = app.add_window(|ctx| View::new(None, ctx));
2959 let handle_1 = app.add_view(window_id, |ctx| View::new(None, ctx));
2960 let handle_2 = app.add_view(window_id, |ctx| View::new(Some(handle_1.clone()), ctx));
2961 assert_eq!(app.ctx.views.len(), 3);
2962
2963 handle_1.update(app, |view, ctx| {
2964 view.events.push("updated".into());
2965 ctx.emit(1);
2966 ctx.emit(2);
2967 });
2968 assert_eq!(handle_1.read(app).events, vec!["updated".to_string()]);
2969 assert_eq!(
2970 handle_2.read(app).events,
2971 vec![
2972 "observed event 1".to_string(),
2973 "observed event 2".to_string(),
2974 ]
2975 );
2976
2977 handle_2.update(app, |view, _| {
2978 drop(handle_1);
2979 view.other.take();
2980 });
2981
2982 assert_eq!(app.ctx.views.len(), 2);
2983 assert!(app.subscriptions.is_empty());
2984 assert!(app.model_observations.is_empty());
2985 })
2986 }
2987
2988 #[test]
2989 fn test_subscribe_and_emit_from_view() {
2990 #[derive(Default)]
2991 struct View {
2992 events: Vec<usize>,
2993 }
2994
2995 impl Entity for View {
2996 type Event = usize;
2997 }
2998
2999 impl super::View for View {
3000 fn render<'a>(&self, _: &AppContext) -> ElementBox {
3001 Empty::new().boxed()
3002 }
3003
3004 fn ui_name() -> &'static str {
3005 "View"
3006 }
3007 }
3008
3009 struct Model;
3010
3011 impl Entity for Model {
3012 type Event = usize;
3013 }
3014
3015 App::test((), |app| {
3016 let (window_id, handle_1) = app.add_window(|_| View::default());
3017 let handle_2 = app.add_view(window_id, |_| View::default());
3018 let handle_2b = handle_2.clone();
3019 let handle_3 = app.add_model(|_| Model);
3020
3021 handle_1.update(app, |_, c| {
3022 c.subscribe_to_view(&handle_2, move |me, _, event, c| {
3023 me.events.push(*event);
3024
3025 c.subscribe_to_view(&handle_2b, |me, _, event, _| {
3026 me.events.push(*event * 2);
3027 });
3028 });
3029
3030 c.subscribe_to_model(&handle_3, |me, _, event, _| {
3031 me.events.push(*event);
3032 })
3033 });
3034
3035 handle_2.update(app, |_, c| c.emit(7));
3036 assert_eq!(handle_1.read(app).events, vec![7]);
3037
3038 handle_2.update(app, |_, c| c.emit(5));
3039 assert_eq!(handle_1.read(app).events, vec![7, 10, 5]);
3040
3041 handle_3.update(app, |_, c| c.emit(9));
3042 assert_eq!(handle_1.read(app).events, vec![7, 10, 5, 9]);
3043 })
3044 }
3045
3046 #[test]
3047 fn test_dropping_subscribers() {
3048 struct View;
3049
3050 impl Entity for View {
3051 type Event = ();
3052 }
3053
3054 impl super::View for View {
3055 fn render<'a>(&self, _: &AppContext) -> ElementBox {
3056 Empty::new().boxed()
3057 }
3058
3059 fn ui_name() -> &'static str {
3060 "View"
3061 }
3062 }
3063
3064 struct Model;
3065
3066 impl Entity for Model {
3067 type Event = ();
3068 }
3069
3070 App::test((), |app| {
3071 let (window_id, _) = app.add_window(|_| View);
3072 let observing_view = app.add_view(window_id, |_| View);
3073 let emitting_view = app.add_view(window_id, |_| View);
3074 let observing_model = app.add_model(|_| Model);
3075 let observed_model = app.add_model(|_| Model);
3076
3077 observing_view.update(app, |_, ctx| {
3078 ctx.subscribe_to_view(&emitting_view, |_, _, _, _| {});
3079 ctx.subscribe_to_model(&observed_model, |_, _, _, _| {});
3080 });
3081 observing_model.update(app, |_, ctx| {
3082 ctx.subscribe(&observed_model, |_, _, _| {});
3083 });
3084
3085 app.update(|| {
3086 drop(observing_view);
3087 drop(observing_model);
3088 });
3089
3090 emitting_view.update(app, |_, ctx| ctx.emit(()));
3091 observed_model.update(app, |_, ctx| ctx.emit(()));
3092 })
3093 }
3094
3095 #[test]
3096 fn test_observe_and_notify_from_view() {
3097 #[derive(Default)]
3098 struct View {
3099 events: Vec<usize>,
3100 }
3101
3102 impl Entity for View {
3103 type Event = usize;
3104 }
3105
3106 impl super::View for View {
3107 fn render<'a>(&self, _: &AppContext) -> ElementBox {
3108 Empty::new().boxed()
3109 }
3110
3111 fn ui_name() -> &'static str {
3112 "View"
3113 }
3114 }
3115
3116 #[derive(Default)]
3117 struct Model {
3118 count: usize,
3119 }
3120
3121 impl Entity for Model {
3122 type Event = ();
3123 }
3124
3125 App::test((), |app| {
3126 let (_, view) = app.add_window(|_| View::default());
3127 let model = app.add_model(|_| Model::default());
3128
3129 view.update(app, |_, c| {
3130 c.observe_model(&model, |me, observed, c| {
3131 me.events.push(observed.read(c).count)
3132 });
3133 });
3134
3135 model.update(app, |model, c| {
3136 model.count = 11;
3137 c.notify();
3138 });
3139 assert_eq!(view.read(app).events, vec![11]);
3140 })
3141 }
3142
3143 #[test]
3144 fn test_dropping_observers() {
3145 struct View;
3146
3147 impl Entity for View {
3148 type Event = ();
3149 }
3150
3151 impl super::View for View {
3152 fn render<'a>(&self, _: &AppContext) -> ElementBox {
3153 Empty::new().boxed()
3154 }
3155
3156 fn ui_name() -> &'static str {
3157 "View"
3158 }
3159 }
3160
3161 struct Model;
3162
3163 impl Entity for Model {
3164 type Event = ();
3165 }
3166
3167 App::test((), |app| {
3168 let (window_id, _) = app.add_window(|_| View);
3169 let observing_view = app.add_view(window_id, |_| View);
3170 let observing_model = app.add_model(|_| Model);
3171 let observed_model = app.add_model(|_| Model);
3172
3173 observing_view.update(app, |_, ctx| {
3174 ctx.observe_model(&observed_model, |_, _, _| {});
3175 });
3176 observing_model.update(app, |_, ctx| {
3177 ctx.observe(&observed_model, |_, _, _| {});
3178 });
3179
3180 app.update(|| {
3181 drop(observing_view);
3182 drop(observing_model);
3183 });
3184
3185 observed_model.update(app, |_, ctx| ctx.notify());
3186 })
3187 }
3188
3189 #[test]
3190 fn test_focus() {
3191 struct View {
3192 name: String,
3193 events: Arc<Mutex<Vec<String>>>,
3194 }
3195
3196 impl Entity for View {
3197 type Event = ();
3198 }
3199
3200 impl super::View for View {
3201 fn render<'a>(&self, _: &AppContext) -> ElementBox {
3202 Empty::new().boxed()
3203 }
3204
3205 fn ui_name() -> &'static str {
3206 "View"
3207 }
3208
3209 fn on_focus(&mut self, _: &mut ViewContext<Self>) {
3210 self.events.lock().push(format!("{} focused", &self.name));
3211 }
3212
3213 fn on_blur(&mut self, _: &mut ViewContext<Self>) {
3214 self.events.lock().push(format!("{} blurred", &self.name));
3215 }
3216 }
3217
3218 App::test((), |app| {
3219 let events: Arc<Mutex<Vec<String>>> = Default::default();
3220 let (window_id, view_1) = app.add_window(|_| View {
3221 events: events.clone(),
3222 name: "view 1".to_string(),
3223 });
3224 let view_2 = app.add_view(window_id, |_| View {
3225 events: events.clone(),
3226 name: "view 2".to_string(),
3227 });
3228
3229 view_1.update(app, |_, ctx| ctx.focus(&view_2));
3230 view_1.update(app, |_, ctx| ctx.focus(&view_1));
3231 view_1.update(app, |_, ctx| ctx.focus(&view_2));
3232 view_1.update(app, |_, _| drop(view_2));
3233
3234 assert_eq!(
3235 *events.lock(),
3236 [
3237 "view 1 focused".to_string(),
3238 "view 1 blurred".to_string(),
3239 "view 2 focused".to_string(),
3240 "view 2 blurred".to_string(),
3241 "view 1 focused".to_string(),
3242 "view 1 blurred".to_string(),
3243 "view 2 focused".to_string(),
3244 "view 1 focused".to_string(),
3245 ],
3246 );
3247 })
3248 }
3249
3250 #[test]
3251 fn test_spawn_from_view() {
3252 #[derive(Default)]
3253 struct View {
3254 count: usize,
3255 }
3256
3257 impl Entity for View {
3258 type Event = ();
3259 }
3260
3261 impl super::View for View {
3262 fn render<'a>(&self, _: &AppContext) -> ElementBox {
3263 Empty::new().boxed()
3264 }
3265
3266 fn ui_name() -> &'static str {
3267 "View"
3268 }
3269 }
3270
3271 App::test_async((), |mut app| async move {
3272 let handle = app.add_window(|_| View::default()).1;
3273 handle
3274 .update(&mut app, |_, c| {
3275 c.spawn(async { 7 }, |me, output, _| {
3276 me.count = output;
3277 })
3278 })
3279 .await;
3280 app.read(|ctx| assert_eq!(handle.read(ctx).count, 7));
3281 handle
3282 .update(&mut app, |_, c| {
3283 c.spawn(async { 14 }, |me, output, _| {
3284 me.count = output;
3285 })
3286 })
3287 .await;
3288 app.read(|ctx| assert_eq!(handle.read(ctx).count, 14));
3289 });
3290 }
3291
3292 #[test]
3293 fn test_spawn_stream_local_from_view() {
3294 #[derive(Default)]
3295 struct View {
3296 events: Vec<Option<usize>>,
3297 }
3298
3299 impl Entity for View {
3300 type Event = ();
3301 }
3302
3303 impl super::View for View {
3304 fn render<'a>(&self, _: &AppContext) -> ElementBox {
3305 Empty::new().boxed()
3306 }
3307
3308 fn ui_name() -> &'static str {
3309 "View"
3310 }
3311 }
3312
3313 App::test_async((), |mut app| async move {
3314 let (_, handle) = app.add_window(|_| View::default());
3315 handle
3316 .update(&mut app, |_, c| {
3317 c.spawn_stream(
3318 smol::stream::iter(vec![1_usize, 2, 3]),
3319 |me, output, _| {
3320 me.events.push(Some(output));
3321 },
3322 |me, _| {
3323 me.events.push(None);
3324 },
3325 )
3326 })
3327 .await;
3328
3329 app.read(|ctx| assert_eq!(handle.read(ctx).events, [Some(1), Some(2), Some(3), None]))
3330 });
3331 }
3332
3333 #[test]
3334 fn test_dispatch_action() {
3335 struct ViewA {
3336 id: usize,
3337 }
3338
3339 impl Entity for ViewA {
3340 type Event = ();
3341 }
3342
3343 impl View for ViewA {
3344 fn render<'a>(&self, _: &AppContext) -> ElementBox {
3345 Empty::new().boxed()
3346 }
3347
3348 fn ui_name() -> &'static str {
3349 "View"
3350 }
3351 }
3352
3353 struct ViewB {
3354 id: usize,
3355 }
3356
3357 impl Entity for ViewB {
3358 type Event = ();
3359 }
3360
3361 impl View for ViewB {
3362 fn render<'a>(&self, _: &AppContext) -> ElementBox {
3363 Empty::new().boxed()
3364 }
3365
3366 fn ui_name() -> &'static str {
3367 "View"
3368 }
3369 }
3370
3371 struct ActionArg {
3372 foo: String,
3373 }
3374
3375 App::test((), |app| {
3376 let actions = Rc::new(RefCell::new(Vec::new()));
3377
3378 let actions_clone = actions.clone();
3379 app.add_global_action("action", move |_: &ActionArg, _: &mut MutableAppContext| {
3380 actions_clone.borrow_mut().push("global a".to_string());
3381 });
3382
3383 let actions_clone = actions.clone();
3384 app.add_global_action("action", move |_: &ActionArg, _: &mut MutableAppContext| {
3385 actions_clone.borrow_mut().push("global b".to_string());
3386 });
3387
3388 let actions_clone = actions.clone();
3389 app.add_action("action", move |view: &mut ViewA, arg: &ActionArg, ctx| {
3390 assert_eq!(arg.foo, "bar");
3391 ctx.propagate_action();
3392 actions_clone.borrow_mut().push(format!("{} a", view.id));
3393 });
3394
3395 let actions_clone = actions.clone();
3396 app.add_action("action", move |view: &mut ViewA, _: &ActionArg, ctx| {
3397 if view.id != 1 {
3398 ctx.propagate_action();
3399 }
3400 actions_clone.borrow_mut().push(format!("{} b", view.id));
3401 });
3402
3403 let actions_clone = actions.clone();
3404 app.add_action("action", move |view: &mut ViewB, _: &ActionArg, ctx| {
3405 ctx.propagate_action();
3406 actions_clone.borrow_mut().push(format!("{} c", view.id));
3407 });
3408
3409 let actions_clone = actions.clone();
3410 app.add_action("action", move |view: &mut ViewB, _: &ActionArg, ctx| {
3411 ctx.propagate_action();
3412 actions_clone.borrow_mut().push(format!("{} d", view.id));
3413 });
3414
3415 let (window_id, view_1) = app.add_window(|_| ViewA { id: 1 });
3416 let view_2 = app.add_view(window_id, |_| ViewB { id: 2 });
3417 let view_3 = app.add_view(window_id, |_| ViewA { id: 3 });
3418 let view_4 = app.add_view(window_id, |_| ViewB { id: 4 });
3419
3420 app.dispatch_action(
3421 window_id,
3422 vec![view_1.id(), view_2.id(), view_3.id(), view_4.id()],
3423 "action",
3424 ActionArg { foo: "bar".into() },
3425 );
3426
3427 assert_eq!(
3428 *actions.borrow(),
3429 vec!["4 d", "4 c", "3 b", "3 a", "2 d", "2 c", "1 b"]
3430 );
3431
3432 // Remove view_1, which doesn't propagate the action
3433 actions.borrow_mut().clear();
3434 app.dispatch_action(
3435 window_id,
3436 vec![view_2.id(), view_3.id(), view_4.id()],
3437 "action",
3438 ActionArg { foo: "bar".into() },
3439 );
3440
3441 assert_eq!(
3442 *actions.borrow(),
3443 vec!["4 d", "4 c", "3 b", "3 a", "2 d", "2 c", "global b", "global a"]
3444 );
3445 })
3446 }
3447
3448 #[test]
3449 fn test_dispatch_keystroke() {
3450 use std::cell::Cell;
3451
3452 #[derive(Clone)]
3453 struct ActionArg {
3454 key: String,
3455 }
3456
3457 struct View {
3458 id: usize,
3459 keymap_context: keymap::Context,
3460 }
3461
3462 impl Entity for View {
3463 type Event = ();
3464 }
3465
3466 impl super::View for View {
3467 fn render<'a>(&self, _: &AppContext) -> ElementBox {
3468 Empty::new().boxed()
3469 }
3470
3471 fn ui_name() -> &'static str {
3472 "View"
3473 }
3474
3475 fn keymap_context(&self, _: &AppContext) -> keymap::Context {
3476 self.keymap_context.clone()
3477 }
3478 }
3479
3480 impl View {
3481 fn new(id: usize) -> Self {
3482 View {
3483 id,
3484 keymap_context: keymap::Context::default(),
3485 }
3486 }
3487 }
3488
3489 App::test((), |app| {
3490 let mut view_1 = View::new(1);
3491 let mut view_2 = View::new(2);
3492 let mut view_3 = View::new(3);
3493 view_1.keymap_context.set.insert("a".into());
3494 view_2.keymap_context.set.insert("b".into());
3495 view_3.keymap_context.set.insert("c".into());
3496
3497 let (window_id, view_1) = app.add_window(|_| view_1);
3498 let view_2 = app.add_view(window_id, |_| view_2);
3499 let view_3 = app.add_view(window_id, |_| view_3);
3500
3501 // This keymap's only binding dispatches an action on view 2 because that view will have
3502 // "a" and "b" in its context, but not "c".
3503 let binding = keymap::Binding::new("a", "action", Some("a && b && !c"))
3504 .with_arg(ActionArg { key: "a".into() });
3505 app.add_bindings(vec![binding]);
3506
3507 let handled_action = Rc::new(Cell::new(false));
3508 let handled_action_clone = handled_action.clone();
3509 app.add_action("action", move |view: &mut View, arg: &ActionArg, _ctx| {
3510 handled_action_clone.set(true);
3511 assert_eq!(view.id, 2);
3512 assert_eq!(arg.key, "a");
3513 });
3514
3515 app.dispatch_keystroke(
3516 window_id,
3517 vec![view_1.id(), view_2.id(), view_3.id()],
3518 &Keystroke::parse("a").unwrap(),
3519 )
3520 .unwrap();
3521
3522 assert!(handled_action.get());
3523 });
3524 }
3525
3526 #[test]
3527 fn test_model_condition() {
3528 struct Counter(usize);
3529
3530 impl super::Entity for Counter {
3531 type Event = ();
3532 }
3533
3534 impl Counter {
3535 fn inc(&mut self, ctx: &mut ModelContext<Self>) {
3536 self.0 += 1;
3537 ctx.notify();
3538 }
3539 }
3540
3541 App::test_async((), |mut app| async move {
3542 let model = app.add_model(|_| Counter(0));
3543
3544 let condition1 = model.condition(&app, |model, _| model.0 == 2);
3545 let condition2 = model.condition(&app, |model, _| model.0 == 3);
3546 smol::pin!(condition1, condition2);
3547
3548 model.update(&mut app, |model, ctx| model.inc(ctx));
3549 assert_eq!(poll_once(&mut condition1).await, None);
3550 assert_eq!(poll_once(&mut condition2).await, None);
3551
3552 model.update(&mut app, |model, ctx| model.inc(ctx));
3553 assert_eq!(poll_once(&mut condition1).await, Some(()));
3554 assert_eq!(poll_once(&mut condition2).await, None);
3555
3556 model.update(&mut app, |model, ctx| model.inc(ctx));
3557 assert_eq!(poll_once(&mut condition2).await, Some(()));
3558
3559 // Broadcast channel should be removed if no conditions remain on next notification.
3560 model.update(&mut app, |_, ctx| ctx.notify());
3561 app.update(|ctx| assert!(ctx.async_observations.get(&model.id()).is_none()));
3562 });
3563 }
3564
3565 #[test]
3566 #[should_panic]
3567 fn test_model_condition_timeout() {
3568 struct Model;
3569
3570 impl super::Entity for Model {
3571 type Event = ();
3572 }
3573
3574 App::test_async((), |mut app| async move {
3575 let model = app.add_model(|_| Model);
3576 model.condition(&app, |_, _| false).await;
3577 });
3578 }
3579
3580 #[test]
3581 #[should_panic(expected = "model dropped with pending condition")]
3582 fn test_model_condition_panic_on_drop() {
3583 struct Model;
3584
3585 impl super::Entity for Model {
3586 type Event = ();
3587 }
3588
3589 App::test_async((), |mut app| async move {
3590 let model = app.add_model(|_| Model);
3591 let condition = model.condition(&app, |_, _| false);
3592 app.update(|_| drop(model));
3593 condition.await;
3594 });
3595 }
3596
3597 #[test]
3598 fn test_view_condition() {
3599 struct Counter(usize);
3600
3601 impl super::Entity for Counter {
3602 type Event = ();
3603 }
3604
3605 impl super::View for Counter {
3606 fn ui_name() -> &'static str {
3607 "test view"
3608 }
3609
3610 fn render(&self, _: &AppContext) -> ElementBox {
3611 Empty::new().boxed()
3612 }
3613 }
3614
3615 impl Counter {
3616 fn inc(&mut self, ctx: &mut ViewContext<Self>) {
3617 self.0 += 1;
3618 ctx.notify();
3619 }
3620 }
3621
3622 App::test_async((), |mut app| async move {
3623 let (_, view) = app.add_window(|_| Counter(0));
3624
3625 let condition1 = view.condition(&app, |view, _| view.0 == 2);
3626 let condition2 = view.condition(&app, |view, _| view.0 == 3);
3627 smol::pin!(condition1, condition2);
3628
3629 view.update(&mut app, |view, ctx| view.inc(ctx));
3630 assert_eq!(poll_once(&mut condition1).await, None);
3631 assert_eq!(poll_once(&mut condition2).await, None);
3632
3633 view.update(&mut app, |view, ctx| view.inc(ctx));
3634 assert_eq!(poll_once(&mut condition1).await, Some(()));
3635 assert_eq!(poll_once(&mut condition2).await, None);
3636
3637 view.update(&mut app, |view, ctx| view.inc(ctx));
3638 assert_eq!(poll_once(&mut condition2).await, Some(()));
3639
3640 // Broadcast channel should be removed if no conditions remain on next notification.
3641 view.update(&mut app, |_, ctx| ctx.notify());
3642 app.update(|ctx| assert!(ctx.async_observations.get(&view.id()).is_none()));
3643 });
3644 }
3645
3646 #[test]
3647 #[should_panic]
3648 fn test_view_condition_timeout() {
3649 struct View;
3650
3651 impl super::Entity for View {
3652 type Event = ();
3653 }
3654
3655 impl super::View for View {
3656 fn ui_name() -> &'static str {
3657 "test view"
3658 }
3659
3660 fn render(&self, _: &AppContext) -> ElementBox {
3661 Empty::new().boxed()
3662 }
3663 }
3664
3665 App::test_async((), |mut app| async move {
3666 let (_, view) = app.add_window(|_| View);
3667 view.condition(&app, |_, _| false).await;
3668 });
3669 }
3670
3671 #[test]
3672 #[should_panic(expected = "model dropped with pending condition")]
3673 fn test_view_condition_panic_on_drop() {
3674 struct View;
3675
3676 impl super::Entity for View {
3677 type Event = ();
3678 }
3679
3680 impl super::View for View {
3681 fn ui_name() -> &'static str {
3682 "test view"
3683 }
3684
3685 fn render(&self, _: &AppContext) -> ElementBox {
3686 Empty::new().boxed()
3687 }
3688 }
3689
3690 App::test_async((), |mut app| async move {
3691 let window_id = app.add_window(|_| View).0;
3692 let view = app.add_view(window_id, |_| View);
3693
3694 let condition = view.condition(&app, |_, _| false);
3695 app.update(|_| drop(view));
3696 condition.await;
3697 });
3698 }
3699
3700 // #[test]
3701 // fn test_ui_and_window_updates() {
3702 // struct View {
3703 // count: usize,
3704 // }
3705
3706 // impl Entity for View {
3707 // type Event = ();
3708 // }
3709
3710 // impl super::View for View {
3711 // fn render<'a>(&self, _: &AppContext) -> ElementBox {
3712 // Empty::new().boxed()
3713 // }
3714
3715 // fn ui_name() -> &'static str {
3716 // "View"
3717 // }
3718 // }
3719
3720 // App::test(|app| async move {
3721 // let (window_id, _) = app.add_window(|_| View { count: 3 });
3722 // let view_1 = app.add_view(window_id, |_| View { count: 1 });
3723 // let view_2 = app.add_view(window_id, |_| View { count: 2 });
3724
3725 // // Ensure that registering for UI updates after mutating the app still gives us all the
3726 // // updates.
3727 // let ui_updates = Rc::new(RefCell::new(Vec::new()));
3728 // let ui_updates_ = ui_updates.clone();
3729 // app.on_ui_update(move |update, _| ui_updates_.borrow_mut().push(update));
3730
3731 // assert_eq!(
3732 // ui_updates.borrow_mut().drain(..).collect::<Vec<_>>(),
3733 // vec![UiUpdate::OpenWindow {
3734 // window_id,
3735 // width: 1024.0,
3736 // height: 768.0,
3737 // }]
3738 // );
3739
3740 // let window_invalidations = Rc::new(RefCell::new(Vec::new()));
3741 // let window_invalidations_ = window_invalidations.clone();
3742 // app.on_window_invalidated(window_id, move |update, _| {
3743 // window_invalidations_.borrow_mut().push(update)
3744 // });
3745
3746 // let view_2_id = view_2.id();
3747 // view_1.update(app, |view, ctx| {
3748 // view.count = 7;
3749 // ctx.notify();
3750 // drop(view_2);
3751 // });
3752
3753 // let invalidation = window_invalidations.borrow_mut().drain(..).next().unwrap();
3754 // assert_eq!(invalidation.updated.len(), 1);
3755 // assert!(invalidation.updated.contains(&view_1.id()));
3756 // assert_eq!(invalidation.removed, vec![view_2_id]);
3757
3758 // let view_3 = view_1.update(app, |_, ctx| ctx.add_view(|_| View { count: 8 }));
3759
3760 // let invalidation = window_invalidations.borrow_mut().drain(..).next().unwrap();
3761 // assert_eq!(invalidation.updated.len(), 1);
3762 // assert!(invalidation.updated.contains(&view_3.id()));
3763 // assert!(invalidation.removed.is_empty());
3764
3765 // view_3
3766 // .update(app, |_, ctx| {
3767 // ctx.spawn_local(async { 9 }, |me, output, ctx| {
3768 // me.count = output;
3769 // ctx.notify();
3770 // })
3771 // })
3772 // .await;
3773
3774 // let invalidation = window_invalidations.borrow_mut().drain(..).next().unwrap();
3775 // assert_eq!(invalidation.updated.len(), 1);
3776 // assert!(invalidation.updated.contains(&view_3.id()));
3777 // assert!(invalidation.removed.is_empty());
3778 // });
3779 // }
3780}