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}