model_context.rs

  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        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    }
 99
100    pub fn observe_release<T2, E>(
101        &mut self,
102        entity: &E,
103        on_release: impl FnOnce(&mut T, &mut T2, &mut ModelContext<'_, T>) + 'static,
104    ) -> Subscription
105    where
106        T: Any,
107        T2: 'static,
108        E: Entity<T2>,
109    {
110        let entity_id = entity.entity_id();
111        let this = self.weak_model();
112        self.app.release_listeners.insert(
113            entity_id,
114            Box::new(move |entity, cx| {
115                let entity = entity.downcast_mut().expect("invalid entity type");
116                if let Some(this) = this.upgrade() {
117                    this.update(cx, |this, cx| on_release(this, entity, cx));
118                }
119            }),
120        )
121    }
122
123    pub fn observe_global<G: 'static>(
124        &mut self,
125        mut f: impl FnMut(&mut T, &mut ModelContext<'_, T>) + 'static,
126    ) -> Subscription
127    where
128        T: 'static,
129    {
130        let handle = self.weak_model();
131        self.global_observers.insert(
132            TypeId::of::<G>(),
133            Box::new(move |cx| handle.update(cx, |view, cx| f(view, cx)).is_ok()),
134        )
135    }
136
137    pub fn on_app_quit<Fut>(
138        &mut self,
139        mut on_quit: impl FnMut(&mut T, &mut ModelContext<T>) -> Fut + 'static,
140    ) -> Subscription
141    where
142        Fut: 'static + Future<Output = ()>,
143        T: 'static,
144    {
145        let handle = self.weak_model();
146        self.app.quit_observers.insert(
147            (),
148            Box::new(move |cx| {
149                let future = handle.update(cx, |entity, cx| on_quit(entity, cx)).ok();
150                async move {
151                    if let Some(future) = future {
152                        future.await;
153                    }
154                }
155                .boxed_local()
156            }),
157        )
158    }
159
160    pub fn notify(&mut self) {
161        if self
162            .app
163            .pending_notifications
164            .insert(self.model_state.entity_id)
165        {
166            self.app.pending_effects.push_back(Effect::Notify {
167                emitter: self.model_state.entity_id,
168            });
169        }
170    }
171
172    pub fn update_global<G, R>(&mut self, f: impl FnOnce(&mut G, &mut Self) -> R) -> R
173    where
174        G: 'static,
175    {
176        let mut global = self.app.lease_global::<G>();
177        let result = f(&mut global, self);
178        self.app.end_global_lease(global);
179        result
180    }
181
182    pub fn spawn<Fut, R>(&self, f: impl FnOnce(WeakModel<T>, AsyncAppContext) -> Fut) -> Task<R>
183    where
184        T: 'static,
185        Fut: Future<Output = R> + 'static,
186        R: 'static,
187    {
188        let this = self.weak_model();
189        self.app.spawn(|cx| f(this, cx))
190    }
191}
192
193impl<'a, T> ModelContext<'a, T> {
194    pub fn emit<Evt>(&mut self, event: Evt)
195    where
196        T: EventEmitter<Evt>,
197        Evt: 'static,
198    {
199        self.app.pending_effects.push_back(Effect::Emit {
200            emitter: self.model_state.entity_id,
201            event_type: TypeId::of::<Evt>(),
202            event: Box::new(event),
203        });
204    }
205}
206
207impl<'a, T> Context for ModelContext<'a, T> {
208    type Result<U> = U;
209
210    fn build_model<U: 'static>(
211        &mut self,
212        build_model: impl FnOnce(&mut ModelContext<'_, U>) -> U,
213    ) -> Model<U> {
214        self.app.build_model(build_model)
215    }
216
217    fn update_model<U: 'static, R>(
218        &mut self,
219        handle: &Model<U>,
220        update: impl FnOnce(&mut U, &mut ModelContext<'_, U>) -> R,
221    ) -> R {
222        self.app.update_model(handle, update)
223    }
224
225    fn update_window<R, F>(&mut self, window: AnyWindowHandle, update: F) -> Result<R>
226    where
227        F: FnOnce(AnyView, &mut WindowContext<'_>) -> R,
228    {
229        self.app.update_window(window, update)
230    }
231
232    fn read_model<U, R>(
233        &self,
234        handle: &Model<U>,
235        read: impl FnOnce(&U, &AppContext) -> R,
236    ) -> Self::Result<R>
237    where
238        U: 'static,
239    {
240        self.app.read_model(handle, read)
241    }
242
243    fn read_window<U, R>(
244        &self,
245        window: &WindowHandle<U>,
246        read: impl FnOnce(View<U>, &AppContext) -> R,
247    ) -> Result<R>
248    where
249        U: 'static,
250    {
251        self.app.read_window(window, read)
252    }
253}
254
255impl<T> Borrow<AppContext> for ModelContext<'_, T> {
256    fn borrow(&self) -> &AppContext {
257        &self.app
258    }
259}
260
261impl<T> BorrowMut<AppContext> for ModelContext<'_, T> {
262    fn borrow_mut(&mut self) -> &mut AppContext {
263        &mut self.app
264    }
265}