1use crate::{
2 AppContext, Context, Effect, EntityId, EventEmitter, Executor, Handle, Reference, Subscription,
3 WeakHandle,
4};
5use std::marker::PhantomData;
6
7pub struct ModelContext<'a, T> {
8 app: Reference<'a, AppContext>,
9 entity_type: PhantomData<T>,
10 entity_id: EntityId,
11}
12
13impl<'a, T: Send + Sync + 'static> ModelContext<'a, T> {
14 pub(crate) fn mutable(app: &'a mut AppContext, entity_id: EntityId) -> Self {
15 Self {
16 app: Reference::Mutable(app),
17 entity_type: PhantomData,
18 entity_id,
19 }
20 }
21
22 // todo!
23 // fn update<R>(&mut self, update: impl FnOnce(&mut T, &mut Self) -> R) -> R {
24 // let mut entity = self
25 // .app
26 // .entities
27 // .get_mut(self.entity_id)
28 // .unwrap()
29 // .take()
30 // .unwrap();
31 // let result = update(entity.downcast_mut::<T>().unwrap(), self);
32 // self.app
33 // .entities
34 // .get_mut(self.entity_id)
35 // .unwrap()
36 // .replace(entity);
37 // result
38 // }
39
40 pub fn handle(&self) -> WeakHandle<T> {
41 self.app.entities.weak_handle(self.entity_id)
42 }
43
44 pub fn observe<E: Send + Sync + 'static>(
45 &mut self,
46 handle: &Handle<E>,
47 on_notify: impl Fn(&mut T, Handle<E>, &mut ModelContext<'_, T>) + Send + Sync + 'static,
48 ) -> Subscription {
49 let this = self.handle();
50 let handle = handle.downgrade();
51 self.app.observers.insert(
52 handle.id,
53 Box::new(move |cx| {
54 if let Some((this, handle)) = this.upgrade().zip(handle.upgrade()) {
55 this.update(cx, |this, cx| on_notify(this, handle, cx));
56 true
57 } else {
58 false
59 }
60 }),
61 )
62 }
63
64 pub fn subscribe<E: EventEmitter + Send + Sync + 'static>(
65 &mut self,
66 handle: &Handle<E>,
67 on_event: impl Fn(&mut T, Handle<E>, &E::Event, &mut ModelContext<'_, T>)
68 + Send
69 + Sync
70 + 'static,
71 ) -> Subscription {
72 let this = self.handle();
73 let handle = handle.downgrade();
74 self.app.event_handlers.insert(
75 handle.id,
76 Box::new(move |event, cx| {
77 let event = event.downcast_ref().expect("invalid event type");
78 if let Some((this, handle)) = this.upgrade().zip(handle.upgrade()) {
79 this.update(cx, |this, cx| on_event(this, handle, event, cx));
80 true
81 } else {
82 false
83 }
84 }),
85 )
86 }
87
88 pub fn on_release(
89 &mut self,
90 on_release: impl Fn(&mut T, &mut AppContext) + Send + Sync + 'static,
91 ) -> Subscription {
92 self.app.release_handlers.insert(
93 self.entity_id,
94 Box::new(move |this, cx| {
95 let this = this.downcast_mut().expect("invalid entity type");
96 on_release(this, cx);
97 }),
98 )
99 }
100
101 pub fn observe_release<E: Send + Sync + 'static>(
102 &mut self,
103 handle: &Handle<E>,
104 on_release: impl Fn(&mut T, &mut E, &mut ModelContext<'_, T>) + Send + Sync + 'static,
105 ) -> Subscription {
106 let this = self.handle();
107 self.app.release_handlers.insert(
108 handle.id,
109 Box::new(move |entity, cx| {
110 let entity = entity.downcast_mut().expect("invalid entity type");
111 if let Some(this) = this.upgrade() {
112 this.update(cx, |this, cx| on_release(this, entity, cx));
113 }
114 }),
115 )
116 }
117
118 pub fn notify(&mut self) {
119 self.app.push_effect(Effect::Notify {
120 emitter: self.entity_id,
121 });
122 }
123}
124
125impl<'a, T: EventEmitter + Send + Sync + 'static> ModelContext<'a, T> {
126 pub fn emit(&mut self, event: T::Event) {
127 self.app.push_effect(Effect::Emit {
128 emitter: self.entity_id,
129 event: Box::new(event),
130 });
131 }
132}
133
134impl<'a, T: 'static> Context for ModelContext<'a, T> {
135 type BorrowedContext<'b, 'c> = ModelContext<'b, T>;
136 type EntityContext<'b, 'c, U: Send + Sync + 'static> = ModelContext<'b, U>;
137 type Result<U> = U;
138
139 fn refresh(&mut self) {
140 self.app.refresh();
141 }
142
143 fn entity<U: Send + Sync + 'static>(
144 &mut self,
145 build_entity: impl FnOnce(&mut Self::EntityContext<'_, '_, U>) -> U,
146 ) -> Handle<U> {
147 self.app.entity(build_entity)
148 }
149
150 fn update_entity<U: Send + Sync + 'static, R>(
151 &mut self,
152 handle: &Handle<U>,
153 update: impl FnOnce(&mut U, &mut Self::EntityContext<'_, '_, U>) -> R,
154 ) -> R {
155 self.app.update_entity(handle, update)
156 }
157
158 fn read_global<G: 'static + Send + Sync, R>(
159 &self,
160 read: impl FnOnce(&G, &Self::BorrowedContext<'_, '_>) -> R,
161 ) -> R {
162 read(self.app.global(), self)
163 }
164
165 fn update_global<G, R>(&mut self, f: impl FnOnce(&mut G, &mut Self) -> R) -> R
166 where
167 G: 'static + Send + Sync,
168 {
169 let mut global = self.app.pop_global::<G>();
170 let result = f(global.as_mut(), self);
171 self.app.push_global(global);
172 result
173 }
174}