1use crate::{
2 AnyView, AnyWindowHandle, AppContext, AsyncAppContext, Context, Effect, Entity, EntityId,
3 EventEmitter, 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<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 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>) + 'static,
71 ) -> Subscription
72 where
73 T: 'static,
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 on_release: impl FnOnce(&mut T, &mut AppContext) + '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 on_release: impl FnOnce(&mut T, &mut T2, &mut ModelContext<'_, T>) + 'static,
114 ) -> Subscription
115 where
116 T: Any,
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>) + 'static,
136 ) -> Subscription
137 where
138 T: 'static,
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 + 'static,
150 ) -> Subscription
151 where
152 Fut: 'static + Future<Output = ()>,
153 T: 'static,
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_local()
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,
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> + 'static,
196 R: 'static,
197 {
198 let this = self.weak_model();
199 self.app.spawn(|cx| f(this, cx))
200 }
201}
202
203impl<'a, T> ModelContext<'a, T>
204where
205 T: EventEmitter,
206{
207 pub fn emit(&mut self, event: T::Event) {
208 self.app.pending_effects.push_back(Effect::Emit {
209 emitter: self.model_state.entity_id,
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
241impl<T> Borrow<AppContext> for ModelContext<'_, T> {
242 fn borrow(&self) -> &AppContext {
243 &self.app
244 }
245}
246
247impl<T> BorrowMut<AppContext> for ModelContext<'_, T> {
248 fn borrow_mut(&mut self) -> &mut AppContext {
249 &mut self.app
250 }
251}