model_context.rs

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