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 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>(
63 &mut self,
64 entity: &E,
65 mut on_event: impl FnMut(&mut T, E, &T2::Event, &mut ModelContext<'_, T>) + 'static,
66 ) -> Subscription
67 where
68 T: 'static,
69 T2: 'static + EventEmitter,
70 E: Entity<T2>,
71 {
72 let this = self.weak_model();
73 self.app.subscribe_internal(entity, move |e, event, cx| {
74 if let Some(this) = this.upgrade() {
75 this.update(cx, |this, cx| on_event(this, e, event, cx));
76 true
77 } else {
78 false
79 }
80 })
81 }
82
83 pub fn on_release(
84 &mut self,
85 on_release: impl FnOnce(&mut T, &mut AppContext) + 'static,
86 ) -> Subscription
87 where
88 T: 'static,
89 {
90 self.app.release_listeners.insert(
91 self.model_state.entity_id,
92 Box::new(move |this, cx| {
93 let this = this.downcast_mut().expect("invalid entity type");
94 on_release(this, cx);
95 }),
96 )
97 }
98
99 pub fn observe_release<T2, E>(
100 &mut self,
101 entity: &E,
102 on_release: impl FnOnce(&mut T, &mut T2, &mut ModelContext<'_, T>) + 'static,
103 ) -> Subscription
104 where
105 T: Any,
106 T2: 'static,
107 E: Entity<T2>,
108 {
109 let entity_id = entity.entity_id();
110 let this = self.weak_model();
111 self.app.release_listeners.insert(
112 entity_id,
113 Box::new(move |entity, cx| {
114 let entity = entity.downcast_mut().expect("invalid entity type");
115 if let Some(this) = this.upgrade() {
116 this.update(cx, |this, cx| on_release(this, entity, cx));
117 }
118 }),
119 )
120 }
121
122 pub fn observe_global<G: 'static>(
123 &mut self,
124 mut f: impl FnMut(&mut T, &mut ModelContext<'_, T>) + 'static,
125 ) -> Subscription
126 where
127 T: 'static,
128 {
129 let handle = self.weak_model();
130 self.global_observers.insert(
131 TypeId::of::<G>(),
132 Box::new(move |cx| handle.update(cx, |view, cx| f(view, cx)).is_ok()),
133 )
134 }
135
136 pub fn on_app_quit<Fut>(
137 &mut self,
138 mut on_quit: impl FnMut(&mut T, &mut ModelContext<T>) -> Fut + 'static,
139 ) -> Subscription
140 where
141 Fut: 'static + Future<Output = ()>,
142 T: 'static,
143 {
144 let handle = self.weak_model();
145 self.app.quit_observers.insert(
146 (),
147 Box::new(move |cx| {
148 let future = handle.update(cx, |entity, cx| on_quit(entity, cx)).ok();
149 async move {
150 if let Some(future) = future {
151 future.await;
152 }
153 }
154 .boxed_local()
155 }),
156 )
157 }
158
159 pub fn notify(&mut self) {
160 if self
161 .app
162 .pending_notifications
163 .insert(self.model_state.entity_id)
164 {
165 self.app.pending_effects.push_back(Effect::Notify {
166 emitter: self.model_state.entity_id,
167 });
168 }
169 }
170
171 pub fn update_global<G, R>(&mut self, f: impl FnOnce(&mut G, &mut Self) -> R) -> R
172 where
173 G: 'static,
174 {
175 let mut global = self.app.lease_global::<G>();
176 let result = f(&mut global, self);
177 self.app.end_global_lease(global);
178 result
179 }
180
181 pub fn spawn<Fut, R>(&self, f: impl FnOnce(WeakModel<T>, AsyncAppContext) -> Fut) -> Task<R>
182 where
183 T: 'static,
184 Fut: Future<Output = R> + 'static,
185 R: 'static,
186 {
187 let this = self.weak_model();
188 self.app.spawn(|cx| f(this, cx))
189 }
190}
191
192impl<'a, T> ModelContext<'a, T>
193where
194 T: EventEmitter,
195{
196 pub fn emit(&mut self, event: T::Event) {
197 self.app.pending_effects.push_back(Effect::Emit {
198 emitter: self.model_state.entity_id,
199 event: Box::new(event),
200 });
201 }
202}
203
204impl<'a, T> Context for ModelContext<'a, T> {
205 type Result<U> = U;
206
207 fn build_model<U: 'static>(
208 &mut self,
209 build_model: impl FnOnce(&mut ModelContext<'_, U>) -> U,
210 ) -> Model<U> {
211 self.app.build_model(build_model)
212 }
213
214 fn update_model<U: 'static, R>(
215 &mut self,
216 handle: &Model<U>,
217 update: impl FnOnce(&mut U, &mut ModelContext<'_, U>) -> R,
218 ) -> R {
219 self.app.update_model(handle, update)
220 }
221
222 fn update_window<R, F>(&mut self, window: AnyWindowHandle, update: F) -> Result<R>
223 where
224 F: FnOnce(AnyView, &mut WindowContext<'_>) -> R,
225 {
226 self.app.update_window(window, update)
227 }
228
229 fn read_model<U, R>(
230 &self,
231 handle: &Model<U>,
232 read: impl FnOnce(&U, &AppContext) -> R,
233 ) -> Self::Result<R>
234 where
235 U: 'static,
236 {
237 self.app.read_model(handle, read)
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}