1use crate::{
2 AppContext, AsyncAppContext, Context, Effect, EntityId, EventEmitter, Handle, Reference,
3 Subscription, Task, WeakHandle,
4};
5use derive_more::{Deref, DerefMut};
6use std::{future::Future, marker::PhantomData};
7
8#[derive(Deref, DerefMut)]
9pub struct ModelContext<'a, T> {
10 #[deref]
11 #[deref_mut]
12 app: Reference<'a, AppContext>,
13 entity_type: PhantomData<T>,
14 entity_id: EntityId,
15}
16
17impl<'a, T: Send + Sync + 'static> ModelContext<'a, T> {
18 pub(crate) fn mutable(app: &'a mut AppContext, entity_id: EntityId) -> Self {
19 Self {
20 app: Reference::Mutable(app),
21 entity_type: PhantomData,
22 entity_id,
23 }
24 }
25
26 pub fn handle(&self) -> WeakHandle<T> {
27 self.app.entities.weak_handle(self.entity_id)
28 }
29
30 pub fn observe<E: Send + Sync + 'static>(
31 &mut self,
32 handle: &Handle<E>,
33 on_notify: impl Fn(&mut T, Handle<E>, &mut ModelContext<'_, T>) + Send + Sync + 'static,
34 ) -> Subscription {
35 let this = self.handle();
36 let handle = handle.downgrade();
37 self.app.observers.insert(
38 handle.id,
39 Box::new(move |cx| {
40 if let Some((this, handle)) = this.upgrade().zip(handle.upgrade()) {
41 this.update(cx, |this, cx| on_notify(this, handle, cx));
42 true
43 } else {
44 false
45 }
46 }),
47 )
48 }
49
50 pub fn subscribe<E: EventEmitter + Send + Sync + 'static>(
51 &mut self,
52 handle: &Handle<E>,
53 on_event: impl Fn(&mut T, Handle<E>, &E::Event, &mut ModelContext<'_, T>)
54 + Send
55 + Sync
56 + 'static,
57 ) -> Subscription {
58 let this = self.handle();
59 let handle = handle.downgrade();
60 self.app.event_listeners.insert(
61 handle.id,
62 Box::new(move |event, cx| {
63 let event = event.downcast_ref().expect("invalid event type");
64 if let Some((this, handle)) = this.upgrade().zip(handle.upgrade()) {
65 this.update(cx, |this, cx| on_event(this, handle, event, cx));
66 true
67 } else {
68 false
69 }
70 }),
71 )
72 }
73
74 pub fn on_release(
75 &mut self,
76 on_release: impl Fn(&mut T, &mut AppContext) + Send + Sync + 'static,
77 ) -> Subscription {
78 self.app.release_listeners.insert(
79 self.entity_id,
80 Box::new(move |this, cx| {
81 let this = this.downcast_mut().expect("invalid entity type");
82 on_release(this, cx);
83 }),
84 )
85 }
86
87 pub fn observe_release<E: Send + Sync + 'static>(
88 &mut self,
89 handle: &Handle<E>,
90 on_release: impl Fn(&mut T, &mut E, &mut ModelContext<'_, T>) + Send + Sync + 'static,
91 ) -> Subscription {
92 let this = self.handle();
93 self.app.release_listeners.insert(
94 handle.id,
95 Box::new(move |entity, cx| {
96 let entity = entity.downcast_mut().expect("invalid entity type");
97 if let Some(this) = this.upgrade() {
98 this.update(cx, |this, cx| on_release(this, entity, cx));
99 }
100 }),
101 )
102 }
103
104 pub fn notify(&mut self) {
105 if self.app.pending_notifications.insert(self.entity_id) {
106 self.app.pending_effects.push_back(Effect::Notify {
107 emitter: self.entity_id,
108 });
109 }
110 }
111
112 pub fn update_global<G, R>(&mut self, f: impl FnOnce(&mut G, &mut Self) -> R) -> R
113 where
114 G: 'static + Send + Sync,
115 {
116 let mut global = self.app.lease_global::<G>();
117 let result = f(global.as_mut(), self);
118 self.app.restore_global(global);
119 result
120 }
121
122 pub fn spawn<Fut, R>(
123 &self,
124 f: impl FnOnce(WeakHandle<T>, AsyncAppContext) -> Fut + Send + 'static,
125 ) -> Task<R>
126 where
127 Fut: Future<Output = R> + Send + 'static,
128 R: Send + 'static,
129 {
130 let this = self.handle();
131 self.app.spawn(|cx| f(this, cx))
132 }
133}
134
135impl<'a, T: EventEmitter + Send + Sync + 'static> ModelContext<'a, T> {
136 pub fn emit(&mut self, event: T::Event) {
137 self.app.pending_effects.push_back(Effect::Emit {
138 emitter: self.entity_id,
139 event: Box::new(event),
140 });
141 }
142}
143
144impl<'a, T: 'static> Context for ModelContext<'a, T> {
145 type EntityContext<'b, 'c, U: Send + Sync + 'static> = ModelContext<'b, U>;
146 type Result<U> = U;
147
148 fn entity<U: Send + Sync + 'static>(
149 &mut self,
150 build_entity: impl FnOnce(&mut Self::EntityContext<'_, '_, U>) -> U,
151 ) -> Handle<U> {
152 self.app.entity(build_entity)
153 }
154
155 fn update_entity<U: Send + Sync + 'static, R>(
156 &mut self,
157 handle: &Handle<U>,
158 update: impl FnOnce(&mut U, &mut Self::EntityContext<'_, '_, U>) -> R,
159 ) -> R {
160 self.app.update_entity(handle, update)
161 }
162}