1use crate::{
2 elements::Element,
3 executor::{self},
4 keymap::{self, Keystroke},
5 platform::{self, App as _},
6 util::post_inc,
7};
8use anyhow::{anyhow, Result};
9use keymap::MatchResult;
10use parking_lot::Mutex;
11use smol::{channel, prelude::*};
12use std::{
13 any::{type_name, Any, TypeId},
14 borrow,
15 cell::RefCell,
16 collections::{HashMap, HashSet, VecDeque},
17 fmt::{self, Debug},
18 hash::{Hash, Hasher},
19 marker::PhantomData,
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 pub fn test<T, F: Future<Output = T>>(f: impl FnOnce(App) -> F) -> T {
70 let platform = platform::current::app(); // TODO: Make a test platform app
71 let foreground = Rc::new(executor::Foreground::test());
72 let app = Self(Rc::new(RefCell::new(MutableAppContext::new(
73 foreground.clone(),
74 Arc::new(platform),
75 ))));
76 app.0.borrow_mut().weak_self = Some(Rc::downgrade(&app.0));
77 smol::block_on(foreground.run(f(app)))
78 }
79
80 pub fn new() -> Result<Self> {
81 let platform = Arc::new(platform::current::app());
82 let foreground = Rc::new(executor::Foreground::platform(platform.dispatcher())?);
83 let app = Self(Rc::new(RefCell::new(MutableAppContext::new(
84 foreground, platform,
85 ))));
86 app.0.borrow_mut().weak_self = Some(Rc::downgrade(&app.0));
87 Ok(app)
88 }
89
90 pub fn on_window_invalidated<F: 'static + FnMut(WindowInvalidation, &mut MutableAppContext)>(
91 &self,
92 window_id: usize,
93 callback: F,
94 ) {
95 self.0
96 .borrow_mut()
97 .on_window_invalidated(window_id, callback);
98 }
99
100 pub fn add_action<S, V, T, F>(&self, name: S, handler: F)
101 where
102 S: Into<String>,
103 V: View,
104 T: Any,
105 F: 'static + FnMut(&mut V, &T, &mut ViewContext<V>),
106 {
107 self.0.borrow_mut().add_action(name, handler);
108 }
109
110 pub fn add_global_action<S, T, F>(&self, name: S, handler: F)
111 where
112 S: Into<String>,
113 T: 'static + Any,
114 F: 'static + FnMut(&T, &mut MutableAppContext),
115 {
116 self.0.borrow_mut().add_global_action(name, handler);
117 }
118
119 pub fn dispatch_action<T: 'static + Any>(
120 &self,
121 window_id: usize,
122 responder_chain: Vec<usize>,
123 name: &str,
124 arg: T,
125 ) {
126 self.0.borrow_mut().dispatch_action(
127 window_id,
128 &responder_chain,
129 name,
130 Box::new(arg).as_ref(),
131 );
132 }
133
134 pub fn dispatch_global_action<T: 'static + Any>(&self, name: &str, arg: T) {
135 self.0
136 .borrow_mut()
137 .dispatch_global_action(name, Box::new(arg).as_ref());
138 }
139
140 pub fn add_bindings<T: IntoIterator<Item = keymap::Binding>>(&self, bindings: T) {
141 self.0.borrow_mut().add_bindings(bindings);
142 }
143
144 pub fn dispatch_keystroke(
145 &self,
146 window_id: usize,
147 responder_chain: Vec<usize>,
148 keystroke: &Keystroke,
149 ) -> Result<bool> {
150 let mut state = self.0.borrow_mut();
151 state.dispatch_keystroke(window_id, responder_chain, keystroke)
152 }
153
154 pub fn add_model<T, F>(&mut self, build_model: F) -> ModelHandle<T>
155 where
156 T: Entity,
157 F: FnOnce(&mut ModelContext<T>) -> T,
158 {
159 let mut state = self.0.borrow_mut();
160 state.pending_flushes += 1;
161 let handle = state.add_model(build_model);
162 state.flush_effects();
163 handle
164 }
165
166 fn read_model<T, F, S>(&self, handle: &ModelHandle<T>, read: F) -> S
167 where
168 T: Entity,
169 F: FnOnce(&T, &AppContext) -> S,
170 {
171 let state = self.0.borrow();
172 read(state.model(handle), &state.ctx)
173 }
174
175 pub fn add_window<T, F>(&mut self, build_root_view: F) -> (usize, ViewHandle<T>)
176 where
177 T: View,
178 F: FnOnce(&mut ViewContext<T>) -> T,
179 {
180 self.0.borrow_mut().add_window(build_root_view)
181 }
182
183 pub fn window_ids(&self) -> Vec<usize> {
184 self.0.borrow().window_ids().collect()
185 }
186
187 pub fn root_view<T: View>(&self, window_id: usize) -> Option<ViewHandle<T>> {
188 self.0.borrow().root_view(window_id)
189 }
190
191 pub fn add_view<T, F>(&mut self, window_id: usize, build_view: F) -> ViewHandle<T>
192 where
193 T: View,
194 F: FnOnce(&mut ViewContext<T>) -> T,
195 {
196 let mut state = self.0.borrow_mut();
197 state.pending_flushes += 1;
198 let handle = state.add_view(window_id, build_view);
199 state.flush_effects();
200 handle
201 }
202
203 pub fn add_option_view<T, F>(
204 &mut self,
205 window_id: usize,
206 build_view: F,
207 ) -> Option<ViewHandle<T>>
208 where
209 T: View,
210 F: FnOnce(&mut ViewContext<T>) -> Option<T>,
211 {
212 let mut state = self.0.borrow_mut();
213 state.pending_flushes += 1;
214 let handle = state.add_option_view(window_id, build_view);
215 state.flush_effects();
216 handle
217 }
218
219 pub fn read<T, F: FnOnce(&AppContext) -> T>(&mut self, callback: F) -> T {
220 callback(self.0.borrow().ctx())
221 }
222
223 pub fn update<T, F: FnOnce(&mut MutableAppContext) -> T>(&mut self, callback: F) -> T {
224 let mut state = self.0.borrow_mut();
225 state.pending_flushes += 1;
226 let result = callback(&mut *state);
227 state.flush_effects();
228 result
229 }
230
231 fn read_view<T, F, S>(&self, handle: &ViewHandle<T>, read: F) -> S
232 where
233 T: View,
234 F: FnOnce(&T, &AppContext) -> S,
235 {
236 let state = self.0.borrow();
237 read(state.view(handle), state.ctx())
238 }
239
240 pub fn finish_pending_tasks(&self) -> impl Future<Output = ()> {
241 self.0.borrow().finish_pending_tasks()
242 }
243}
244
245impl UpdateModel for App {
246 fn update_model<T, F, S>(&mut self, handle: &ModelHandle<T>, update: F) -> S
247 where
248 T: Entity,
249 F: FnOnce(&mut T, &mut ModelContext<T>) -> S,
250 {
251 let mut state = self.0.borrow_mut();
252 state.pending_flushes += 1;
253 let result = state.update_model(handle, update);
254 state.flush_effects();
255 result
256 }
257}
258
259impl UpdateView for App {
260 fn update_view<T, F, S>(&mut self, handle: &ViewHandle<T>, update: F) -> S
261 where
262 T: View,
263 F: FnOnce(&mut T, &mut ViewContext<T>) -> S,
264 {
265 let mut state = self.0.borrow_mut();
266 state.pending_flushes += 1;
267 let result = state.update_view(handle, update);
268 state.flush_effects();
269 result
270 }
271}
272
273type ActionCallback =
274 dyn FnMut(&mut dyn AnyView, &dyn Any, &mut MutableAppContext, usize, usize) -> bool;
275
276type GlobalActionCallback = dyn FnMut(&dyn Any, &mut MutableAppContext);
277
278pub struct MutableAppContext {
279 platform: Arc<dyn platform::App>,
280 ctx: AppContext,
281 actions: HashMap<TypeId, HashMap<String, Vec<Box<ActionCallback>>>>,
282 global_actions: HashMap<String, Vec<Box<GlobalActionCallback>>>,
283 keystroke_matcher: keymap::Matcher,
284 next_entity_id: usize,
285 next_window_id: usize,
286 next_task_id: usize,
287 weak_self: Option<rc::Weak<RefCell<Self>>>,
288 subscriptions: HashMap<usize, Vec<Subscription>>,
289 observations: HashMap<usize, Vec<Observation>>,
290 window_invalidations: HashMap<usize, WindowInvalidation>,
291 invalidation_callbacks:
292 HashMap<usize, Box<dyn FnMut(WindowInvalidation, &mut MutableAppContext)>>,
293 foreground: Rc<executor::Foreground>,
294 background: Arc<executor::Background>,
295 task_callbacks: HashMap<usize, TaskCallback>,
296 task_done: (channel::Sender<usize>, channel::Receiver<usize>),
297 pending_effects: VecDeque<Effect>,
298 pending_flushes: usize,
299 flushing_effects: bool,
300}
301
302impl MutableAppContext {
303 pub fn new(foreground: Rc<executor::Foreground>, platform: Arc<dyn platform::App>) -> Self {
304 Self {
305 platform,
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 pub fn finish_pending_tasks(&self) -> impl Future<Output = ()> {
1042 let mut pending_tasks = self.task_callbacks.keys().cloned().collect::<HashSet<_>>();
1043 let task_done = self.task_done.1.clone();
1044
1045 async move {
1046 while !pending_tasks.is_empty() {
1047 if let Ok(task_id) = task_done.recv().await {
1048 pending_tasks.remove(&task_id);
1049 } else {
1050 break;
1051 }
1052 }
1053 }
1054 }
1055}
1056
1057impl ModelAsRef for MutableAppContext {
1058 fn model<T: Entity>(&self, handle: &ModelHandle<T>) -> &T {
1059 if let Some(model) = self.ctx.models.get(&handle.model_id) {
1060 model
1061 .as_any()
1062 .downcast_ref()
1063 .expect("Downcast is type safe")
1064 } else {
1065 panic!("Circular model reference");
1066 }
1067 }
1068}
1069
1070impl UpdateModel for MutableAppContext {
1071 fn update_model<T, F, S>(&mut self, handle: &ModelHandle<T>, update: F) -> S
1072 where
1073 T: Entity,
1074 F: FnOnce(&mut T, &mut ModelContext<T>) -> S,
1075 {
1076 if let Some(mut model) = self.ctx.models.remove(&handle.model_id) {
1077 self.pending_flushes += 1;
1078 let mut ctx = ModelContext::new(self, handle.model_id);
1079 let result = update(
1080 model
1081 .as_any_mut()
1082 .downcast_mut()
1083 .expect("Downcast is type safe"),
1084 &mut ctx,
1085 );
1086 self.ctx.models.insert(handle.model_id, model);
1087 self.flush_effects();
1088 result
1089 } else {
1090 panic!("Circular model update");
1091 }
1092 }
1093}
1094
1095impl ViewAsRef for MutableAppContext {
1096 fn view<T: View>(&self, handle: &ViewHandle<T>) -> &T {
1097 if let Some(window) = self.ctx.windows.get(&handle.window_id) {
1098 if let Some(view) = window.views.get(&handle.view_id) {
1099 view.as_any().downcast_ref().expect("Downcast is type safe")
1100 } else {
1101 panic!("Circular view reference");
1102 }
1103 } else {
1104 panic!("Window does not exist");
1105 }
1106 }
1107}
1108
1109impl UpdateView for MutableAppContext {
1110 fn update_view<T, F, S>(&mut self, handle: &ViewHandle<T>, update: F) -> S
1111 where
1112 T: View,
1113 F: FnOnce(&mut T, &mut ViewContext<T>) -> S,
1114 {
1115 self.pending_flushes += 1;
1116 let mut view = if let Some(window) = self.ctx.windows.get_mut(&handle.window_id) {
1117 if let Some(view) = window.views.remove(&handle.view_id) {
1118 view
1119 } else {
1120 panic!("Circular view update");
1121 }
1122 } else {
1123 panic!("Window does not exist");
1124 };
1125
1126 let mut ctx = ViewContext::new(self, handle.window_id, handle.view_id);
1127 let result = update(
1128 view.as_any_mut()
1129 .downcast_mut()
1130 .expect("Downcast is type safe"),
1131 &mut ctx,
1132 );
1133 self.ctx
1134 .windows
1135 .get_mut(&handle.window_id)
1136 .unwrap()
1137 .views
1138 .insert(handle.view_id, view);
1139 self.flush_effects();
1140 result
1141 }
1142}
1143
1144pub struct AppContext {
1145 models: HashMap<usize, Box<dyn AnyModel>>,
1146 windows: HashMap<usize, Window>,
1147 ref_counts: Arc<Mutex<RefCounts>>,
1148}
1149
1150impl AppContext {
1151 pub fn root_view_id(&self, window_id: usize) -> Option<usize> {
1152 self.windows
1153 .get(&window_id)
1154 .and_then(|window| window.root_view.as_ref().map(|v| v.id()))
1155 }
1156
1157 pub fn focused_view_id(&self, window_id: usize) -> Option<usize> {
1158 self.windows
1159 .get(&window_id)
1160 .and_then(|window| window.focused_view)
1161 }
1162
1163 pub fn render_view(&self, window_id: usize, view_id: usize) -> Result<Box<dyn Element>> {
1164 self.windows
1165 .get(&window_id)
1166 .and_then(|w| w.views.get(&view_id))
1167 .map(|v| v.render(self))
1168 .ok_or(anyhow!("view not found"))
1169 }
1170
1171 pub fn render_views(&self, window_id: usize) -> Result<HashMap<usize, Box<dyn Element>>> {
1172 self.windows
1173 .get(&window_id)
1174 .map(|w| {
1175 w.views
1176 .iter()
1177 .map(|(id, view)| (*id, view.render(self)))
1178 .collect::<HashMap<_, Box<dyn Element>>>()
1179 })
1180 .ok_or(anyhow!("window not found"))
1181 }
1182}
1183
1184impl ModelAsRef for AppContext {
1185 fn model<T: Entity>(&self, handle: &ModelHandle<T>) -> &T {
1186 if let Some(model) = self.models.get(&handle.model_id) {
1187 model
1188 .as_any()
1189 .downcast_ref()
1190 .expect("downcast should be type safe")
1191 } else {
1192 panic!("circular model reference");
1193 }
1194 }
1195}
1196
1197impl ViewAsRef for AppContext {
1198 fn view<T: View>(&self, handle: &ViewHandle<T>) -> &T {
1199 if let Some(window) = self.windows.get(&handle.window_id) {
1200 if let Some(view) = window.views.get(&handle.view_id) {
1201 view.as_any()
1202 .downcast_ref()
1203 .expect("downcast should be type safe")
1204 } else {
1205 panic!("circular view reference");
1206 }
1207 } else {
1208 panic!("window does not exist");
1209 }
1210 }
1211}
1212
1213#[derive(Default)]
1214struct Window {
1215 views: HashMap<usize, Box<dyn AnyView>>,
1216 root_view: Option<AnyViewHandle>,
1217 focused_view: Option<usize>,
1218}
1219
1220#[derive(Default, Clone)]
1221pub struct WindowInvalidation {
1222 pub updated: HashSet<usize>,
1223 pub removed: Vec<usize>,
1224}
1225
1226pub enum Effect {
1227 Event {
1228 entity_id: usize,
1229 payload: Box<dyn Any>,
1230 },
1231 ModelNotification {
1232 model_id: usize,
1233 },
1234 ViewNotification {
1235 window_id: usize,
1236 view_id: usize,
1237 },
1238 Focus {
1239 window_id: usize,
1240 view_id: usize,
1241 },
1242}
1243
1244pub trait AnyModel: Send + Sync {
1245 fn as_any(&self) -> &dyn Any;
1246 fn as_any_mut(&mut self) -> &mut dyn Any;
1247}
1248
1249impl<T> AnyModel for T
1250where
1251 T: Entity,
1252{
1253 fn as_any(&self) -> &dyn Any {
1254 self
1255 }
1256
1257 fn as_any_mut(&mut self) -> &mut dyn Any {
1258 self
1259 }
1260}
1261
1262pub trait AnyView: Send + Sync {
1263 fn as_any(&self) -> &dyn Any;
1264 fn as_any_mut(&mut self) -> &mut dyn Any;
1265 fn ui_name(&self) -> &'static str;
1266 fn render<'a>(&self, app: &AppContext) -> Box<dyn Element>;
1267 fn on_focus(&mut self, app: &mut MutableAppContext, window_id: usize, view_id: usize);
1268 fn on_blur(&mut self, app: &mut MutableAppContext, window_id: usize, view_id: usize);
1269 fn keymap_context(&self, app: &AppContext) -> keymap::Context;
1270}
1271
1272impl<T> AnyView for T
1273where
1274 T: View,
1275{
1276 fn as_any(&self) -> &dyn Any {
1277 self
1278 }
1279
1280 fn as_any_mut(&mut self) -> &mut dyn Any {
1281 self
1282 }
1283
1284 fn ui_name(&self) -> &'static str {
1285 T::ui_name()
1286 }
1287
1288 fn render<'a>(&self, app: &AppContext) -> Box<dyn Element> {
1289 View::render(self, app)
1290 }
1291
1292 fn on_focus(&mut self, app: &mut MutableAppContext, window_id: usize, view_id: usize) {
1293 let mut ctx = ViewContext::new(app, window_id, view_id);
1294 View::on_focus(self, &mut ctx);
1295 }
1296
1297 fn on_blur(&mut self, app: &mut MutableAppContext, window_id: usize, view_id: usize) {
1298 let mut ctx = ViewContext::new(app, window_id, view_id);
1299 View::on_blur(self, &mut ctx);
1300 }
1301
1302 fn keymap_context(&self, app: &AppContext) -> keymap::Context {
1303 View::keymap_context(self, app)
1304 }
1305}
1306
1307pub struct ModelContext<'a, T: ?Sized> {
1308 app: &'a mut MutableAppContext,
1309 model_id: usize,
1310 model_type: PhantomData<T>,
1311 halt_stream: bool,
1312}
1313
1314impl<'a, T: Entity> ModelContext<'a, T> {
1315 fn new(app: &'a mut MutableAppContext, model_id: usize) -> Self {
1316 Self {
1317 app,
1318 model_id,
1319 model_type: PhantomData,
1320 halt_stream: false,
1321 }
1322 }
1323
1324 pub fn app(&self) -> &AppContext {
1325 &self.app.ctx
1326 }
1327
1328 pub fn app_mut(&mut self) -> &mut MutableAppContext {
1329 self.app
1330 }
1331
1332 pub fn background_executor(&self) -> Arc<executor::Background> {
1333 self.app.background.clone()
1334 }
1335
1336 pub fn halt_stream(&mut self) {
1337 self.halt_stream = true;
1338 }
1339
1340 pub fn model_id(&self) -> usize {
1341 self.model_id
1342 }
1343
1344 pub fn add_model<S, F>(&mut self, build_model: F) -> ModelHandle<S>
1345 where
1346 S: Entity,
1347 F: FnOnce(&mut ModelContext<S>) -> S,
1348 {
1349 self.app.add_model(build_model)
1350 }
1351
1352 pub fn subscribe<S: Entity, F>(&mut self, handle: &ModelHandle<S>, mut callback: F)
1353 where
1354 S::Event: 'static,
1355 F: 'static + FnMut(&mut T, &S::Event, &mut ModelContext<T>),
1356 {
1357 self.app
1358 .subscriptions
1359 .entry(handle.model_id)
1360 .or_default()
1361 .push(Subscription::FromModel {
1362 model_id: self.model_id,
1363 callback: Box::new(move |model, payload, app, model_id| {
1364 let model = model.downcast_mut().expect("downcast is type safe");
1365 let payload = payload.downcast_ref().expect("downcast is type safe");
1366 let mut ctx = ModelContext::new(app, model_id);
1367 callback(model, payload, &mut ctx);
1368 }),
1369 });
1370 }
1371
1372 pub fn emit(&mut self, payload: T::Event) {
1373 self.app.pending_effects.push_back(Effect::Event {
1374 entity_id: self.model_id,
1375 payload: Box::new(payload),
1376 });
1377 }
1378
1379 pub fn observe<S, F>(&mut self, handle: &ModelHandle<S>, mut callback: F)
1380 where
1381 S: Entity,
1382 F: 'static + FnMut(&mut T, ModelHandle<S>, &mut ModelContext<T>),
1383 {
1384 self.app
1385 .observations
1386 .entry(handle.model_id)
1387 .or_default()
1388 .push(Observation::FromModel {
1389 model_id: self.model_id,
1390 callback: Box::new(move |model, observed_id, app, model_id| {
1391 let model = model.downcast_mut().expect("downcast is type safe");
1392 let observed = ModelHandle::new(observed_id, &app.ctx.ref_counts);
1393 let mut ctx = ModelContext::new(app, model_id);
1394 callback(model, observed, &mut ctx);
1395 }),
1396 });
1397 }
1398
1399 pub fn notify(&mut self) {
1400 self.app
1401 .pending_effects
1402 .push_back(Effect::ModelNotification {
1403 model_id: self.model_id,
1404 });
1405 }
1406
1407 pub fn spawn_local<S, F, U>(&mut self, future: S, callback: F) -> impl Future<Output = U>
1408 where
1409 S: 'static + Future,
1410 F: 'static + FnOnce(&mut T, S::Output, &mut ModelContext<T>) -> U,
1411 U: 'static,
1412 {
1413 let (tx, rx) = channel::bounded(1);
1414
1415 let task_id = self.app.spawn_local(future);
1416
1417 self.app.task_callbacks.insert(
1418 task_id,
1419 TaskCallback::OnModelFromFuture {
1420 model_id: self.model_id,
1421 callback: Box::new(move |model, output, app, model_id, executor| {
1422 let model = model.downcast_mut().unwrap();
1423 let output = *output.downcast().unwrap();
1424 let result = callback(model, output, &mut ModelContext::new(app, model_id));
1425 executor
1426 .spawn(async move { tx.send(result).await })
1427 .detach();
1428 }),
1429 },
1430 );
1431
1432 async move { rx.recv().await.unwrap() }
1433 }
1434
1435 pub fn spawn<S, F, U>(&mut self, future: S, callback: F) -> impl Future<Output = U>
1436 where
1437 S: 'static + Future + Send,
1438 S::Output: Send,
1439 F: 'static + FnOnce(&mut T, S::Output, &mut ModelContext<T>) -> U,
1440 U: 'static,
1441 {
1442 let (tx, rx) = channel::bounded(1);
1443
1444 self.app
1445 .background
1446 .spawn(async move {
1447 if let Err(e) = tx.send(future.await).await {
1448 log::error!("error sending background task result to main thread: {}", e);
1449 }
1450 })
1451 .detach();
1452
1453 self.spawn_local(async move { rx.recv().await.unwrap() }, callback)
1454 }
1455
1456 pub fn spawn_stream_local<S, F>(
1457 &mut self,
1458 stream: S,
1459 mut callback: F,
1460 ) -> impl Future<Output = ()>
1461 where
1462 S: 'static + Stream + Unpin,
1463 F: 'static + FnMut(&mut T, Option<S::Item>, &mut ModelContext<T>),
1464 {
1465 let (tx, rx) = channel::bounded(1);
1466
1467 let task_id = self.app.spawn_stream_local(stream, tx);
1468 self.app.task_callbacks.insert(
1469 task_id,
1470 TaskCallback::OnModelFromStream {
1471 model_id: self.model_id,
1472 callback: Box::new(move |model, output, app, model_id| {
1473 let model = model.downcast_mut().unwrap();
1474 let output = *output.downcast().unwrap();
1475 let mut ctx = ModelContext::new(app, model_id);
1476 callback(model, output, &mut ctx);
1477 ctx.halt_stream
1478 }),
1479 },
1480 );
1481
1482 async move { rx.recv().await.unwrap() }
1483 }
1484}
1485
1486impl<M> ModelAsRef for ModelContext<'_, M> {
1487 fn model<T: Entity>(&self, handle: &ModelHandle<T>) -> &T {
1488 self.app.model(handle)
1489 }
1490}
1491
1492impl<M> UpdateModel for ModelContext<'_, M> {
1493 fn update_model<T, F, S>(&mut self, handle: &ModelHandle<T>, update: F) -> S
1494 where
1495 T: Entity,
1496 F: FnOnce(&mut T, &mut ModelContext<T>) -> S,
1497 {
1498 self.app.update_model(handle, update)
1499 }
1500}
1501
1502pub struct ViewContext<'a, T: ?Sized> {
1503 app: &'a mut MutableAppContext,
1504 window_id: usize,
1505 view_id: usize,
1506 view_type: PhantomData<T>,
1507 halt_action_dispatch: bool,
1508 halt_stream: bool,
1509}
1510
1511impl<'a, T: View> ViewContext<'a, T> {
1512 fn new(app: &'a mut MutableAppContext, window_id: usize, view_id: usize) -> Self {
1513 Self {
1514 app,
1515 window_id,
1516 view_id,
1517 view_type: PhantomData,
1518 halt_action_dispatch: true,
1519 halt_stream: false,
1520 }
1521 }
1522
1523 pub fn handle(&self) -> WeakViewHandle<T> {
1524 WeakViewHandle::new(self.window_id, self.view_id)
1525 }
1526
1527 pub fn window_id(&self) -> usize {
1528 self.window_id
1529 }
1530
1531 pub fn app(&self) -> &AppContext {
1532 &self.app.ctx
1533 }
1534
1535 pub fn app_mut(&mut self) -> &mut MutableAppContext {
1536 self.app
1537 }
1538
1539 pub fn focus<S>(&mut self, handle: S)
1540 where
1541 S: Into<AnyViewHandle>,
1542 {
1543 let handle = handle.into();
1544 self.app.pending_effects.push_back(Effect::Focus {
1545 window_id: handle.window_id,
1546 view_id: handle.view_id,
1547 });
1548 }
1549
1550 pub fn focus_self(&mut self) {
1551 self.app.pending_effects.push_back(Effect::Focus {
1552 window_id: self.window_id,
1553 view_id: self.view_id,
1554 });
1555 }
1556
1557 pub fn add_model<S, F>(&mut self, build_model: F) -> ModelHandle<S>
1558 where
1559 S: Entity,
1560 F: FnOnce(&mut ModelContext<S>) -> S,
1561 {
1562 self.app.add_model(build_model)
1563 }
1564
1565 pub fn add_view<S, F>(&mut self, build_view: F) -> ViewHandle<S>
1566 where
1567 S: View,
1568 F: FnOnce(&mut ViewContext<S>) -> S,
1569 {
1570 self.app.add_view(self.window_id, build_view)
1571 }
1572
1573 pub fn add_option_view<S, F>(&mut self, build_view: F) -> Option<ViewHandle<S>>
1574 where
1575 S: View,
1576 F: FnOnce(&mut ViewContext<S>) -> Option<S>,
1577 {
1578 self.app.add_option_view(self.window_id, build_view)
1579 }
1580
1581 pub fn subscribe_to_model<E, F>(&mut self, handle: &ModelHandle<E>, mut callback: F)
1582 where
1583 E: Entity,
1584 E::Event: 'static,
1585 F: 'static + FnMut(&mut T, ModelHandle<E>, &E::Event, &mut ViewContext<T>),
1586 {
1587 let emitter_handle = handle.downgrade();
1588 self.app
1589 .subscriptions
1590 .entry(handle.id())
1591 .or_default()
1592 .push(Subscription::FromView {
1593 window_id: self.window_id,
1594 view_id: self.view_id,
1595 callback: Box::new(move |view, payload, app, window_id, view_id| {
1596 if let Some(emitter_handle) = emitter_handle.upgrade(app.ctx()) {
1597 let model = view.downcast_mut().expect("downcast is type safe");
1598 let payload = payload.downcast_ref().expect("downcast is type safe");
1599 let mut ctx = ViewContext::new(app, window_id, view_id);
1600 callback(model, emitter_handle, payload, &mut ctx);
1601 }
1602 }),
1603 });
1604 }
1605
1606 pub fn subscribe_to_view<V, F>(&mut self, handle: &ViewHandle<V>, mut callback: F)
1607 where
1608 V: View,
1609 V::Event: 'static,
1610 F: 'static + FnMut(&mut T, ViewHandle<V>, &V::Event, &mut ViewContext<T>),
1611 {
1612 let emitter_handle = handle.downgrade();
1613
1614 self.app
1615 .subscriptions
1616 .entry(handle.id())
1617 .or_default()
1618 .push(Subscription::FromView {
1619 window_id: self.window_id,
1620 view_id: self.view_id,
1621 callback: Box::new(move |view, payload, app, window_id, view_id| {
1622 if let Some(emitter_handle) = emitter_handle.upgrade(app.ctx()) {
1623 let model = view.downcast_mut().expect("downcast is type safe");
1624 let payload = payload.downcast_ref().expect("downcast is type safe");
1625 let mut ctx = ViewContext::new(app, window_id, view_id);
1626 callback(model, emitter_handle, payload, &mut ctx);
1627 }
1628 }),
1629 });
1630 }
1631
1632 pub fn emit(&mut self, payload: T::Event) {
1633 self.app.pending_effects.push_back(Effect::Event {
1634 entity_id: self.view_id,
1635 payload: Box::new(payload),
1636 });
1637 }
1638
1639 pub fn observe<S, F>(&mut self, handle: &ModelHandle<S>, mut callback: F)
1640 where
1641 S: Entity,
1642 F: 'static + FnMut(&mut T, ModelHandle<S>, &mut ViewContext<T>),
1643 {
1644 self.app
1645 .observations
1646 .entry(handle.id())
1647 .or_default()
1648 .push(Observation::FromView {
1649 window_id: self.window_id,
1650 view_id: self.view_id,
1651 callback: Box::new(move |view, observed_id, app, window_id, view_id| {
1652 let view = view.downcast_mut().expect("downcast is type safe");
1653 let observed = ModelHandle::new(observed_id, &app.ctx.ref_counts);
1654 let mut ctx = ViewContext::new(app, window_id, view_id);
1655 callback(view, observed, &mut ctx);
1656 }),
1657 });
1658 }
1659
1660 pub fn notify(&mut self) {
1661 self.app
1662 .pending_effects
1663 .push_back(Effect::ViewNotification {
1664 window_id: self.window_id,
1665 view_id: self.view_id,
1666 });
1667 }
1668
1669 pub fn propagate_action(&mut self) {
1670 self.halt_action_dispatch = false;
1671 }
1672
1673 pub fn halt_stream(&mut self) {
1674 self.halt_stream = true;
1675 }
1676
1677 pub fn spawn_local<S, F, U>(&mut self, future: S, callback: F) -> impl Future<Output = U>
1678 where
1679 S: 'static + Future,
1680 F: 'static + FnOnce(&mut T, S::Output, &mut ViewContext<T>) -> U,
1681 U: 'static,
1682 {
1683 let (tx, rx) = channel::bounded(1);
1684
1685 let task_id = self.app.spawn_local(future);
1686
1687 self.app.task_callbacks.insert(
1688 task_id,
1689 TaskCallback::OnViewFromFuture {
1690 window_id: self.window_id,
1691 view_id: self.view_id,
1692 callback: Box::new(move |view, output, app, window_id, view_id, executor| {
1693 let view = view.as_any_mut().downcast_mut().unwrap();
1694 let output = *output.downcast().unwrap();
1695 let result =
1696 callback(view, output, &mut ViewContext::new(app, window_id, view_id));
1697 executor
1698 .spawn(async move { tx.send(result).await })
1699 .detach();
1700 }),
1701 },
1702 );
1703
1704 async move { rx.recv().await.unwrap() }
1705 }
1706
1707 pub fn spawn<S, F, U>(&mut self, future: S, callback: F) -> impl Future<Output = U>
1708 where
1709 S: 'static + Future + Send,
1710 S::Output: Send,
1711 F: 'static + FnOnce(&mut T, S::Output, &mut ViewContext<T>) -> U,
1712 U: 'static,
1713 {
1714 let (tx, rx) = channel::bounded(1);
1715
1716 self.app
1717 .background
1718 .spawn(async move {
1719 if let Err(_) = tx.send(future.await).await {
1720 log::error!("Error sending background task result to main thread",);
1721 }
1722 })
1723 .detach();
1724
1725 self.spawn_local(async move { rx.recv().await.unwrap() }, callback)
1726 }
1727
1728 pub fn spawn_stream_local<S, F>(
1729 &mut self,
1730 stream: S,
1731 mut callback: F,
1732 ) -> impl Future<Output = ()>
1733 where
1734 S: 'static + Stream + Unpin,
1735 F: 'static + FnMut(&mut T, Option<S::Item>, &mut ViewContext<T>),
1736 {
1737 let (tx, rx) = channel::bounded(1);
1738
1739 let task_id = self.app.spawn_stream_local(stream, tx);
1740 self.app.task_callbacks.insert(
1741 task_id,
1742 TaskCallback::OnViewFromStream {
1743 window_id: self.window_id,
1744 view_id: self.view_id,
1745 callback: Box::new(move |view, output, app, window_id, view_id| {
1746 let view = view.as_any_mut().downcast_mut().unwrap();
1747 let output = *output.downcast().unwrap();
1748 let mut ctx = ViewContext::new(app, window_id, view_id);
1749 callback(view, output, &mut ctx);
1750 ctx.halt_stream
1751 }),
1752 },
1753 );
1754
1755 async move { rx.recv().await.unwrap() }
1756 }
1757}
1758
1759impl<V> ModelAsRef for ViewContext<'_, V> {
1760 fn model<T: Entity>(&self, handle: &ModelHandle<T>) -> &T {
1761 self.app.model(handle)
1762 }
1763}
1764
1765impl<V: View> UpdateModel for ViewContext<'_, V> {
1766 fn update_model<T, F, S>(&mut self, handle: &ModelHandle<T>, update: F) -> S
1767 where
1768 T: Entity,
1769 F: FnOnce(&mut T, &mut ModelContext<T>) -> S,
1770 {
1771 self.app.update_model(handle, update)
1772 }
1773}
1774
1775impl<V: View> ViewAsRef for ViewContext<'_, V> {
1776 fn view<T: View>(&self, handle: &ViewHandle<T>) -> &T {
1777 self.app.view(handle)
1778 }
1779}
1780
1781impl<V: View> UpdateView for ViewContext<'_, V> {
1782 fn update_view<T, F, S>(&mut self, handle: &ViewHandle<T>, update: F) -> S
1783 where
1784 T: View,
1785 F: FnOnce(&mut T, &mut ViewContext<T>) -> S,
1786 {
1787 self.app.update_view(handle, update)
1788 }
1789}
1790
1791pub trait Handle<T> {
1792 fn id(&self) -> usize;
1793 fn location(&self) -> EntityLocation;
1794}
1795
1796#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
1797pub enum EntityLocation {
1798 Model(usize),
1799 View(usize, usize),
1800}
1801
1802pub struct ModelHandle<T> {
1803 model_id: usize,
1804 model_type: PhantomData<T>,
1805 ref_counts: Weak<Mutex<RefCounts>>,
1806}
1807
1808impl<T: Entity> ModelHandle<T> {
1809 fn new(model_id: usize, ref_counts: &Arc<Mutex<RefCounts>>) -> Self {
1810 ref_counts.lock().inc(model_id);
1811 Self {
1812 model_id,
1813 model_type: PhantomData,
1814 ref_counts: Arc::downgrade(ref_counts),
1815 }
1816 }
1817
1818 fn downgrade(&self) -> WeakModelHandle<T> {
1819 WeakModelHandle::new(self.model_id)
1820 }
1821
1822 pub fn id(&self) -> usize {
1823 self.model_id
1824 }
1825
1826 pub fn as_ref<'a, A: ModelAsRef>(&self, app: &'a A) -> &'a T {
1827 app.model(self)
1828 }
1829
1830 pub fn read<'a, S, F>(&self, app: &'a App, read: F) -> S
1831 where
1832 F: FnOnce(&T, &AppContext) -> S,
1833 {
1834 app.read_model(self, read)
1835 }
1836
1837 pub fn update<A, F, S>(&self, app: &mut A, update: F) -> S
1838 where
1839 A: UpdateModel,
1840 F: FnOnce(&mut T, &mut ModelContext<T>) -> S,
1841 {
1842 app.update_model(self, update)
1843 }
1844}
1845
1846impl<T> Clone for ModelHandle<T> {
1847 fn clone(&self) -> Self {
1848 if let Some(ref_counts) = self.ref_counts.upgrade() {
1849 ref_counts.lock().inc(self.model_id);
1850 }
1851
1852 Self {
1853 model_id: self.model_id,
1854 model_type: PhantomData,
1855 ref_counts: self.ref_counts.clone(),
1856 }
1857 }
1858}
1859
1860impl<T> PartialEq for ModelHandle<T> {
1861 fn eq(&self, other: &Self) -> bool {
1862 self.model_id == other.model_id
1863 }
1864}
1865
1866impl<T> Eq for ModelHandle<T> {}
1867
1868impl<T> Hash for ModelHandle<T> {
1869 fn hash<H: Hasher>(&self, state: &mut H) {
1870 self.model_id.hash(state);
1871 }
1872}
1873
1874impl<T> borrow::Borrow<usize> for ModelHandle<T> {
1875 fn borrow(&self) -> &usize {
1876 &self.model_id
1877 }
1878}
1879
1880impl<T> Debug for ModelHandle<T> {
1881 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1882 f.debug_tuple(&format!("ModelHandle<{}>", type_name::<T>()))
1883 .field(&self.model_id)
1884 .finish()
1885 }
1886}
1887
1888unsafe impl<T> Send for ModelHandle<T> {}
1889unsafe impl<T> Sync for ModelHandle<T> {}
1890
1891impl<T> Drop for ModelHandle<T> {
1892 fn drop(&mut self) {
1893 if let Some(ref_counts) = self.ref_counts.upgrade() {
1894 ref_counts.lock().dec_model(self.model_id);
1895 }
1896 }
1897}
1898
1899impl<T> Handle<T> for ModelHandle<T> {
1900 fn id(&self) -> usize {
1901 self.model_id
1902 }
1903
1904 fn location(&self) -> EntityLocation {
1905 EntityLocation::Model(self.model_id)
1906 }
1907}
1908
1909pub struct WeakModelHandle<T> {
1910 model_id: usize,
1911 model_type: PhantomData<T>,
1912}
1913
1914impl<T: Entity> WeakModelHandle<T> {
1915 fn new(model_id: usize) -> Self {
1916 Self {
1917 model_id,
1918 model_type: PhantomData,
1919 }
1920 }
1921
1922 pub fn upgrade(&self, app: &AppContext) -> Option<ModelHandle<T>> {
1923 if app.models.contains_key(&self.model_id) {
1924 Some(ModelHandle::new(self.model_id, &app.ref_counts))
1925 } else {
1926 None
1927 }
1928 }
1929}
1930
1931pub struct ViewHandle<T> {
1932 window_id: usize,
1933 view_id: usize,
1934 view_type: PhantomData<T>,
1935 ref_counts: Weak<Mutex<RefCounts>>,
1936}
1937
1938impl<T: View> ViewHandle<T> {
1939 fn new(window_id: usize, view_id: usize, ref_counts: &Arc<Mutex<RefCounts>>) -> Self {
1940 ref_counts.lock().inc(view_id);
1941 Self {
1942 window_id,
1943 view_id,
1944 view_type: PhantomData,
1945 ref_counts: Arc::downgrade(ref_counts),
1946 }
1947 }
1948
1949 fn downgrade(&self) -> WeakViewHandle<T> {
1950 WeakViewHandle::new(self.window_id, self.view_id)
1951 }
1952
1953 pub fn window_id(&self) -> usize {
1954 self.window_id
1955 }
1956
1957 pub fn id(&self) -> usize {
1958 self.view_id
1959 }
1960
1961 pub fn as_ref<'a, A: ViewAsRef>(&self, app: &'a A) -> &'a T {
1962 app.view(self)
1963 }
1964
1965 pub fn read<'a, F, S>(&self, app: &'a App, read: F) -> S
1966 where
1967 F: FnOnce(&T, &AppContext) -> S,
1968 {
1969 app.read_view(self, read)
1970 }
1971
1972 pub fn update<A, F, S>(&self, app: &mut A, update: F) -> S
1973 where
1974 A: UpdateView,
1975 F: FnOnce(&mut T, &mut ViewContext<T>) -> S,
1976 {
1977 app.update_view(self, update)
1978 }
1979
1980 pub fn is_focused(&self, app: &AppContext) -> bool {
1981 app.focused_view_id(self.window_id)
1982 .map_or(false, |focused_id| focused_id == self.view_id)
1983 }
1984}
1985
1986impl<T> Clone for ViewHandle<T> {
1987 fn clone(&self) -> Self {
1988 if let Some(ref_counts) = self.ref_counts.upgrade() {
1989 ref_counts.lock().inc(self.view_id);
1990 }
1991
1992 Self {
1993 window_id: self.window_id,
1994 view_id: self.view_id,
1995 view_type: PhantomData,
1996 ref_counts: self.ref_counts.clone(),
1997 }
1998 }
1999}
2000
2001impl<T> PartialEq for ViewHandle<T> {
2002 fn eq(&self, other: &Self) -> bool {
2003 self.window_id == other.window_id && self.view_id == other.view_id
2004 }
2005}
2006
2007impl<T> Eq for ViewHandle<T> {}
2008
2009impl<T> Debug for ViewHandle<T> {
2010 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2011 f.debug_struct(&format!("ViewHandle<{}>", type_name::<T>()))
2012 .field("window_id", &self.window_id)
2013 .field("view_id", &self.view_id)
2014 .finish()
2015 }
2016}
2017
2018impl<T> Drop for ViewHandle<T> {
2019 fn drop(&mut self) {
2020 if let Some(ref_counts) = self.ref_counts.upgrade() {
2021 ref_counts.lock().dec_view(self.window_id, self.view_id);
2022 }
2023 }
2024}
2025
2026impl<T> Handle<T> for ViewHandle<T> {
2027 fn id(&self) -> usize {
2028 self.view_id
2029 }
2030
2031 fn location(&self) -> EntityLocation {
2032 EntityLocation::View(self.window_id, self.view_id)
2033 }
2034}
2035
2036#[derive(Clone)]
2037pub struct AnyViewHandle {
2038 window_id: usize,
2039 view_id: usize,
2040 view_type: TypeId,
2041 ref_counts: Weak<Mutex<RefCounts>>,
2042}
2043
2044impl AnyViewHandle {
2045 pub fn id(&self) -> usize {
2046 self.view_id
2047 }
2048
2049 pub fn is<T: 'static>(&self) -> bool {
2050 TypeId::of::<T>() == self.view_type
2051 }
2052
2053 pub fn downcast<T: View>(self) -> Option<ViewHandle<T>> {
2054 if self.is::<T>() {
2055 if let Some(ref_counts) = self.ref_counts.upgrade() {
2056 return Some(ViewHandle::new(self.window_id, self.view_id, &ref_counts));
2057 }
2058 }
2059 None
2060 }
2061}
2062
2063impl<T: View> From<&ViewHandle<T>> for AnyViewHandle {
2064 fn from(handle: &ViewHandle<T>) -> Self {
2065 if let Some(ref_counts) = handle.ref_counts.upgrade() {
2066 ref_counts.lock().inc(handle.view_id);
2067 }
2068 AnyViewHandle {
2069 window_id: handle.window_id,
2070 view_id: handle.view_id,
2071 view_type: TypeId::of::<T>(),
2072 ref_counts: handle.ref_counts.clone(),
2073 }
2074 }
2075}
2076
2077impl<T: View> From<ViewHandle<T>> for AnyViewHandle {
2078 fn from(handle: ViewHandle<T>) -> Self {
2079 (&handle).into()
2080 }
2081}
2082
2083pub struct WeakViewHandle<T> {
2084 window_id: usize,
2085 view_id: usize,
2086 view_type: PhantomData<T>,
2087}
2088
2089impl<T: View> WeakViewHandle<T> {
2090 fn new(window_id: usize, view_id: usize) -> Self {
2091 Self {
2092 window_id,
2093 view_id,
2094 view_type: PhantomData,
2095 }
2096 }
2097
2098 pub fn upgrade(&self, app: &AppContext) -> Option<ViewHandle<T>> {
2099 if app
2100 .windows
2101 .get(&self.window_id)
2102 .and_then(|w| w.views.get(&self.view_id))
2103 .is_some()
2104 {
2105 Some(ViewHandle::new(
2106 self.window_id,
2107 self.view_id,
2108 &app.ref_counts,
2109 ))
2110 } else {
2111 None
2112 }
2113 }
2114}
2115
2116impl<T> Clone for WeakViewHandle<T> {
2117 fn clone(&self) -> Self {
2118 Self {
2119 window_id: self.window_id,
2120 view_id: self.view_id,
2121 view_type: PhantomData,
2122 }
2123 }
2124}
2125
2126#[derive(Default)]
2127struct RefCounts {
2128 counts: HashMap<usize, usize>,
2129 dropped_models: HashSet<usize>,
2130 dropped_views: HashSet<(usize, usize)>,
2131}
2132
2133impl RefCounts {
2134 fn inc(&mut self, model_id: usize) {
2135 *self.counts.entry(model_id).or_insert(0) += 1;
2136 }
2137
2138 fn dec_model(&mut self, model_id: usize) {
2139 if let Some(count) = self.counts.get_mut(&model_id) {
2140 *count -= 1;
2141 if *count == 0 {
2142 self.counts.remove(&model_id);
2143 self.dropped_models.insert(model_id);
2144 }
2145 } else {
2146 panic!("Expected ref count to be positive")
2147 }
2148 }
2149
2150 fn dec_view(&mut self, window_id: usize, view_id: usize) {
2151 if let Some(count) = self.counts.get_mut(&view_id) {
2152 *count -= 1;
2153 if *count == 0 {
2154 self.counts.remove(&view_id);
2155 self.dropped_views.insert((window_id, view_id));
2156 }
2157 } else {
2158 panic!("Expected ref count to be positive")
2159 }
2160 }
2161
2162 fn take_dropped(&mut self) -> (HashSet<usize>, HashSet<(usize, usize)>) {
2163 let mut dropped_models = HashSet::new();
2164 let mut dropped_views = HashSet::new();
2165 std::mem::swap(&mut self.dropped_models, &mut dropped_models);
2166 std::mem::swap(&mut self.dropped_views, &mut dropped_views);
2167 (dropped_models, dropped_views)
2168 }
2169}
2170
2171enum Subscription {
2172 FromModel {
2173 model_id: usize,
2174 callback: Box<dyn FnMut(&mut dyn Any, &dyn Any, &mut MutableAppContext, usize)>,
2175 },
2176 FromView {
2177 window_id: usize,
2178 view_id: usize,
2179 callback: Box<dyn FnMut(&mut dyn Any, &dyn Any, &mut MutableAppContext, usize, usize)>,
2180 },
2181}
2182
2183enum Observation {
2184 FromModel {
2185 model_id: usize,
2186 callback: Box<dyn FnMut(&mut dyn Any, usize, &mut MutableAppContext, usize)>,
2187 },
2188 FromView {
2189 window_id: usize,
2190 view_id: usize,
2191 callback: Box<dyn FnMut(&mut dyn Any, usize, &mut MutableAppContext, usize, usize)>,
2192 },
2193}
2194
2195enum TaskCallback {
2196 OnModelFromFuture {
2197 model_id: usize,
2198 callback: Box<
2199 dyn FnOnce(
2200 &mut dyn Any,
2201 Box<dyn Any>,
2202 &mut MutableAppContext,
2203 usize,
2204 Rc<executor::Foreground>,
2205 ),
2206 >,
2207 },
2208 OnModelFromStream {
2209 model_id: usize,
2210 callback: Box<dyn FnMut(&mut dyn Any, Box<dyn Any>, &mut MutableAppContext, usize) -> bool>,
2211 },
2212 OnViewFromFuture {
2213 window_id: usize,
2214 view_id: usize,
2215 callback: Box<
2216 dyn FnOnce(
2217 &mut dyn AnyView,
2218 Box<dyn Any>,
2219 &mut MutableAppContext,
2220 usize,
2221 usize,
2222 Rc<executor::Foreground>,
2223 ),
2224 >,
2225 },
2226 OnViewFromStream {
2227 window_id: usize,
2228 view_id: usize,
2229 callback: Box<
2230 dyn FnMut(&mut dyn AnyView, Box<dyn Any>, &mut MutableAppContext, usize, usize) -> bool,
2231 >,
2232 },
2233}
2234
2235#[cfg(test)]
2236mod tests {
2237 use super::*;
2238 use crate::elements::*;
2239
2240 #[test]
2241 fn test_model_handles() {
2242 struct Model {
2243 other: Option<ModelHandle<Model>>,
2244 events: Vec<String>,
2245 }
2246
2247 impl Entity for Model {
2248 type Event = usize;
2249 }
2250
2251 impl Model {
2252 fn new(other: Option<ModelHandle<Self>>, ctx: &mut ModelContext<Self>) -> Self {
2253 if let Some(other) = other.as_ref() {
2254 ctx.observe(other, |me, _, _| {
2255 me.events.push("notified".into());
2256 });
2257 ctx.subscribe(other, |me, event, _| {
2258 me.events.push(format!("observed event {}", event));
2259 });
2260 }
2261
2262 Self {
2263 other,
2264 events: Vec::new(),
2265 }
2266 }
2267 }
2268
2269 let mut app = App::new().unwrap();
2270 let app = &mut app;
2271
2272 let handle_1 = app.add_model(|ctx| Model::new(None, ctx));
2273 let handle_2 = app.add_model(|ctx| Model::new(Some(handle_1.clone()), ctx));
2274 assert_eq!(app.0.borrow().ctx.models.len(), 2);
2275
2276 handle_1.update(app, |model, ctx| {
2277 model.events.push("updated".into());
2278 ctx.emit(1);
2279 ctx.notify();
2280 ctx.emit(2);
2281 });
2282 handle_1.read(app, |model, _| {
2283 assert_eq!(model.events, vec!["updated".to_string()]);
2284 });
2285 handle_2.read(app, |model, _| {
2286 assert_eq!(
2287 model.events,
2288 vec![
2289 "observed event 1".to_string(),
2290 "notified".to_string(),
2291 "observed event 2".to_string(),
2292 ]
2293 );
2294 });
2295
2296 handle_2.update(app, |model, _| {
2297 drop(handle_1);
2298 model.other.take();
2299 });
2300
2301 let app_state = app.0.borrow();
2302 assert_eq!(app_state.ctx.models.len(), 1);
2303 assert!(app_state.subscriptions.is_empty());
2304 assert!(app_state.observations.is_empty());
2305 }
2306
2307 #[test]
2308 fn test_subscribe_and_emit_from_model() {
2309 #[derive(Default)]
2310 struct Model {
2311 events: Vec<usize>,
2312 }
2313
2314 impl Entity for Model {
2315 type Event = usize;
2316 }
2317
2318 let mut app = App::new().unwrap();
2319 let app = &mut app;
2320
2321 let handle_1 = app.add_model(|_| Model::default());
2322 let handle_2 = app.add_model(|_| Model::default());
2323 let handle_2b = handle_2.clone();
2324
2325 handle_1.update(app, |_, c| {
2326 c.subscribe(&handle_2, move |model: &mut Model, event, c| {
2327 model.events.push(*event);
2328
2329 c.subscribe(&handle_2b, |model, event, _| {
2330 model.events.push(*event * 2);
2331 });
2332 });
2333 });
2334
2335 handle_2.update(app, |_, c| c.emit(7));
2336 handle_1.read(app, |model, _| assert_eq!(model.events, vec![7]));
2337
2338 handle_2.update(app, |_, c| c.emit(5));
2339 handle_1.read(app, |model, _| assert_eq!(model.events, vec![7, 10, 5]));
2340 }
2341
2342 #[test]
2343 fn test_observe_and_notify_from_model() {
2344 #[derive(Default)]
2345 struct Model {
2346 count: usize,
2347 events: Vec<usize>,
2348 }
2349
2350 impl Entity for Model {
2351 type Event = ();
2352 }
2353
2354 let mut app = App::new().unwrap();
2355
2356 let app = &mut app;
2357 let handle_1 = app.add_model(|_| Model::default());
2358 let handle_2 = app.add_model(|_| Model::default());
2359 let handle_2b = handle_2.clone();
2360
2361 handle_1.update(app, |_, c| {
2362 c.observe(&handle_2, move |model, observed, c| {
2363 model.events.push(observed.as_ref(c).count);
2364 c.observe(&handle_2b, |model, observed, c| {
2365 model.events.push(observed.as_ref(c).count * 2);
2366 });
2367 });
2368 });
2369
2370 handle_2.update(app, |model, c| {
2371 model.count = 7;
2372 c.notify()
2373 });
2374 handle_1.read(app, |model, _| assert_eq!(model.events, vec![7]));
2375
2376 handle_2.update(app, |model, c| {
2377 model.count = 5;
2378 c.notify()
2379 });
2380 handle_1.read(app, |model, _| assert_eq!(model.events, vec![7, 10, 5]))
2381 }
2382
2383 #[test]
2384 fn test_spawn_from_model() {
2385 #[derive(Default)]
2386 struct Model {
2387 count: usize,
2388 }
2389
2390 impl Entity for Model {
2391 type Event = ();
2392 }
2393
2394 App::test(|mut app| async move {
2395 let handle = app.add_model(|_| Model::default());
2396 handle
2397 .update(&mut app, |_, c| {
2398 c.spawn_local(async { 7 }, |model, output, _| {
2399 model.count = output;
2400 })
2401 })
2402 .await;
2403 handle.read(&app, |model, _| assert_eq!(model.count, 7));
2404
2405 handle
2406 .update(&mut app, |_, c| {
2407 c.spawn(async { 14 }, |model, output, _| {
2408 model.count = output;
2409 })
2410 })
2411 .await;
2412 handle.read(&app, |model, _| assert_eq!(model.count, 14));
2413 });
2414 }
2415
2416 #[test]
2417 fn test_spawn_stream_local_from_model() {
2418 #[derive(Default)]
2419 struct Model {
2420 events: Vec<Option<usize>>,
2421 }
2422
2423 impl Entity for Model {
2424 type Event = ();
2425 }
2426
2427 App::test(|mut app| async move {
2428 let handle = app.add_model(|_| Model::default());
2429 handle
2430 .update(&mut app, |_, c| {
2431 c.spawn_stream_local(smol::stream::iter(vec![1, 2, 3]), |model, output, _| {
2432 model.events.push(output);
2433 })
2434 })
2435 .await;
2436
2437 handle.read(&app, |model, _| {
2438 assert_eq!(model.events, [Some(1), Some(2), Some(3), None])
2439 });
2440 })
2441 }
2442
2443 #[test]
2444 fn test_view_handles() {
2445 struct View {
2446 other: Option<ViewHandle<View>>,
2447 events: Vec<String>,
2448 }
2449
2450 impl Entity for View {
2451 type Event = usize;
2452 }
2453
2454 impl super::View for View {
2455 fn render<'a>(&self, _: &AppContext) -> Box<dyn Element> {
2456 Empty::new().boxed()
2457 }
2458
2459 fn ui_name() -> &'static str {
2460 "View"
2461 }
2462 }
2463
2464 impl View {
2465 fn new(other: Option<ViewHandle<View>>, ctx: &mut ViewContext<Self>) -> Self {
2466 if let Some(other) = other.as_ref() {
2467 ctx.subscribe_to_view(other, |me, _, event, _| {
2468 me.events.push(format!("observed event {}", event));
2469 });
2470 }
2471 Self {
2472 other,
2473 events: Vec::new(),
2474 }
2475 }
2476 }
2477
2478 let mut app = App::new().unwrap();
2479 let app = &mut app;
2480
2481 let (window_id, _) = app.add_window(|ctx| View::new(None, ctx));
2482 let handle_1 = app.add_view(window_id, |ctx| View::new(None, ctx));
2483 let handle_2 = app.add_view(window_id, |ctx| View::new(Some(handle_1.clone()), ctx));
2484 assert_eq!(app.0.borrow().ctx.windows[&window_id].views.len(), 3);
2485
2486 handle_1.update(app, |view, ctx| {
2487 view.events.push("updated".into());
2488 ctx.emit(1);
2489 ctx.emit(2);
2490 });
2491 handle_1.read(app, |view, _| {
2492 assert_eq!(view.events, vec!["updated".to_string()]);
2493 });
2494 handle_2.read(app, |view, _| {
2495 assert_eq!(
2496 view.events,
2497 vec![
2498 "observed event 1".to_string(),
2499 "observed event 2".to_string(),
2500 ]
2501 );
2502 });
2503
2504 handle_2.update(app, |view, _| {
2505 drop(handle_1);
2506 view.other.take();
2507 });
2508
2509 let app_state = app.0.borrow();
2510 assert_eq!(app_state.ctx.windows[&window_id].views.len(), 2);
2511 assert!(app_state.subscriptions.is_empty());
2512 assert!(app_state.observations.is_empty());
2513 }
2514
2515 #[test]
2516 fn test_subscribe_and_emit_from_view() {
2517 #[derive(Default)]
2518 struct View {
2519 events: Vec<usize>,
2520 }
2521
2522 impl Entity for View {
2523 type Event = usize;
2524 }
2525
2526 impl super::View for View {
2527 fn render<'a>(&self, _: &AppContext) -> Box<dyn Element> {
2528 Empty::new().boxed()
2529 }
2530
2531 fn ui_name() -> &'static str {
2532 "View"
2533 }
2534 }
2535
2536 struct Model;
2537
2538 impl Entity for Model {
2539 type Event = usize;
2540 }
2541
2542 let mut app = App::new().unwrap();
2543 let app = &mut app;
2544
2545 let (window_id, handle_1) = app.add_window(|_| View::default());
2546 let handle_2 = app.add_view(window_id, |_| View::default());
2547 let handle_2b = handle_2.clone();
2548 let handle_3 = app.add_model(|_| Model);
2549
2550 handle_1.update(app, |_, c| {
2551 c.subscribe_to_view(&handle_2, move |me, _, event, c| {
2552 me.events.push(*event);
2553
2554 c.subscribe_to_view(&handle_2b, |me, _, event, _| {
2555 me.events.push(*event * 2);
2556 });
2557 });
2558
2559 c.subscribe_to_model(&handle_3, |me, _, event, _| {
2560 me.events.push(*event);
2561 })
2562 });
2563
2564 handle_2.update(app, |_, c| c.emit(7));
2565 handle_1.read(app, |view, _| assert_eq!(view.events, vec![7]));
2566
2567 handle_2.update(app, |_, c| c.emit(5));
2568 handle_1.read(app, |view, _| assert_eq!(view.events, vec![7, 10, 5]));
2569
2570 handle_3.update(app, |_, c| c.emit(9));
2571 handle_1.read(app, |view, _| assert_eq!(view.events, vec![7, 10, 5, 9]));
2572 }
2573
2574 #[test]
2575 fn test_dropping_subscribers() {
2576 struct View;
2577
2578 impl Entity for View {
2579 type Event = ();
2580 }
2581
2582 impl super::View for View {
2583 fn render<'a>(&self, _: &AppContext) -> Box<dyn Element> {
2584 Empty::new().boxed()
2585 }
2586
2587 fn ui_name() -> &'static str {
2588 "View"
2589 }
2590 }
2591
2592 struct Model;
2593
2594 impl Entity for Model {
2595 type Event = ();
2596 }
2597
2598 let mut app = App::new().unwrap();
2599 let app = &mut app;
2600
2601 let (window_id, _) = app.add_window(|_| View);
2602 let observing_view = app.add_view(window_id, |_| View);
2603 let emitting_view = app.add_view(window_id, |_| View);
2604 let observing_model = app.add_model(|_| Model);
2605 let observed_model = app.add_model(|_| Model);
2606
2607 observing_view.update(app, |_, ctx| {
2608 ctx.subscribe_to_view(&emitting_view, |_, _, _, _| {});
2609 ctx.subscribe_to_model(&observed_model, |_, _, _, _| {});
2610 });
2611 observing_model.update(app, |_, ctx| {
2612 ctx.subscribe(&observed_model, |_, _, _| {});
2613 });
2614
2615 app.update(|_| {
2616 drop(observing_view);
2617 drop(observing_model);
2618 });
2619
2620 emitting_view.update(app, |_, ctx| ctx.emit(()));
2621 observed_model.update(app, |_, ctx| ctx.emit(()));
2622 }
2623
2624 #[test]
2625 fn test_observe_and_notify_from_view() {
2626 #[derive(Default)]
2627 struct View {
2628 events: Vec<usize>,
2629 }
2630
2631 impl Entity for View {
2632 type Event = usize;
2633 }
2634
2635 impl super::View for View {
2636 fn render<'a>(&self, _: &AppContext) -> Box<dyn Element> {
2637 Empty::new().boxed()
2638 }
2639
2640 fn ui_name() -> &'static str {
2641 "View"
2642 }
2643 }
2644
2645 #[derive(Default)]
2646 struct Model {
2647 count: usize,
2648 }
2649
2650 impl Entity for Model {
2651 type Event = ();
2652 }
2653
2654 let mut app = App::new().unwrap();
2655 let app = &mut app;
2656 let (_, view) = app.add_window(|_| View::default());
2657 let model = app.add_model(|_| Model::default());
2658
2659 view.update(app, |_, c| {
2660 c.observe(&model, |me, observed, c| {
2661 me.events.push(observed.as_ref(c).count)
2662 });
2663 });
2664
2665 model.update(app, |model, c| {
2666 model.count = 11;
2667 c.notify();
2668 });
2669 view.read(app, |view, _| assert_eq!(view.events, vec![11]));
2670 }
2671
2672 #[test]
2673 fn test_dropping_observers() {
2674 struct View;
2675
2676 impl Entity for View {
2677 type Event = ();
2678 }
2679
2680 impl super::View for View {
2681 fn render<'a>(&self, _: &AppContext) -> Box<dyn Element> {
2682 Empty::new().boxed()
2683 }
2684
2685 fn ui_name() -> &'static str {
2686 "View"
2687 }
2688 }
2689
2690 struct Model;
2691
2692 impl Entity for Model {
2693 type Event = ();
2694 }
2695
2696 let mut app = App::new().unwrap();
2697 let app = &mut app;
2698
2699 let (window_id, _) = app.add_window(|_| View);
2700 let observing_view = app.add_view(window_id, |_| View);
2701 let observing_model = app.add_model(|_| Model);
2702 let observed_model = app.add_model(|_| Model);
2703
2704 observing_view.update(app, |_, ctx| {
2705 ctx.observe(&observed_model, |_, _, _| {});
2706 });
2707 observing_model.update(app, |_, ctx| {
2708 ctx.observe(&observed_model, |_, _, _| {});
2709 });
2710
2711 app.update(|_| {
2712 drop(observing_view);
2713 drop(observing_model);
2714 });
2715
2716 observed_model.update(app, |_, ctx| ctx.notify());
2717 }
2718
2719 #[test]
2720 fn test_focus() {
2721 #[derive(Default)]
2722 struct View {
2723 events: Vec<String>,
2724 }
2725
2726 impl Entity for View {
2727 type Event = String;
2728 }
2729
2730 impl super::View for View {
2731 fn render<'a>(&self, _: &AppContext) -> Box<dyn Element> {
2732 Empty::new().boxed()
2733 }
2734
2735 fn ui_name() -> &'static str {
2736 "View"
2737 }
2738
2739 fn on_focus(&mut self, ctx: &mut ViewContext<Self>) {
2740 self.events.push("self focused".into());
2741 ctx.emit("focused".into());
2742 }
2743
2744 fn on_blur(&mut self, ctx: &mut ViewContext<Self>) {
2745 self.events.push("self blurred".into());
2746 ctx.emit("blurred".into());
2747 }
2748 }
2749
2750 let mut app = App::new().unwrap();
2751 let app = &mut app;
2752 let (window_id, view_1) = app.add_window(|_| View::default());
2753 let view_2 = app.add_view(window_id, |_| View::default());
2754
2755 view_1.update(app, |_, ctx| {
2756 ctx.subscribe_to_view(&view_2, |view_1, _, event, _| {
2757 view_1.events.push(format!("view 2 {}", event));
2758 });
2759 ctx.focus(&view_2);
2760 });
2761
2762 view_1.update(app, |_, ctx| {
2763 ctx.focus(&view_1);
2764 });
2765
2766 view_1.read(app, |view_1, _| {
2767 assert_eq!(
2768 view_1.events,
2769 [
2770 "self focused".to_string(),
2771 "self blurred".to_string(),
2772 "view 2 focused".to_string(),
2773 "self focused".to_string(),
2774 "view 2 blurred".to_string(),
2775 ],
2776 );
2777 });
2778 }
2779
2780 #[test]
2781 fn test_spawn_from_view() {
2782 #[derive(Default)]
2783 struct View {
2784 count: usize,
2785 }
2786
2787 impl Entity for View {
2788 type Event = ();
2789 }
2790
2791 impl super::View for View {
2792 fn render<'a>(&self, _: &AppContext) -> Box<dyn Element> {
2793 Empty::new().boxed()
2794 }
2795
2796 fn ui_name() -> &'static str {
2797 "View"
2798 }
2799 }
2800
2801 App::test(|mut app| async move {
2802 let (_, handle) = app.add_window(|_| View::default());
2803 handle
2804 .update(&mut app, |_, c| {
2805 c.spawn_local(async { 7 }, |me, output, _| {
2806 me.count = output;
2807 })
2808 })
2809 .await;
2810 handle.read(&app, |view, _| assert_eq!(view.count, 7));
2811 handle
2812 .update(&mut app, |_, c| {
2813 c.spawn(async { 14 }, |me, output, _| {
2814 me.count = output;
2815 })
2816 })
2817 .await;
2818 handle.read(&app, |view, _| assert_eq!(view.count, 14));
2819 });
2820 }
2821
2822 #[test]
2823 fn test_spawn_stream_local_from_view() {
2824 #[derive(Default)]
2825 struct View {
2826 events: Vec<Option<usize>>,
2827 }
2828
2829 impl Entity for View {
2830 type Event = ();
2831 }
2832
2833 impl super::View for View {
2834 fn render<'a>(&self, _: &AppContext) -> Box<dyn Element> {
2835 Empty::new().boxed()
2836 }
2837
2838 fn ui_name() -> &'static str {
2839 "View"
2840 }
2841 }
2842
2843 App::test(|mut app| async move {
2844 let (_, handle) = app.add_window(|_| View::default());
2845 handle
2846 .update(&mut app, |_, c| {
2847 c.spawn_stream_local(smol::stream::iter(vec![1, 2, 3]), |me, output, _| {
2848 me.events.push(output);
2849 })
2850 })
2851 .await;
2852
2853 handle.read(&app, |view, _| {
2854 assert_eq!(view.events, [Some(1), Some(2), Some(3), None])
2855 });
2856 });
2857 }
2858
2859 #[test]
2860 fn test_dispatch_action() {
2861 struct ViewA {
2862 id: usize,
2863 }
2864
2865 impl Entity for ViewA {
2866 type Event = ();
2867 }
2868
2869 impl View for ViewA {
2870 fn render<'a>(&self, _: &AppContext) -> Box<dyn Element> {
2871 Empty::new().boxed()
2872 }
2873
2874 fn ui_name() -> &'static str {
2875 "View"
2876 }
2877 }
2878
2879 struct ViewB {
2880 id: usize,
2881 }
2882
2883 impl Entity for ViewB {
2884 type Event = ();
2885 }
2886
2887 impl View for ViewB {
2888 fn render<'a>(&self, _: &AppContext) -> Box<dyn Element> {
2889 Empty::new().boxed()
2890 }
2891
2892 fn ui_name() -> &'static str {
2893 "View"
2894 }
2895 }
2896
2897 struct ActionArg {
2898 foo: String,
2899 }
2900
2901 let mut app = App::new().unwrap();
2902 let actions = Rc::new(RefCell::new(Vec::new()));
2903
2904 let actions_clone = actions.clone();
2905 app.add_global_action("action", move |_: &ActionArg, _: &mut MutableAppContext| {
2906 actions_clone.borrow_mut().push("global a".to_string());
2907 });
2908
2909 let actions_clone = actions.clone();
2910 app.add_global_action("action", move |_: &ActionArg, _: &mut MutableAppContext| {
2911 actions_clone.borrow_mut().push("global b".to_string());
2912 });
2913
2914 let actions_clone = actions.clone();
2915 app.add_action("action", move |view: &mut ViewA, arg: &ActionArg, ctx| {
2916 assert_eq!(arg.foo, "bar");
2917 ctx.propagate_action();
2918 actions_clone.borrow_mut().push(format!("{} a", view.id));
2919 });
2920
2921 let actions_clone = actions.clone();
2922 app.add_action("action", move |view: &mut ViewA, _: &ActionArg, ctx| {
2923 if view.id != 1 {
2924 ctx.propagate_action();
2925 }
2926 actions_clone.borrow_mut().push(format!("{} b", view.id));
2927 });
2928
2929 let actions_clone = actions.clone();
2930 app.add_action("action", move |view: &mut ViewB, _: &ActionArg, ctx| {
2931 ctx.propagate_action();
2932 actions_clone.borrow_mut().push(format!("{} c", view.id));
2933 });
2934
2935 let actions_clone = actions.clone();
2936 app.add_action("action", move |view: &mut ViewB, _: &ActionArg, ctx| {
2937 ctx.propagate_action();
2938 actions_clone.borrow_mut().push(format!("{} d", view.id));
2939 });
2940
2941 let (window_id, view_1) = app.add_window(|_| ViewA { id: 1 });
2942 let view_2 = app.add_view(window_id, |_| ViewB { id: 2 });
2943 let view_3 = app.add_view(window_id, |_| ViewA { id: 3 });
2944 let view_4 = app.add_view(window_id, |_| ViewB { id: 4 });
2945
2946 app.dispatch_action(
2947 window_id,
2948 vec![view_1.id(), view_2.id(), view_3.id(), view_4.id()],
2949 "action",
2950 ActionArg { foo: "bar".into() },
2951 );
2952
2953 assert_eq!(
2954 *actions.borrow(),
2955 vec!["4 d", "4 c", "3 b", "3 a", "2 d", "2 c", "1 b"]
2956 );
2957
2958 // Remove view_1, which doesn't propagate the action
2959 actions.borrow_mut().clear();
2960 app.dispatch_action(
2961 window_id,
2962 vec![view_2.id(), view_3.id(), view_4.id()],
2963 "action",
2964 ActionArg { foo: "bar".into() },
2965 );
2966
2967 assert_eq!(
2968 *actions.borrow(),
2969 vec!["4 d", "4 c", "3 b", "3 a", "2 d", "2 c", "global b", "global a"]
2970 );
2971 }
2972
2973 #[test]
2974 fn test_dispatch_keystroke() -> Result<()> {
2975 use std::cell::Cell;
2976
2977 #[derive(Clone)]
2978 struct ActionArg {
2979 key: String,
2980 }
2981
2982 struct View {
2983 id: usize,
2984 keymap_context: keymap::Context,
2985 }
2986
2987 impl Entity for View {
2988 type Event = ();
2989 }
2990
2991 impl super::View for View {
2992 fn render<'a>(&self, _: &AppContext) -> Box<dyn Element> {
2993 Empty::new().boxed()
2994 }
2995
2996 fn ui_name() -> &'static str {
2997 "View"
2998 }
2999
3000 fn keymap_context(&self, _: &AppContext) -> keymap::Context {
3001 self.keymap_context.clone()
3002 }
3003 }
3004
3005 impl View {
3006 fn new(id: usize) -> Self {
3007 View {
3008 id,
3009 keymap_context: keymap::Context::default(),
3010 }
3011 }
3012 }
3013
3014 let mut app = App::new().unwrap();
3015
3016 let mut view_1 = View::new(1);
3017 let mut view_2 = View::new(2);
3018 let mut view_3 = View::new(3);
3019 view_1.keymap_context.set.insert("a".into());
3020 view_2.keymap_context.set.insert("b".into());
3021 view_3.keymap_context.set.insert("c".into());
3022
3023 let (window_id, view_1) = app.add_window(|_| view_1);
3024 let view_2 = app.add_view(window_id, |_| view_2);
3025 let view_3 = app.add_view(window_id, |_| view_3);
3026
3027 // This keymap's only binding dispatches an action on view 2 because that view will have
3028 // "a" and "b" in its context, but not "c".
3029 let binding = keymap::Binding::new("a", "action", Some("a && b && !c"))
3030 .with_arg(ActionArg { key: "a".into() });
3031 app.add_bindings(vec![binding]);
3032
3033 let handled_action = Rc::new(Cell::new(false));
3034 let handled_action_clone = handled_action.clone();
3035 app.add_action("action", move |view: &mut View, arg: &ActionArg, _ctx| {
3036 handled_action_clone.set(true);
3037 assert_eq!(view.id, 2);
3038 assert_eq!(arg.key, "a");
3039 });
3040
3041 app.dispatch_keystroke(
3042 window_id,
3043 vec![view_1.id(), view_2.id(), view_3.id()],
3044 &Keystroke::parse("a")?,
3045 )?;
3046
3047 assert!(handled_action.get());
3048 Ok(())
3049 }
3050
3051 // #[test]
3052 // fn test_ui_and_window_updates() {
3053 // struct View {
3054 // count: usize,
3055 // }
3056
3057 // impl Entity for View {
3058 // type Event = ();
3059 // }
3060
3061 // impl super::View for View {
3062 // fn render<'a>(&self, _: &AppContext) -> Box<dyn Element> {
3063 // Empty::new().boxed()
3064 // }
3065
3066 // fn ui_name() -> &'static str {
3067 // "View"
3068 // }
3069 // }
3070
3071 // App::test(|mut app| async move {
3072 // let (window_id, _) = app.add_window(|_| View { count: 3 });
3073 // let view_1 = app.add_view(window_id, |_| View { count: 1 });
3074 // let view_2 = app.add_view(window_id, |_| View { count: 2 });
3075
3076 // // Ensure that registering for UI updates after mutating the app still gives us all the
3077 // // updates.
3078 // let ui_updates = Rc::new(RefCell::new(Vec::new()));
3079 // let ui_updates_ = ui_updates.clone();
3080 // app.on_ui_update(move |update, _| ui_updates_.borrow_mut().push(update));
3081
3082 // assert_eq!(
3083 // ui_updates.borrow_mut().drain(..).collect::<Vec<_>>(),
3084 // vec![UiUpdate::OpenWindow {
3085 // window_id,
3086 // width: 1024.0,
3087 // height: 768.0,
3088 // }]
3089 // );
3090
3091 // let window_invalidations = Rc::new(RefCell::new(Vec::new()));
3092 // let window_invalidations_ = window_invalidations.clone();
3093 // app.on_window_invalidated(window_id, move |update, _| {
3094 // window_invalidations_.borrow_mut().push(update)
3095 // });
3096
3097 // let view_2_id = view_2.id();
3098 // view_1.update(&mut app, |view, ctx| {
3099 // view.count = 7;
3100 // ctx.notify();
3101 // drop(view_2);
3102 // });
3103
3104 // let invalidation = window_invalidations.borrow_mut().drain(..).next().unwrap();
3105 // assert_eq!(invalidation.updated.len(), 1);
3106 // assert!(invalidation.updated.contains(&view_1.id()));
3107 // assert_eq!(invalidation.removed, vec![view_2_id]);
3108
3109 // let view_3 = view_1.update(&mut app, |_, ctx| ctx.add_view(|_| View { count: 8 }));
3110
3111 // let invalidation = window_invalidations.borrow_mut().drain(..).next().unwrap();
3112 // assert_eq!(invalidation.updated.len(), 1);
3113 // assert!(invalidation.updated.contains(&view_3.id()));
3114 // assert!(invalidation.removed.is_empty());
3115
3116 // view_3
3117 // .update(&mut app, |_, ctx| {
3118 // ctx.spawn_local(async { 9 }, |me, output, ctx| {
3119 // me.count = output;
3120 // ctx.notify();
3121 // })
3122 // })
3123 // .await;
3124
3125 // let invalidation = window_invalidations.borrow_mut().drain(..).next().unwrap();
3126 // assert_eq!(invalidation.updated.len(), 1);
3127 // assert!(invalidation.updated.contains(&view_3.id()));
3128 // assert!(invalidation.removed.is_empty());
3129 // });
3130 // }
3131
3132 #[test]
3133 fn test_finish_pending_tasks() {
3134 struct View;
3135
3136 impl Entity for View {
3137 type Event = ();
3138 }
3139
3140 impl super::View for View {
3141 fn render<'a>(&self, _: &AppContext) -> Box<dyn Element> {
3142 Empty::new().boxed()
3143 }
3144
3145 fn ui_name() -> &'static str {
3146 "View"
3147 }
3148 }
3149
3150 struct Model;
3151
3152 impl Entity for Model {
3153 type Event = ();
3154 }
3155
3156 App::test(|mut app| async move {
3157 let model = app.add_model(|_| Model);
3158 let (_, view) = app.add_window(|_| View);
3159
3160 model.update(&mut app, |_, ctx| {
3161 let _ = ctx.spawn(async {}, |_, _, _| {});
3162 let _ = ctx.spawn_local(async {}, |_, _, _| {});
3163 let _ = ctx.spawn_stream_local(smol::stream::iter(vec![1, 2, 3]), |_, _, _| {});
3164 });
3165
3166 view.update(&mut app, |_, ctx| {
3167 let _ = ctx.spawn(async {}, |_, _, _| {});
3168 let _ = ctx.spawn_local(async {}, |_, _, _| {});
3169 let _ = ctx.spawn_stream_local(smol::stream::iter(vec![1, 2, 3]), |_, _, _| {});
3170 });
3171
3172 assert!(!app.0.borrow().task_callbacks.is_empty());
3173 app.finish_pending_tasks().await;
3174 assert!(app.0.borrow().task_callbacks.is_empty());
3175 app.finish_pending_tasks().await; // Don't block if there are no tasks
3176 });
3177 }
3178}