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