model_context.rs

  1use crate::{
  2    AppContext, Context, Effect, EntityId, EventEmitter, Executor, Handle, Reference, Subscription,
  3    WeakHandle,
  4};
  5use std::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_handlers.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_handlers.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_handlers.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        self.app.push_effect(Effect::Notify {
102            emitter: self.entity_id,
103        });
104    }
105
106    pub fn update_global<G, R>(&mut self, f: impl FnOnce(&mut G, &mut Self) -> R) -> R
107    where
108        G: 'static + Send + Sync,
109    {
110        let mut global = self.app.pop_global::<G>();
111        let result = f(global.as_mut(), self);
112        self.app.push_global(global);
113        result
114    }
115}
116
117impl<'a, T: EventEmitter + Send + Sync + 'static> ModelContext<'a, T> {
118    pub fn emit(&mut self, event: T::Event) {
119        self.app.push_effect(Effect::Emit {
120            emitter: self.entity_id,
121            event: Box::new(event),
122        });
123    }
124}
125
126impl<'a, T: 'static> Context for ModelContext<'a, T> {
127    type EntityContext<'b, 'c, U: Send + Sync + 'static> = ModelContext<'b, U>;
128    type Result<U> = U;
129
130    fn entity<U: Send + Sync + 'static>(
131        &mut self,
132        build_entity: impl FnOnce(&mut Self::EntityContext<'_, '_, U>) -> U,
133    ) -> Handle<U> {
134        self.app.entity(build_entity)
135    }
136
137    fn update_entity<U: Send + Sync + 'static, R>(
138        &mut self,
139        handle: &Handle<U>,
140        update: impl FnOnce(&mut U, &mut Self::EntityContext<'_, '_, U>) -> R,
141    ) -> R {
142        self.app.update_entity(handle, update)
143    }
144}