model_context.rs

  1use crate::{
  2    AppContext, AsyncAppContext, Context, Effect, EntityId, EventEmitter, Handle, MainThread,
  3    Reference, Subscription, Task, WeakHandle,
  4};
  5use derive_more::{Deref, DerefMut};
  6use futures::FutureExt;
  7use std::{
  8    any::TypeId,
  9    borrow::{Borrow, BorrowMut},
 10    future::Future,
 11    marker::PhantomData,
 12};
 13
 14#[derive(Deref, DerefMut)]
 15pub struct ModelContext<'a, T> {
 16    #[deref]
 17    #[deref_mut]
 18    app: Reference<'a, AppContext>,
 19    entity_type: PhantomData<T>,
 20    entity_id: EntityId,
 21}
 22
 23impl<'a, T: Send + Sync + 'static> ModelContext<'a, T> {
 24    pub(crate) fn mutable(app: &'a mut AppContext, entity_id: EntityId) -> Self {
 25        Self {
 26            app: Reference::Mutable(app),
 27            entity_type: PhantomData,
 28            entity_id,
 29        }
 30    }
 31
 32    pub fn entity_id(&self) -> EntityId {
 33        self.entity_id
 34    }
 35
 36    pub fn handle(&self) -> Handle<T> {
 37        self.weak_handle()
 38            .upgrade()
 39            .expect("The entity must be alive if we have a model context")
 40    }
 41
 42    pub fn weak_handle(&self) -> WeakHandle<T> {
 43        self.app.entities.weak_handle(self.entity_id)
 44    }
 45
 46    pub fn observe<E: Send + Sync + 'static>(
 47        &mut self,
 48        handle: &Handle<E>,
 49        on_notify: impl Fn(&mut T, Handle<E>, &mut ModelContext<'_, T>) + Send + Sync + 'static,
 50    ) -> Subscription {
 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: EventEmitter + Send + Sync + 'static>(
 67        &mut self,
 68        handle: &Handle<E>,
 69        on_event: impl Fn(&mut T, Handle<E>, &E::Event, &mut ModelContext<'_, T>)
 70            + Send
 71            + Sync
 72            + 'static,
 73    ) -> Subscription {
 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 = 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        on_release: impl Fn(&mut T, &mut AppContext) + Send + Sync + 'static,
 93    ) -> Subscription {
 94        self.app.release_listeners.insert(
 95            self.entity_id,
 96            Box::new(move |this, cx| {
 97                let this = this.downcast_mut().expect("invalid entity type");
 98                on_release(this, cx);
 99            }),
100        )
101    }
102
103    pub fn observe_release<E: Send + Sync + 'static>(
104        &mut self,
105        handle: &Handle<E>,
106        on_release: impl Fn(&mut T, &mut E, &mut ModelContext<'_, T>) + Send + Sync + 'static,
107    ) -> Subscription {
108        let this = self.weak_handle();
109        self.app.release_listeners.insert(
110            handle.entity_id,
111            Box::new(move |entity, cx| {
112                let entity = entity.downcast_mut().expect("invalid entity type");
113                if let Some(this) = this.upgrade() {
114                    this.update(cx, |this, cx| on_release(this, entity, cx));
115                }
116            }),
117        )
118    }
119
120    pub fn observe_global<G: 'static>(
121        &mut self,
122        f: impl Fn(&mut T, &mut ModelContext<'_, T>) + Send + Sync + 'static,
123    ) -> Subscription {
124        let handle = self.weak_handle();
125        self.global_observers.insert(
126            TypeId::of::<G>(),
127            Box::new(move |cx| handle.update(cx, |view, cx| f(view, cx)).is_ok()),
128        )
129    }
130
131    pub fn on_app_quit<Fut>(
132        &mut self,
133        on_quit: impl Fn(&mut T, &mut ModelContext<T>) -> Fut + Send + Sync + 'static,
134    ) -> Subscription
135    where
136        Fut: 'static + Future<Output = ()> + Send,
137    {
138        let handle = self.weak_handle();
139        self.app.quit_observers.insert(
140            (),
141            Box::new(move |cx| {
142                let future = handle.update(cx, |entity, cx| on_quit(entity, cx)).ok();
143                async move {
144                    if let Some(future) = future {
145                        future.await;
146                    }
147                }
148                .boxed()
149            }),
150        )
151    }
152
153    pub fn notify(&mut self) {
154        if self.app.pending_notifications.insert(self.entity_id) {
155            self.app.pending_effects.push_back(Effect::Notify {
156                emitter: self.entity_id,
157            });
158        }
159    }
160
161    pub fn update_global<G, R>(&mut self, f: impl FnOnce(&mut G, &mut Self) -> R) -> R
162    where
163        G: 'static + Send + Sync,
164    {
165        let mut global = self.app.lease_global::<G>();
166        let result = f(global.as_mut(), self);
167        self.app.restore_global(global);
168        result
169    }
170
171    pub fn spawn<Fut, R>(
172        &self,
173        f: impl FnOnce(WeakHandle<T>, AsyncAppContext) -> Fut + Send + 'static,
174    ) -> Task<R>
175    where
176        Fut: Future<Output = R> + Send + 'static,
177        R: Send + 'static,
178    {
179        let this = self.weak_handle();
180        self.app.spawn(|cx| f(this, cx))
181    }
182
183    pub fn spawn_on_main<Fut, R>(
184        &self,
185        f: impl FnOnce(WeakHandle<T>, MainThread<AsyncAppContext>) -> Fut + Send + 'static,
186    ) -> Task<R>
187    where
188        Fut: Future<Output = R> + 'static,
189        R: Send + 'static,
190    {
191        let this = self.weak_handle();
192        self.app.spawn_on_main(|cx| f(this, cx))
193    }
194}
195
196impl<'a, T: EventEmitter + Send + Sync + 'static> ModelContext<'a, T> {
197    pub fn emit(&mut self, event: T::Event) {
198        self.app.pending_effects.push_back(Effect::Emit {
199            emitter: self.entity_id,
200            event: Box::new(event),
201        });
202    }
203}
204
205impl<'a, T: 'static> Context for ModelContext<'a, T> {
206    type EntityContext<'b, 'c, U: Send + Sync + 'static> = ModelContext<'b, U>;
207    type Result<U> = U;
208
209    fn entity<U: Send + Sync + 'static>(
210        &mut self,
211        build_entity: impl FnOnce(&mut Self::EntityContext<'_, '_, U>) -> U,
212    ) -> Handle<U> {
213        self.app.entity(build_entity)
214    }
215
216    fn update_entity<U: Send + Sync + 'static, R>(
217        &mut self,
218        handle: &Handle<U>,
219        update: impl FnOnce(&mut U, &mut Self::EntityContext<'_, '_, U>) -> R,
220    ) -> R {
221        self.app.update_entity(handle, update)
222    }
223}
224
225impl<T> Borrow<AppContext> for ModelContext<'_, T> {
226    fn borrow(&self) -> &AppContext {
227        &self.app
228    }
229}
230
231impl<T> BorrowMut<AppContext> for ModelContext<'_, T> {
232    fn borrow_mut(&mut self) -> &mut AppContext {
233        &mut self.app
234    }
235}