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