1use crate::{AppContext, Context, Effect, EntityId, EventEmitter, Handle, Reference, WeakHandle};
2use std::{marker::PhantomData, sync::Arc};
3
4pub struct ModelContext<'a, T> {
5 app: Reference<'a, AppContext>,
6 entity_type: PhantomData<T>,
7 entity_id: EntityId,
8}
9
10impl<'a, T: Send + Sync + 'static> ModelContext<'a, T> {
11 pub(crate) fn mutable(app: &'a mut AppContext, entity_id: EntityId) -> Self {
12 Self {
13 app: Reference::Mutable(app),
14 entity_type: PhantomData,
15 entity_id,
16 }
17 }
18
19 // todo!
20 // fn update<R>(&mut self, update: impl FnOnce(&mut T, &mut Self) -> R) -> R {
21 // let mut entity = self
22 // .app
23 // .entities
24 // .get_mut(self.entity_id)
25 // .unwrap()
26 // .take()
27 // .unwrap();
28 // let result = update(entity.downcast_mut::<T>().unwrap(), self);
29 // self.app
30 // .entities
31 // .get_mut(self.entity_id)
32 // .unwrap()
33 // .replace(entity);
34 // result
35 // }
36
37 pub fn handle(&self) -> WeakHandle<T> {
38 self.app.entities.weak_handle(self.entity_id)
39 }
40
41 pub fn observe<E: Send + Sync + 'static>(
42 &mut self,
43 handle: &Handle<E>,
44 on_notify: impl Fn(&mut T, Handle<E>, &mut ModelContext<'_, T>) + Send + Sync + 'static,
45 ) {
46 let this = self.handle();
47 let handle = handle.downgrade();
48 self.app
49 .observers
50 .entry(handle.id)
51 .or_default()
52 .push(Arc::new(move |cx| {
53 if let Some((this, handle)) = this.upgrade(cx).zip(handle.upgrade(cx)) {
54 this.update(cx, |this, cx| on_notify(this, handle, cx));
55 true
56 } else {
57 false
58 }
59 }));
60 }
61
62 pub fn subscribe<E: EventEmitter + Send + Sync + 'static>(
63 &mut self,
64 handle: &Handle<E>,
65 on_event: impl Fn(&mut T, Handle<E>, &E::Event, &mut ModelContext<'_, T>)
66 + Send
67 + Sync
68 + 'static,
69 ) {
70 let this = self.handle();
71 let handle = handle.downgrade();
72 self.app
73 .event_handlers
74 .entry(handle.id)
75 .or_default()
76 .push(Arc::new(move |event, cx| {
77 let event = event.downcast_ref().expect("invalid event type");
78 if let Some((this, handle)) = this.upgrade(cx).zip(handle.upgrade(cx)) {
79 this.update(cx, |this, cx| on_event(this, handle, event, cx));
80 true
81 } else {
82 false
83 }
84 }));
85 }
86
87 pub fn notify(&mut self) {
88 self.app
89 .pending_effects
90 .push_back(Effect::Notify(self.entity_id));
91 }
92}
93
94impl<'a, T: EventEmitter + Send + Sync + 'static> ModelContext<'a, T> {
95 pub fn emit(&mut self, event: T::Event) {
96 self.app.pending_effects.push_back(Effect::Emit {
97 entity_id: self.entity_id,
98 event: Box::new(event),
99 });
100 }
101}
102
103impl<'a, T: 'static> Context for ModelContext<'a, T> {
104 type EntityContext<'b, 'c, U: Send + Sync + 'static> = ModelContext<'b, U>;
105 type Result<U> = U;
106
107 fn entity<U: Send + Sync + 'static>(
108 &mut self,
109 build_entity: impl FnOnce(&mut Self::EntityContext<'_, '_, U>) -> U,
110 ) -> Handle<U> {
111 self.app.entity(build_entity)
112 }
113
114 fn update_entity<U: Send + Sync + 'static, R>(
115 &mut self,
116 handle: &Handle<U>,
117 update: impl FnOnce(&mut U, &mut Self::EntityContext<'_, '_, U>) -> R,
118 ) -> R {
119 self.app.update_entity(handle, update)
120 }
121}