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 WeakHandle {
39 id: self.entity_id,
40 entity_type: PhantomData,
41 }
42 }
43
44 pub fn observe<E: Send + Sync + 'static>(
45 &mut self,
46 handle: &Handle<E>,
47 on_notify: impl Fn(&mut T, Handle<E>, &mut ModelContext<'_, T>) + Send + Sync + 'static,
48 ) {
49 let this = self.handle();
50 let handle = handle.downgrade();
51 self.app
52 .observers
53 .entry(handle.id)
54 .or_default()
55 .push(Arc::new(move |cx| {
56 if let Some((this, handle)) = this.upgrade(cx).zip(handle.upgrade(cx)) {
57 this.update(cx, |this, cx| on_notify(this, handle, cx));
58 true
59 } else {
60 false
61 }
62 }));
63 }
64
65 pub fn notify(&mut self) {
66 self.app
67 .pending_effects
68 .push_back(Effect::Notify(self.entity_id));
69 }
70}
71
72impl<'a, T: 'static> Context for ModelContext<'a, T> {
73 type EntityContext<'b, 'c, U: Send + Sync + 'static> = ModelContext<'b, U>;
74 type Result<U> = U;
75
76 fn entity<U: Send + Sync + 'static>(
77 &mut self,
78 build_entity: impl FnOnce(&mut Self::EntityContext<'_, '_, U>) -> U,
79 ) -> Handle<U> {
80 self.app.entity(build_entity)
81 }
82
83 fn update_entity<U: Send + Sync + 'static, R>(
84 &mut self,
85 handle: &Handle<U>,
86 update: impl FnOnce(&mut U, &mut Self::EntityContext<'_, '_, U>) -> R,
87 ) -> R {
88 self.app.update_entity(handle, update)
89 }
90}