1use crate::{
2 AppContext, AsyncAppContext, Context, Effect, EntityId, EventEmitter, Handle, MainThread,
3 Reference, Subscription, Task, WeakHandle,
4};
5use derive_more::{Deref, DerefMut};
6use futures::FutureExt;
7use std::{
8 any::{Any, TypeId},
9 borrow::{Borrow, BorrowMut},
10 future::Future,
11};
12
13#[derive(Deref, DerefMut)]
14pub struct ModelContext<'a, T> {
15 #[deref]
16 #[deref_mut]
17 app: Reference<'a, AppContext>,
18 model_state: WeakHandle<T>,
19}
20
21impl<'a, T: 'static> ModelContext<'a, T> {
22 pub(crate) fn mutable(app: &'a mut AppContext, model_state: WeakHandle<T>) -> Self {
23 Self {
24 app: Reference::Mutable(app),
25 model_state,
26 }
27 }
28
29 pub fn entity_id(&self) -> EntityId {
30 self.model_state.entity_id
31 }
32
33 pub fn handle(&self) -> Handle<T> {
34 self.weak_handle()
35 .upgrade()
36 .expect("The entity must be alive if we have a model context")
37 }
38
39 pub fn weak_handle(&self) -> WeakHandle<T> {
40 self.model_state.clone()
41 }
42
43 pub fn observe<T2: 'static>(
44 &mut self,
45 handle: &Handle<T2>,
46 mut on_notify: impl FnMut(&mut T, Handle<T2>, &mut ModelContext<'_, T>) + Send + Sync + 'static,
47 ) -> Subscription
48 where
49 T: Any + Send + Sync,
50 {
51 let this = self.weak_handle();
52 let handle = handle.downgrade();
53 self.app.observers.insert(
54 handle.entity_id,
55 Box::new(move |cx| {
56 if let Some((this, handle)) = this.upgrade().zip(handle.upgrade()) {
57 this.update(cx, |this, cx| on_notify(this, handle, cx));
58 true
59 } else {
60 false
61 }
62 }),
63 )
64 }
65
66 pub fn subscribe<E: 'static + EventEmitter>(
67 &mut self,
68 handle: &Handle<E>,
69 mut on_event: impl FnMut(&mut T, Handle<E>, &E::Event, &mut ModelContext<'_, T>)
70 + Send
71 + Sync
72 + 'static,
73 ) -> Subscription
74 where
75 T: Any + Send + Sync,
76 {
77 let this = self.weak_handle();
78 let handle = handle.downgrade();
79 self.app.event_listeners.insert(
80 handle.entity_id,
81 Box::new(move |event, cx| {
82 let event = event.downcast_ref().expect("invalid event type");
83 if let Some((this, handle)) = this.upgrade().zip(handle.upgrade()) {
84 this.update(cx, |this, cx| on_event(this, handle, event, cx));
85 true
86 } else {
87 false
88 }
89 }),
90 )
91 }
92
93 pub fn on_release(
94 &mut self,
95 mut on_release: impl FnMut(&mut T, &mut AppContext) + Send + Sync + 'static,
96 ) -> Subscription
97 where
98 T: 'static,
99 {
100 self.app.release_listeners.insert(
101 self.model_state.entity_id,
102 Box::new(move |this, cx| {
103 let this = this.downcast_mut().expect("invalid entity type");
104 on_release(this, cx);
105 }),
106 )
107 }
108
109 pub fn observe_release<E: 'static>(
110 &mut self,
111 handle: &Handle<E>,
112 mut on_release: impl FnMut(&mut T, &mut E, &mut ModelContext<'_, T>) + Send + Sync + 'static,
113 ) -> Subscription
114 where
115 T: Any + Send + Sync,
116 {
117 let this = self.weak_handle();
118 self.app.release_listeners.insert(
119 handle.entity_id,
120 Box::new(move |entity, cx| {
121 let entity = entity.downcast_mut().expect("invalid entity type");
122 if let Some(this) = this.upgrade() {
123 this.update(cx, |this, cx| on_release(this, entity, cx));
124 }
125 }),
126 )
127 }
128
129 pub fn observe_global<G: 'static>(
130 &mut self,
131 mut f: impl FnMut(&mut T, &mut ModelContext<'_, T>) + Send + Sync + 'static,
132 ) -> Subscription
133 where
134 T: Any + Send + Sync,
135 {
136 let handle = self.weak_handle();
137 self.global_observers.insert(
138 TypeId::of::<G>(),
139 Box::new(move |cx| handle.update(cx, |view, cx| f(view, cx)).is_ok()),
140 )
141 }
142
143 pub fn on_app_quit<Fut>(
144 &mut self,
145 mut on_quit: impl FnMut(&mut T, &mut ModelContext<T>) -> Fut + Send + Sync + 'static,
146 ) -> Subscription
147 where
148 Fut: 'static + Future<Output = ()> + Send,
149 T: Any + Send + Sync,
150 {
151 let handle = self.weak_handle();
152 self.app.quit_observers.insert(
153 (),
154 Box::new(move |cx| {
155 let future = handle.update(cx, |entity, cx| on_quit(entity, cx)).ok();
156 async move {
157 if let Some(future) = future {
158 future.await;
159 }
160 }
161 .boxed()
162 }),
163 )
164 }
165
166 pub fn notify(&mut self) {
167 if self
168 .app
169 .pending_notifications
170 .insert(self.model_state.entity_id)
171 {
172 self.app.pending_effects.push_back(Effect::Notify {
173 emitter: self.model_state.entity_id,
174 });
175 }
176 }
177
178 pub fn update_global<G, R>(&mut self, f: impl FnOnce(&mut G, &mut Self) -> R) -> R
179 where
180 G: 'static + Send + Sync,
181 {
182 let mut global = self.app.lease_global::<G>();
183 let result = f(&mut global, self);
184 self.app.end_global_lease(global);
185 result
186 }
187
188 pub fn spawn<Fut, R>(
189 &self,
190 f: impl FnOnce(WeakHandle<T>, AsyncAppContext) -> Fut + Send + 'static,
191 ) -> Task<R>
192 where
193 T: 'static,
194 Fut: Future<Output = R> + Send + 'static,
195 R: Send + 'static,
196 {
197 let this = self.weak_handle();
198 self.app.spawn(|cx| f(this, cx))
199 }
200
201 pub fn spawn_on_main<Fut, R>(
202 &self,
203 f: impl FnOnce(WeakHandle<T>, MainThread<AsyncAppContext>) -> Fut + Send + 'static,
204 ) -> Task<R>
205 where
206 Fut: Future<Output = R> + 'static,
207 R: Send + 'static,
208 {
209 let this = self.weak_handle();
210 self.app.spawn_on_main(|cx| f(this, cx))
211 }
212}
213
214impl<'a, T> ModelContext<'a, T>
215where
216 T: EventEmitter,
217 T::Event: Send + Sync,
218{
219 pub fn emit(&mut self, event: T::Event) {
220 self.app.pending_effects.push_back(Effect::Emit {
221 emitter: self.model_state.entity_id,
222 event: Box::new(event),
223 });
224 }
225}
226
227impl<'a, T> Context for ModelContext<'a, T> {
228 type EntityContext<'b, 'c, U> = ModelContext<'b, U>;
229 type Result<U> = U;
230
231 fn entity<U>(
232 &mut self,
233 build_entity: impl FnOnce(&mut Self::EntityContext<'_, '_, U>) -> U,
234 ) -> Handle<U>
235 where
236 U: 'static + Send + Sync,
237 {
238 self.app.entity(build_entity)
239 }
240
241 fn update_entity<U: 'static, R>(
242 &mut self,
243 handle: &Handle<U>,
244 update: impl FnOnce(&mut U, &mut Self::EntityContext<'_, '_, U>) -> R,
245 ) -> R {
246 self.app.update_entity(handle, update)
247 }
248}
249
250impl<T> Borrow<AppContext> for ModelContext<'_, T> {
251 fn borrow(&self) -> &AppContext {
252 &self.app
253 }
254}
255
256impl<T> BorrowMut<AppContext> for ModelContext<'_, T> {
257 fn borrow_mut(&mut self) -> &mut AppContext {
258 &mut self.app
259 }
260}