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::{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: WeakHandle<T>,
 19}
 20
 21impl<'a, T: 'static> ModelContext<'a, T> {
 22    pub(crate) fn mutable(app: &'a mut AppContext, model_state: WeakHandle<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) -> Handle<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) -> WeakHandle<T> {
 40        self.model_state.clone()
 41    }
 42
 43    pub fn observe<T2: 'static>(
 44        &mut self,
 45        handle: &Handle<T2>,
 46        mut on_notify: impl FnMut(&mut T, Handle<T2>, &mut ModelContext<'_, T>) + Send + Sync + 'static,
 47    ) -> Subscription
 48    where
 49        T: Any + Send + Sync,
 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: &Handle<E>,
 69        mut on_event: impl FnMut(&mut T, Handle<E>, &E::Event, &mut ModelContext<'_, T>)
 70            + Send
 71            + Sync
 72            + 'static,
 73    ) -> Subscription
 74    where
 75        T: Any + Send + Sync,
 76    {
 77        let this = self.weak_handle();
 78        let handle = handle.downgrade();
 79        self.app.event_listeners.insert(
 80            handle.entity_id,
 81            Box::new(move |event, cx| {
 82                let event = event.downcast_ref().expect("invalid event type");
 83                if let Some((this, handle)) = this.upgrade().zip(handle.upgrade()) {
 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 + Sync + '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<E: 'static>(
110        &mut self,
111        handle: &Handle<E>,
112        mut on_release: impl FnMut(&mut T, &mut E, &mut ModelContext<'_, T>) + Send + Sync + 'static,
113    ) -> Subscription
114    where
115        T: Any + Send + Sync,
116    {
117        let this = self.weak_handle();
118        self.app.release_listeners.insert(
119            handle.entity_id,
120            Box::new(move |entity, cx| {
121                let entity = entity.downcast_mut().expect("invalid entity type");
122                if let Some(this) = this.upgrade() {
123                    this.update(cx, |this, cx| on_release(this, entity, cx));
124                }
125            }),
126        )
127    }
128
129    pub fn observe_global<G: 'static>(
130        &mut self,
131        mut f: impl FnMut(&mut T, &mut ModelContext<'_, T>) + Send + Sync + 'static,
132    ) -> Subscription
133    where
134        T: Any + Send + Sync,
135    {
136        let handle = self.weak_handle();
137        self.global_observers.insert(
138            TypeId::of::<G>(),
139            Box::new(move |cx| handle.update(cx, |view, cx| f(view, cx)).is_ok()),
140        )
141    }
142
143    pub fn on_app_quit<Fut>(
144        &mut self,
145        mut on_quit: impl FnMut(&mut T, &mut ModelContext<T>) -> Fut + Send + Sync + 'static,
146    ) -> Subscription
147    where
148        Fut: 'static + Future<Output = ()> + Send,
149        T: Any + Send + Sync,
150    {
151        let handle = self.weak_handle();
152        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()
162            }),
163        )
164    }
165
166    pub fn notify(&mut self) {
167        if self
168            .app
169            .pending_notifications
170            .insert(self.model_state.entity_id)
171        {
172            self.app.pending_effects.push_back(Effect::Notify {
173                emitter: self.model_state.entity_id,
174            });
175        }
176    }
177
178    pub fn update_global<G, R>(&mut self, f: impl FnOnce(&mut G, &mut Self) -> R) -> R
179    where
180        G: 'static + Send + Sync,
181    {
182        let mut global = self.app.lease_global::<G>();
183        let result = f(&mut global, self);
184        self.app.end_global_lease(global);
185        result
186    }
187
188    pub fn spawn<Fut, R>(
189        &self,
190        f: impl FnOnce(WeakHandle<T>, AsyncAppContext) -> Fut + Send + 'static,
191    ) -> Task<R>
192    where
193        T: 'static,
194        Fut: Future<Output = R> + Send + 'static,
195        R: Send + 'static,
196    {
197        let this = self.weak_handle();
198        self.app.spawn(|cx| f(this, cx))
199    }
200
201    pub fn spawn_on_main<Fut, R>(
202        &self,
203        f: impl FnOnce(WeakHandle<T>, MainThread<AsyncAppContext>) -> Fut + Send + 'static,
204    ) -> Task<R>
205    where
206        Fut: Future<Output = R> + 'static,
207        R: Send + 'static,
208    {
209        let this = self.weak_handle();
210        self.app.spawn_on_main(|cx| f(this, cx))
211    }
212}
213
214impl<'a, T> ModelContext<'a, T>
215where
216    T: EventEmitter,
217    T::Event: Send + Sync,
218{
219    pub fn emit(&mut self, event: T::Event) {
220        self.app.pending_effects.push_back(Effect::Emit {
221            emitter: self.model_state.entity_id,
222            event: Box::new(event),
223        });
224    }
225}
226
227impl<'a, T> Context for ModelContext<'a, T> {
228    type EntityContext<'b, 'c, U> = ModelContext<'b, U>;
229    type Result<U> = U;
230
231    fn entity<U>(
232        &mut self,
233        build_entity: impl FnOnce(&mut Self::EntityContext<'_, '_, U>) -> U,
234    ) -> Handle<U>
235    where
236        U: 'static + Send + Sync,
237    {
238        self.app.entity(build_entity)
239    }
240
241    fn update_entity<U: 'static, R>(
242        &mut self,
243        handle: &Handle<U>,
244        update: impl FnOnce(&mut U, &mut Self::EntityContext<'_, '_, U>) -> R,
245    ) -> R {
246        self.app.update_entity(handle, update)
247    }
248}
249
250impl<T> Borrow<AppContext> for ModelContext<'_, T> {
251    fn borrow(&self) -> &AppContext {
252        &self.app
253    }
254}
255
256impl<T> BorrowMut<AppContext> for ModelContext<'_, T> {
257    fn borrow_mut(&mut self) -> &mut AppContext {
258        &mut self.app
259    }
260}