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