1use crate::{
2 AnyWindowHandle, AppContext, Context, Executor, Handle, MainThread, ModelContext, Result, Task,
3 WindowContext,
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 spawn<Fut, R>(&self, f: impl FnOnce(AsyncAppContext) -> Fut + Send + 'static) -> Task<R>
82 where
83 Fut: Future<Output = R> + Send + 'static,
84 R: Send + 'static,
85 {
86 let this = self.clone();
87 self.executor.spawn(async move { f(this).await })
88 }
89
90 pub fn spawn_on_main<Fut, R>(
91 &self,
92 f: impl FnOnce(AsyncAppContext) -> Fut + Send + 'static,
93 ) -> Task<R>
94 where
95 Fut: Future<Output = R> + 'static,
96 R: Send + 'static,
97 {
98 let this = self.clone();
99 self.executor.spawn_on_main(|| f(this))
100 }
101
102 pub fn run_on_main<R>(
103 &self,
104 f: impl FnOnce(&mut MainThread<AppContext>) -> R + Send + 'static,
105 ) -> Result<Task<R>>
106 where
107 R: Send + 'static,
108 {
109 let app = self.app.upgrade().context("app was released")?;
110 let mut app_context = app.lock();
111 Ok(app_context.run_on_main(f))
112 }
113
114 pub fn has_global<G: 'static>(&self) -> Result<bool> {
115 let app = self.app.upgrade().context("app was released")?;
116 let lock = app.lock(); // Need this to compile
117 Ok(lock.has_global::<G>())
118 }
119
120 pub fn read_global<G: 'static, R>(&self, read: impl FnOnce(&G, &AppContext) -> R) -> Result<R> {
121 let app = self.app.upgrade().context("app was released")?;
122 let lock = app.lock(); // Need this to compile
123 Ok(read(lock.global(), &lock))
124 }
125
126 pub fn try_read_global<G: 'static, R>(
127 &self,
128 read: impl FnOnce(&G, &AppContext) -> R,
129 ) -> Option<R> {
130 let app = self.app.upgrade()?;
131 let lock = app.lock(); // Need this to compile
132 Some(read(lock.try_global()?, &lock))
133 }
134
135 pub fn update_global<G: 'static, R>(
136 &mut self,
137 update: impl FnOnce(&mut G, &mut AppContext) -> R,
138 ) -> Result<R> {
139 let app = self.app.upgrade().context("app was released")?;
140 let mut lock = app.lock(); // Need this to compile
141 Ok(lock.update_global(update))
142 }
143}
144
145#[derive(Clone, Deref, DerefMut)]
146pub struct AsyncWindowContext {
147 #[deref]
148 #[deref_mut]
149 app: AsyncAppContext,
150 window: AnyWindowHandle,
151}
152
153impl AsyncWindowContext {
154 pub(crate) fn new(app: AsyncAppContext, window: AnyWindowHandle) -> Self {
155 Self { app, window }
156 }
157
158 pub fn update<R>(&self, update: impl FnOnce(&mut WindowContext) -> R) -> Result<R> {
159 self.app.update_window(self.window, update)
160 }
161
162 pub fn on_next_frame(&mut self, f: impl FnOnce(&mut WindowContext) + Send + 'static) {
163 self.app
164 .update_window(self.window, |cx| cx.on_next_frame(f))
165 .ok();
166 }
167
168 pub fn read_global<G: 'static, R>(
169 &self,
170 read: impl FnOnce(&G, &WindowContext) -> R,
171 ) -> Result<R> {
172 self.app
173 .read_window(self.window, |cx| read(cx.global(), cx))
174 }
175
176 pub fn update_global<G, R>(
177 &mut self,
178 update: impl FnOnce(&mut G, &mut WindowContext) -> R,
179 ) -> Result<R>
180 where
181 G: 'static,
182 {
183 self.app
184 .update_window(self.window, |cx| cx.update_global(update))
185 }
186
187 pub fn spawn<Fut, R>(
188 &self,
189 f: impl FnOnce(AsyncWindowContext) -> Fut + Send + 'static,
190 ) -> Task<R>
191 where
192 Fut: Future<Output = R> + Send + 'static,
193 R: Send + 'static,
194 {
195 let this = self.clone();
196 self.executor.spawn(async move { f(this).await })
197 }
198
199 pub fn spawn_on_main<Fut, R>(
200 &self,
201 f: impl FnOnce(AsyncWindowContext) -> Fut + Send + 'static,
202 ) -> Task<R>
203 where
204 Fut: Future<Output = R> + 'static,
205 R: Send + 'static,
206 {
207 let this = self.clone();
208 self.executor.spawn_on_main(|| f(this))
209 }
210
211 pub fn run_on_main<R>(
212 &self,
213 f: impl FnOnce(&mut MainThread<WindowContext>) -> R + Send + 'static,
214 ) -> Task<Result<R>>
215 where
216 R: Send + 'static,
217 {
218 self.update(|cx| cx.run_on_main(f))
219 .unwrap_or_else(|error| Task::ready(Err(error)))
220 }
221}
222
223impl Context for AsyncWindowContext {
224 type EntityContext<'a, T> = ModelContext<'a, T>;
225 type Result<T> = Result<T>;
226
227 fn entity<T>(
228 &mut self,
229 build_entity: impl FnOnce(&mut Self::EntityContext<'_, T>) -> T,
230 ) -> Result<Handle<T>>
231 where
232 T: 'static + Send,
233 {
234 self.app
235 .update_window(self.window, |cx| cx.entity(build_entity))
236 }
237
238 fn update_entity<T: 'static, R>(
239 &mut self,
240 handle: &Handle<T>,
241 update: impl FnOnce(&mut T, &mut Self::EntityContext<'_, T>) -> R,
242 ) -> Result<R> {
243 self.app
244 .update_window(self.window, |cx| cx.update_entity(handle, update))
245 }
246}
247
248#[cfg(test)]
249mod tests {
250 use super::*;
251
252 #[test]
253 fn test_async_app_context_send_sync() {
254 fn assert_send_sync<T: Send + Sync>() {}
255 assert_send_sync::<AsyncAppContext>();
256 }
257}