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