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