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