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