model_context.rs

 1use crate::{AppContext, Context, Effect, EntityId, 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 notify(&mut self) {
63        self.app
64            .pending_effects
65            .push_back(Effect::Notify(self.entity_id));
66    }
67}
68
69impl<'a, T: 'static> Context for ModelContext<'a, T> {
70    type EntityContext<'b, 'c, U: Send + Sync + 'static> = ModelContext<'b, U>;
71    type Result<U> = U;
72
73    fn entity<U: Send + Sync + 'static>(
74        &mut self,
75        build_entity: impl FnOnce(&mut Self::EntityContext<'_, '_, U>) -> U,
76    ) -> Handle<U> {
77        self.app.entity(build_entity)
78    }
79
80    fn update_entity<U: Send + Sync + 'static, R>(
81        &mut self,
82        handle: &Handle<U>,
83        update: impl FnOnce(&mut U, &mut Self::EntityContext<'_, '_, U>) -> R,
84    ) -> R {
85        self.app.update_entity(handle, update)
86    }
87}