model_context.rs

  1use crate::{
  2    AppContext, AsyncAppContext, Context, Effect, Entity, EntityId, EventEmitter, MainThread,
  3    Model, Reference, Subscription, Task, WeakModel,
  4};
  5use derive_more::{Deref, DerefMut};
  6use futures::FutureExt;
  7use std::{
  8    any::{Any, TypeId},
  9    borrow::{Borrow, BorrowMut},
 10    future::Future,
 11};
 12
 13#[derive(Deref, DerefMut)]
 14pub struct ModelContext<'a, T> {
 15    #[deref]
 16    #[deref_mut]
 17    app: Reference<'a, AppContext>,
 18    model_state: WeakModel<T>,
 19}
 20
 21impl<'a, T: 'static> ModelContext<'a, T> {
 22    pub(crate) fn mutable(app: &'a mut AppContext, model_state: WeakModel<T>) -> Self {
 23        Self {
 24            app: Reference::Mutable(app),
 25            model_state,
 26        }
 27    }
 28
 29    pub fn entity_id(&self) -> EntityId {
 30        self.model_state.entity_id
 31    }
 32
 33    pub fn handle(&self) -> Model<T> {
 34        self.weak_model()
 35            .upgrade()
 36            .expect("The entity must be alive if we have a model context")
 37    }
 38
 39    pub fn weak_model(&self) -> WeakModel<T> {
 40        self.model_state.clone()
 41    }
 42
 43    pub fn observe<T2, E>(
 44        &mut self,
 45        entity: &E,
 46        mut on_notify: impl FnMut(&mut T, E, &mut ModelContext<'_, T>) + Send + 'static,
 47    ) -> Subscription
 48    where
 49        T: 'static + Send,
 50        T2: 'static,
 51        E: Entity<T2>,
 52    {
 53        let this = self.weak_model();
 54        let entity_id = entity.entity_id();
 55        let handle = entity.downgrade();
 56        self.app.observers.insert(
 57            entity_id,
 58            Box::new(move |cx| {
 59                if let Some((this, handle)) = this.upgrade().zip(E::upgrade_from(&handle)) {
 60                    this.update(cx, |this, cx| on_notify(this, handle, cx));
 61                    true
 62                } else {
 63                    false
 64                }
 65            }),
 66        )
 67    }
 68
 69    pub fn subscribe<T2, E>(
 70        &mut self,
 71        entity: &E,
 72        mut on_event: impl FnMut(&mut T, E, &T2::Event, &mut ModelContext<'_, T>) + Send + 'static,
 73    ) -> Subscription
 74    where
 75        T: 'static + Send,
 76        T2: 'static + EventEmitter,
 77        E: Entity<T2>,
 78    {
 79        let this = self.weak_model();
 80        let entity_id = entity.entity_id();
 81        let entity = entity.downgrade();
 82        self.app.event_listeners.insert(
 83            entity_id,
 84            Box::new(move |event, cx| {
 85                let event: &T2::Event = event.downcast_ref().expect("invalid event type");
 86                if let Some((this, handle)) = this.upgrade().zip(E::upgrade_from(&entity)) {
 87                    this.update(cx, |this, cx| on_event(this, handle, event, cx));
 88                    true
 89                } else {
 90                    false
 91                }
 92            }),
 93        )
 94    }
 95
 96    pub fn on_release(
 97        &mut self,
 98        mut on_release: impl FnMut(&mut T, &mut AppContext) + Send + 'static,
 99    ) -> Subscription
100    where
101        T: 'static,
102    {
103        self.app.release_listeners.insert(
104            self.model_state.entity_id,
105            Box::new(move |this, cx| {
106                let this = this.downcast_mut().expect("invalid entity type");
107                on_release(this, cx);
108            }),
109        )
110    }
111
112    pub fn observe_release<T2, E>(
113        &mut self,
114        entity: &E,
115        mut on_release: impl FnMut(&mut T, &mut T2, &mut ModelContext<'_, T>) + Send + 'static,
116    ) -> Subscription
117    where
118        T: Any + Send,
119        T2: 'static,
120        E: Entity<T2>,
121    {
122        let entity_id = entity.entity_id();
123        let this = self.weak_model();
124        self.app.release_listeners.insert(
125            entity_id,
126            Box::new(move |entity, cx| {
127                let entity = entity.downcast_mut().expect("invalid entity type");
128                if let Some(this) = this.upgrade() {
129                    this.update(cx, |this, cx| on_release(this, entity, cx));
130                }
131            }),
132        )
133    }
134
135    pub fn observe_global<G: 'static>(
136        &mut self,
137        mut f: impl FnMut(&mut T, &mut ModelContext<'_, T>) + Send + 'static,
138    ) -> Subscription
139    where
140        T: 'static + Send,
141    {
142        let handle = self.weak_model();
143        self.global_observers.insert(
144            TypeId::of::<G>(),
145            Box::new(move |cx| handle.update(cx, |view, cx| f(view, cx)).is_ok()),
146        )
147    }
148
149    pub fn on_app_quit<Fut>(
150        &mut self,
151        mut on_quit: impl FnMut(&mut T, &mut ModelContext<T>) -> Fut + Send + 'static,
152    ) -> Subscription
153    where
154        Fut: 'static + Future<Output = ()> + Send,
155        T: 'static + Send,
156    {
157        let handle = self.weak_model();
158        self.app.quit_observers.insert(
159            (),
160            Box::new(move |cx| {
161                let future = handle.update(cx, |entity, cx| on_quit(entity, cx)).ok();
162                async move {
163                    if let Some(future) = future {
164                        future.await;
165                    }
166                }
167                .boxed()
168            }),
169        )
170    }
171
172    pub fn notify(&mut self) {
173        if self
174            .app
175            .pending_notifications
176            .insert(self.model_state.entity_id)
177        {
178            self.app.pending_effects.push_back(Effect::Notify {
179                emitter: self.model_state.entity_id,
180            });
181        }
182    }
183
184    pub fn update_global<G, R>(&mut self, f: impl FnOnce(&mut G, &mut Self) -> R) -> R
185    where
186        G: 'static + Send,
187    {
188        let mut global = self.app.lease_global::<G>();
189        let result = f(&mut global, self);
190        self.app.end_global_lease(global);
191        result
192    }
193
194    pub fn spawn<Fut, R>(
195        &self,
196        f: impl FnOnce(WeakModel<T>, AsyncAppContext) -> Fut + Send + 'static,
197    ) -> Task<R>
198    where
199        T: 'static,
200        Fut: Future<Output = R> + Send + 'static,
201        R: Send + 'static,
202    {
203        let this = self.weak_model();
204        self.app.spawn(|cx| f(this, cx))
205    }
206
207    pub fn spawn_on_main<Fut, R>(
208        &self,
209        f: impl FnOnce(WeakModel<T>, MainThread<AsyncAppContext>) -> Fut + Send + 'static,
210    ) -> Task<R>
211    where
212        Fut: Future<Output = R> + 'static,
213        R: Send + 'static,
214    {
215        let this = self.weak_model();
216        self.app.spawn_on_main(|cx| f(this, cx))
217    }
218}
219
220impl<'a, T> ModelContext<'a, T>
221where
222    T: EventEmitter,
223    T::Event: Send,
224{
225    pub fn emit(&mut self, event: T::Event) {
226        self.app.pending_effects.push_back(Effect::Emit {
227            emitter: self.model_state.entity_id,
228            event: Box::new(event),
229        });
230    }
231}
232
233impl<'a, T> Context for ModelContext<'a, T> {
234    type ModelContext<'b, U> = ModelContext<'b, U>;
235    type Result<U> = U;
236
237    fn build_model<U>(
238        &mut self,
239        build_model: impl FnOnce(&mut Self::ModelContext<'_, U>) -> U,
240    ) -> Model<U>
241    where
242        U: 'static + Send,
243    {
244        self.app.build_model(build_model)
245    }
246
247    fn update_model<U: 'static, R>(
248        &mut self,
249        handle: &Model<U>,
250        update: impl FnOnce(&mut U, &mut Self::ModelContext<'_, U>) -> R,
251    ) -> R {
252        self.app.update_model(handle, update)
253    }
254}
255
256impl<T> Borrow<AppContext> for ModelContext<'_, T> {
257    fn borrow(&self) -> &AppContext {
258        &self.app
259    }
260}
261
262impl<T> BorrowMut<AppContext> for ModelContext<'_, T> {
263    fn borrow_mut(&mut self) -> &mut AppContext {
264        &mut self.app
265    }
266}