model_context.rs

  1use crate::{
  2    AppContext, AsyncAppContext, Context, Effect, EntityId, EventEmitter, Handle, Reference,
  3    Subscription, Task, WeakHandle,
  4};
  5use std::{future::Future, marker::PhantomData};
  6
  7pub struct ModelContext<'a, T> {
  8    app: Reference<'a, AppContext>,
  9    entity_type: PhantomData<T>,
 10    entity_id: EntityId,
 11}
 12
 13impl<'a, T: Send + Sync + 'static> ModelContext<'a, T> {
 14    pub(crate) fn mutable(app: &'a mut AppContext, entity_id: EntityId) -> Self {
 15        Self {
 16            app: Reference::Mutable(app),
 17            entity_type: PhantomData,
 18            entity_id,
 19        }
 20    }
 21
 22    pub fn handle(&self) -> WeakHandle<T> {
 23        self.app.entities.weak_handle(self.entity_id)
 24    }
 25
 26    pub fn observe<E: Send + Sync + 'static>(
 27        &mut self,
 28        handle: &Handle<E>,
 29        on_notify: impl Fn(&mut T, Handle<E>, &mut ModelContext<'_, T>) + Send + Sync + 'static,
 30    ) -> Subscription {
 31        let this = self.handle();
 32        let handle = handle.downgrade();
 33        self.app.observers.insert(
 34            handle.id,
 35            Box::new(move |cx| {
 36                if let Some((this, handle)) = this.upgrade().zip(handle.upgrade()) {
 37                    this.update(cx, |this, cx| on_notify(this, handle, cx));
 38                    true
 39                } else {
 40                    false
 41                }
 42            }),
 43        )
 44    }
 45
 46    pub fn subscribe<E: EventEmitter + Send + Sync + 'static>(
 47        &mut self,
 48        handle: &Handle<E>,
 49        on_event: impl Fn(&mut T, Handle<E>, &E::Event, &mut ModelContext<'_, T>)
 50            + Send
 51            + Sync
 52            + 'static,
 53    ) -> Subscription {
 54        let this = self.handle();
 55        let handle = handle.downgrade();
 56        self.app.event_listeners.insert(
 57            handle.id,
 58            Box::new(move |event, cx| {
 59                let event = event.downcast_ref().expect("invalid event type");
 60                if let Some((this, handle)) = this.upgrade().zip(handle.upgrade()) {
 61                    this.update(cx, |this, cx| on_event(this, handle, event, cx));
 62                    true
 63                } else {
 64                    false
 65                }
 66            }),
 67        )
 68    }
 69
 70    pub fn on_release(
 71        &mut self,
 72        on_release: impl Fn(&mut T, &mut AppContext) + Send + Sync + 'static,
 73    ) -> Subscription {
 74        self.app.release_listeners.insert(
 75            self.entity_id,
 76            Box::new(move |this, cx| {
 77                let this = this.downcast_mut().expect("invalid entity type");
 78                on_release(this, cx);
 79            }),
 80        )
 81    }
 82
 83    pub fn observe_release<E: Send + Sync + 'static>(
 84        &mut self,
 85        handle: &Handle<E>,
 86        on_release: impl Fn(&mut T, &mut E, &mut ModelContext<'_, T>) + Send + Sync + 'static,
 87    ) -> Subscription {
 88        let this = self.handle();
 89        self.app.release_listeners.insert(
 90            handle.id,
 91            Box::new(move |entity, cx| {
 92                let entity = entity.downcast_mut().expect("invalid entity type");
 93                if let Some(this) = this.upgrade() {
 94                    this.update(cx, |this, cx| on_release(this, entity, cx));
 95                }
 96            }),
 97        )
 98    }
 99
100    pub fn notify(&mut self) {
101        if self.app.pending_notifications.insert(self.entity_id) {
102            self.app.pending_effects.push_back(Effect::Notify {
103                emitter: self.entity_id,
104            });
105        }
106    }
107
108    pub fn update_global<G, R>(&mut self, f: impl FnOnce(&mut G, &mut Self) -> R) -> R
109    where
110        G: 'static + Send + Sync,
111    {
112        let mut global = self.app.lease_global::<G>();
113        let result = f(global.as_mut(), self);
114        self.app.restore_global(global);
115        result
116    }
117
118    pub fn spawn<Fut, R>(
119        &self,
120        f: impl FnOnce(WeakHandle<T>, AsyncAppContext) -> Fut + Send + 'static,
121    ) -> Task<R>
122    where
123        Fut: Future<Output = R> + Send + 'static,
124        R: Send + 'static,
125    {
126        let this = self.handle();
127        self.app.spawn(|cx| f(this, cx))
128    }
129}
130
131impl<'a, T: EventEmitter + Send + Sync + 'static> ModelContext<'a, T> {
132    pub fn emit(&mut self, event: T::Event) {
133        self.app.pending_effects.push_back(Effect::Emit {
134            emitter: self.entity_id,
135            event: Box::new(event),
136        });
137    }
138}
139
140impl<'a, T: 'static> Context for ModelContext<'a, T> {
141    type EntityContext<'b, 'c, U: Send + Sync + 'static> = ModelContext<'b, U>;
142    type Result<U> = U;
143
144    fn entity<U: Send + Sync + 'static>(
145        &mut self,
146        build_entity: impl FnOnce(&mut Self::EntityContext<'_, '_, U>) -> U,
147    ) -> Handle<U> {
148        self.app.entity(build_entity)
149    }
150
151    fn update_entity<U: Send + Sync + 'static, R>(
152        &mut self,
153        handle: &Handle<U>,
154        update: impl FnOnce(&mut U, &mut Self::EntityContext<'_, '_, U>) -> R,
155    ) -> R {
156        self.app.update_entity(handle, update)
157    }
158}