model_context.rs

  1use crate::{AppContext, Context, Effect, EntityId, EventEmitter, Handle, Reference, WeakHandle};
  2use std::{marker::PhantomData, sync::Arc};
  3
  4pub struct ModelContext<'a, T> {
  5    app: Reference<'a, AppContext>,
  6    entity_type: PhantomData<T>,
  7    entity_id: EntityId,
  8}
  9
 10impl<'a, T: Send + Sync + 'static> ModelContext<'a, T> {
 11    pub(crate) fn mutable(app: &'a mut AppContext, entity_id: EntityId) -> Self {
 12        Self {
 13            app: Reference::Mutable(app),
 14            entity_type: PhantomData,
 15            entity_id,
 16        }
 17    }
 18
 19    // todo!
 20    // fn update<R>(&mut self, update: impl FnOnce(&mut T, &mut Self) -> R) -> R {
 21    //     let mut entity = self
 22    //         .app
 23    //         .entities
 24    //         .get_mut(self.entity_id)
 25    //         .unwrap()
 26    //         .take()
 27    //         .unwrap();
 28    //     let result = update(entity.downcast_mut::<T>().unwrap(), self);
 29    //     self.app
 30    //         .entities
 31    //         .get_mut(self.entity_id)
 32    //         .unwrap()
 33    //         .replace(entity);
 34    //     result
 35    // }
 36
 37    pub fn handle(&self) -> WeakHandle<T> {
 38        self.app.entities.weak_handle(self.entity_id)
 39    }
 40
 41    pub fn observe<E: Send + Sync + 'static>(
 42        &mut self,
 43        handle: &Handle<E>,
 44        on_notify: impl Fn(&mut T, Handle<E>, &mut ModelContext<'_, T>) + Send + Sync + 'static,
 45    ) {
 46        let this = self.handle();
 47        let handle = handle.downgrade();
 48        self.app
 49            .observers
 50            .entry(handle.id)
 51            .or_default()
 52            .push(Arc::new(move |cx| {
 53                if let Some((this, handle)) = this.upgrade(cx).zip(handle.upgrade(cx)) {
 54                    this.update(cx, |this, cx| on_notify(this, handle, cx));
 55                    true
 56                } else {
 57                    false
 58                }
 59            }));
 60    }
 61
 62    pub fn subscribe<E: EventEmitter + Send + Sync + 'static>(
 63        &mut self,
 64        handle: &Handle<E>,
 65        on_event: impl Fn(&mut T, Handle<E>, &E::Event, &mut ModelContext<'_, T>)
 66            + Send
 67            + Sync
 68            + 'static,
 69    ) {
 70        let this = self.handle();
 71        let handle = handle.downgrade();
 72        self.app
 73            .event_handlers
 74            .entry(handle.id)
 75            .or_default()
 76            .push(Arc::new(move |event, cx| {
 77                let event = event.downcast_ref().expect("invalid event type");
 78                if let Some((this, handle)) = this.upgrade(cx).zip(handle.upgrade(cx)) {
 79                    this.update(cx, |this, cx| on_event(this, handle, event, cx));
 80                    true
 81                } else {
 82                    false
 83                }
 84            }));
 85    }
 86
 87    pub fn notify(&mut self) {
 88        self.app
 89            .pending_effects
 90            .push_back(Effect::Notify(self.entity_id));
 91    }
 92}
 93
 94impl<'a, T: EventEmitter + Send + Sync + 'static> ModelContext<'a, T> {
 95    pub fn emit(&mut self, event: T::Event) {
 96        self.app.pending_effects.push_back(Effect::Emit {
 97            entity_id: self.entity_id,
 98            event: Box::new(event),
 99        });
100    }
101}
102
103impl<'a, T: 'static> Context for ModelContext<'a, T> {
104    type EntityContext<'b, 'c, U: Send + Sync + 'static> = ModelContext<'b, U>;
105    type Result<U> = U;
106
107    fn entity<U: Send + Sync + 'static>(
108        &mut self,
109        build_entity: impl FnOnce(&mut Self::EntityContext<'_, '_, U>) -> U,
110    ) -> Handle<U> {
111        self.app.entity(build_entity)
112    }
113
114    fn update_entity<U: Send + Sync + 'static, R>(
115        &mut self,
116        handle: &Handle<U>,
117        update: impl FnOnce(&mut U, &mut Self::EntityContext<'_, '_, U>) -> R,
118    ) -> R {
119        self.app.update_entity(handle, update)
120    }
121}