1use crate::{
2 AnyWindowHandle, AppContext, Component, Context, Executor, Handle, MainThread, ModelContext,
3 Result, Task, View, ViewContext, VisualContext, WindowContext, WindowHandle,
4};
5use anyhow::Context as _;
6use derive_more::{Deref, DerefMut};
7use parking_lot::Mutex;
8use std::{future::Future, sync::Weak};
9
10#[derive(Clone)]
11pub struct AsyncAppContext {
12 pub(crate) app: Weak<Mutex<AppContext>>,
13 pub(crate) executor: Executor,
14}
15
16impl Context for AsyncAppContext {
17 type EntityContext<'a, T> = ModelContext<'a, T>;
18 type Result<T> = Result<T>;
19
20 fn entity<T: 'static>(
21 &mut self,
22 build_entity: impl FnOnce(&mut Self::EntityContext<'_, T>) -> T,
23 ) -> Self::Result<Handle<T>>
24 where
25 T: 'static + Send,
26 {
27 let app = self.app.upgrade().context("app was released")?;
28 let mut lock = app.lock(); // Need this to compile
29 Ok(lock.entity(build_entity))
30 }
31
32 fn update_entity<T: 'static, R>(
33 &mut self,
34 handle: &Handle<T>,
35 update: impl FnOnce(&mut T, &mut Self::EntityContext<'_, T>) -> R,
36 ) -> Self::Result<R> {
37 let app = self.app.upgrade().context("app was released")?;
38 let mut lock = app.lock(); // Need this to compile
39 Ok(lock.update_entity(handle, update))
40 }
41}
42
43impl AsyncAppContext {
44 pub fn refresh(&mut self) -> Result<()> {
45 let app = self.app.upgrade().context("app was released")?;
46 let mut lock = app.lock(); // Need this to compile
47 lock.refresh();
48 Ok(())
49 }
50
51 pub fn executor(&self) -> &Executor {
52 &self.executor
53 }
54
55 pub fn update<R>(&self, f: impl FnOnce(&mut AppContext) -> R) -> Result<R> {
56 let app = self.app.upgrade().context("app was released")?;
57 let mut lock = app.lock();
58 Ok(f(&mut *lock))
59 }
60
61 pub fn read_window<R>(
62 &self,
63 handle: AnyWindowHandle,
64 update: impl FnOnce(&WindowContext) -> R,
65 ) -> Result<R> {
66 let app = self.app.upgrade().context("app was released")?;
67 let mut app_context = app.lock();
68 app_context.read_window(handle, update)
69 }
70
71 pub fn update_window<R>(
72 &self,
73 handle: AnyWindowHandle,
74 update: impl FnOnce(&mut WindowContext) -> R,
75 ) -> Result<R> {
76 let app = self.app.upgrade().context("app was released")?;
77 let mut app_context = app.lock();
78 app_context.update_window(handle, update)
79 }
80
81 pub fn update_window_root<V, R>(
82 &mut self,
83 handle: &WindowHandle<V>,
84 update: impl FnOnce(&mut V, &mut ViewContext<'_, '_, V>) -> R,
85 ) -> Result<R>
86 where
87 V: 'static,
88 {
89 let app = self.app.upgrade().context("app was released")?;
90 let mut app_context = app.lock();
91 app_context.update_window_root(handle, update)
92 }
93
94 pub fn spawn<Fut, R>(&self, f: impl FnOnce(AsyncAppContext) -> Fut + Send + 'static) -> Task<R>
95 where
96 Fut: Future<Output = R> + Send + 'static,
97 R: Send + 'static,
98 {
99 let this = self.clone();
100 self.executor.spawn(async move { f(this).await })
101 }
102
103 pub fn spawn_on_main<Fut, R>(
104 &self,
105 f: impl FnOnce(AsyncAppContext) -> Fut + Send + 'static,
106 ) -> Task<R>
107 where
108 Fut: Future<Output = R> + 'static,
109 R: Send + 'static,
110 {
111 let this = self.clone();
112 self.executor.spawn_on_main(|| f(this))
113 }
114
115 pub fn run_on_main<R>(
116 &self,
117 f: impl FnOnce(&mut MainThread<AppContext>) -> R + Send + 'static,
118 ) -> Result<Task<R>>
119 where
120 R: Send + 'static,
121 {
122 let app = self.app.upgrade().context("app was released")?;
123 let mut app_context = app.lock();
124 Ok(app_context.run_on_main(f))
125 }
126
127 pub fn has_global<G: 'static>(&self) -> Result<bool> {
128 let app = self.app.upgrade().context("app was released")?;
129 let lock = app.lock(); // Need this to compile
130 Ok(lock.has_global::<G>())
131 }
132
133 pub fn read_global<G: 'static, R>(&self, read: impl FnOnce(&G, &AppContext) -> R) -> Result<R> {
134 let app = self.app.upgrade().context("app was released")?;
135 let lock = app.lock(); // Need this to compile
136 Ok(read(lock.global(), &lock))
137 }
138
139 pub fn try_read_global<G: 'static, R>(
140 &self,
141 read: impl FnOnce(&G, &AppContext) -> R,
142 ) -> Option<R> {
143 let app = self.app.upgrade()?;
144 let lock = app.lock(); // Need this to compile
145 Some(read(lock.try_global()?, &lock))
146 }
147
148 pub fn update_global<G: 'static, R>(
149 &mut self,
150 update: impl FnOnce(&mut G, &mut AppContext) -> R,
151 ) -> Result<R> {
152 let app = self.app.upgrade().context("app was released")?;
153 let mut lock = app.lock(); // Need this to compile
154 Ok(lock.update_global(update))
155 }
156}
157
158#[derive(Clone, Deref, DerefMut)]
159pub struct AsyncWindowContext {
160 #[deref]
161 #[deref_mut]
162 app: AsyncAppContext,
163 window: AnyWindowHandle,
164}
165
166impl AsyncWindowContext {
167 pub(crate) fn new(app: AsyncAppContext, window: AnyWindowHandle) -> Self {
168 Self { app, window }
169 }
170
171 pub fn update<R>(&self, update: impl FnOnce(&mut WindowContext) -> R) -> Result<R> {
172 self.app.update_window(self.window, update)
173 }
174
175 pub fn on_next_frame(&mut self, f: impl FnOnce(&mut WindowContext) + Send + 'static) {
176 self.app
177 .update_window(self.window, |cx| cx.on_next_frame(f))
178 .ok();
179 }
180
181 pub fn read_global<G: 'static, R>(
182 &self,
183 read: impl FnOnce(&G, &WindowContext) -> R,
184 ) -> Result<R> {
185 self.app
186 .read_window(self.window, |cx| read(cx.global(), cx))
187 }
188
189 pub fn update_global<G, R>(
190 &mut self,
191 update: impl FnOnce(&mut G, &mut WindowContext) -> R,
192 ) -> Result<R>
193 where
194 G: 'static,
195 {
196 self.app
197 .update_window(self.window, |cx| cx.update_global(update))
198 }
199
200 pub fn spawn<Fut, R>(
201 &self,
202 f: impl FnOnce(AsyncWindowContext) -> Fut + Send + 'static,
203 ) -> Task<R>
204 where
205 Fut: Future<Output = R> + Send + 'static,
206 R: Send + 'static,
207 {
208 let this = self.clone();
209 self.executor.spawn(async move { f(this).await })
210 }
211
212 pub fn spawn_on_main<Fut, R>(
213 &self,
214 f: impl FnOnce(AsyncWindowContext) -> Fut + Send + 'static,
215 ) -> Task<R>
216 where
217 Fut: Future<Output = R> + 'static,
218 R: Send + 'static,
219 {
220 let this = self.clone();
221 self.executor.spawn_on_main(|| f(this))
222 }
223
224 pub fn run_on_main<R>(
225 &self,
226 f: impl FnOnce(&mut MainThread<WindowContext>) -> R + Send + 'static,
227 ) -> Task<Result<R>>
228 where
229 R: Send + 'static,
230 {
231 self.update(|cx| cx.run_on_main(f))
232 .unwrap_or_else(|error| Task::ready(Err(error)))
233 }
234}
235
236impl Context for AsyncWindowContext {
237 type EntityContext<'a, T> = ModelContext<'a, T>;
238 type Result<T> = Result<T>;
239
240 fn entity<T>(
241 &mut self,
242 build_entity: impl FnOnce(&mut Self::EntityContext<'_, T>) -> T,
243 ) -> Result<Handle<T>>
244 where
245 T: 'static + Send,
246 {
247 self.app
248 .update_window(self.window, |cx| cx.entity(build_entity))
249 }
250
251 fn update_entity<T: 'static, R>(
252 &mut self,
253 handle: &Handle<T>,
254 update: impl FnOnce(&mut T, &mut Self::EntityContext<'_, T>) -> R,
255 ) -> Result<R> {
256 self.app
257 .update_window(self.window, |cx| cx.update_entity(handle, update))
258 }
259}
260
261impl VisualContext for AsyncWindowContext {
262 type ViewContext<'a, 'w, V> = ViewContext<'a, 'w, V>;
263
264 fn build_view<E, V>(
265 &mut self,
266 build_entity: impl FnOnce(&mut Self::ViewContext<'_, '_, V>) -> V,
267 render: impl Fn(&mut V, &mut ViewContext<'_, '_, V>) -> E + Send + 'static,
268 ) -> Self::Result<View<V>>
269 where
270 E: Component<V>,
271 V: 'static + Send,
272 {
273 self.app
274 .update_window(self.window, |cx| cx.build_view(build_entity, render))
275 }
276
277 fn update_view<V: 'static, R>(
278 &mut self,
279 view: &View<V>,
280 update: impl FnOnce(&mut V, &mut Self::ViewContext<'_, '_, V>) -> R,
281 ) -> Self::Result<R> {
282 self.app
283 .update_window(self.window, |cx| cx.update_view(view, update))
284 }
285}
286
287#[cfg(test)]
288mod tests {
289 use super::*;
290
291 #[test]
292 fn test_async_app_context_send_sync() {
293 fn assert_send_sync<T: Send + Sync>() {}
294 assert_send_sync::<AsyncAppContext>();
295 }
296}