model_context.rs

  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}