model_context.rs

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