model_context.rs

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