model_context.rs

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