model_context.rs

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