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