1use crate::{
2 AnyWindowHandle, AppContext, Context, Executor, MainThread, Model, ModelContext, Result, Task,
3 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 ModelContext<'a, T> = ModelContext<'a, T>;
18 type Result<T> = Result<T>;
19
20 fn build_model<T: 'static>(
21 &mut self,
22 build_model: impl FnOnce(&mut Self::ModelContext<'_, T>) -> T,
23 ) -> Self::Result<Model<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.build_model(build_model))
30 }
31
32 fn update_model<T: 'static, R>(
33 &mut self,
34 handle: &Model<T>,
35 update: impl FnOnce(&mut T, &mut Self::ModelContext<'_, 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_model(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 update_window<R>(
62 &self,
63 handle: AnyWindowHandle,
64 update: impl FnOnce(&mut 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.update_window(handle, update)
69 }
70
71 pub fn update_window_root<V, R>(
72 &mut self,
73 handle: &WindowHandle<V>,
74 update: impl FnOnce(&mut V, &mut ViewContext<'_, V>) -> R,
75 ) -> Result<R>
76 where
77 V: 'static + Send,
78 {
79 let app = self.app.upgrade().context("app was released")?;
80 let mut app_context = app.lock();
81 app_context.update_window_root(handle, update)
82 }
83
84 pub fn spawn<Fut, R>(&self, f: impl FnOnce(AsyncAppContext) -> Fut + Send + 'static) -> Task<R>
85 where
86 Fut: Future<Output = R> + Send + 'static,
87 R: Send + 'static,
88 {
89 let this = self.clone();
90 self.executor.spawn(async move { f(this).await })
91 }
92
93 pub fn spawn_on_main<Fut, R>(
94 &self,
95 f: impl FnOnce(AsyncAppContext) -> Fut + Send + 'static,
96 ) -> Task<R>
97 where
98 Fut: Future<Output = R> + 'static,
99 R: Send + 'static,
100 {
101 let this = self.clone();
102 self.executor.spawn_on_main(|| f(this))
103 }
104
105 pub fn run_on_main<R>(
106 &self,
107 f: impl FnOnce(&mut MainThread<AppContext>) -> R + Send + 'static,
108 ) -> Result<Task<R>>
109 where
110 R: Send + 'static,
111 {
112 let app = self.app.upgrade().context("app was released")?;
113 let mut app_context = app.lock();
114 Ok(app_context.run_on_main(f))
115 }
116
117 pub fn has_global<G: 'static>(&self) -> Result<bool> {
118 let app = self.app.upgrade().context("app was released")?;
119 let lock = app.lock(); // Need this to compile
120 Ok(lock.has_global::<G>())
121 }
122
123 pub fn read_global<G: 'static, R>(&self, read: impl FnOnce(&G, &AppContext) -> R) -> Result<R> {
124 let app = self.app.upgrade().context("app was released")?;
125 let lock = app.lock(); // Need this to compile
126 Ok(read(lock.global(), &lock))
127 }
128
129 pub fn try_read_global<G: 'static, R>(
130 &self,
131 read: impl FnOnce(&G, &AppContext) -> R,
132 ) -> Option<R> {
133 let app = self.app.upgrade()?;
134 let lock = app.lock(); // Need this to compile
135 Some(read(lock.try_global()?, &lock))
136 }
137
138 pub fn update_global<G: 'static, R>(
139 &mut self,
140 update: impl FnOnce(&mut G, &mut AppContext) -> R,
141 ) -> Result<R> {
142 let app = self.app.upgrade().context("app was released")?;
143 let mut lock = app.lock(); // Need this to compile
144 Ok(lock.update_global(update))
145 }
146}
147
148#[derive(Clone, Deref, DerefMut)]
149pub struct AsyncWindowContext {
150 #[deref]
151 #[deref_mut]
152 app: AsyncAppContext,
153 window: AnyWindowHandle,
154}
155
156impl AsyncWindowContext {
157 pub(crate) fn new(app: AsyncAppContext, window: AnyWindowHandle) -> Self {
158 Self { app, window }
159 }
160
161 pub fn update<R>(&self, update: impl FnOnce(&mut WindowContext) -> R) -> Result<R> {
162 self.app.update_window(self.window, update)
163 }
164
165 pub fn on_next_frame(&mut self, f: impl FnOnce(&mut WindowContext) + Send + 'static) {
166 self.app
167 .update_window(self.window, |cx| cx.on_next_frame(f))
168 .ok();
169 }
170
171 pub fn read_global<G: 'static, R>(
172 &self,
173 read: impl FnOnce(&G, &WindowContext) -> R,
174 ) -> Result<R> {
175 self.app
176 .update_window(self.window, |cx| read(cx.global(), cx))
177 }
178
179 pub fn update_global<G, R>(
180 &mut self,
181 update: impl FnOnce(&mut G, &mut WindowContext) -> R,
182 ) -> Result<R>
183 where
184 G: 'static,
185 {
186 self.app
187 .update_window(self.window, |cx| cx.update_global(update))
188 }
189
190 pub fn spawn<Fut, R>(
191 &self,
192 f: impl FnOnce(AsyncWindowContext) -> Fut + Send + 'static,
193 ) -> Task<R>
194 where
195 Fut: Future<Output = R> + Send + 'static,
196 R: Send + 'static,
197 {
198 let this = self.clone();
199 self.executor.spawn(async move { f(this).await })
200 }
201
202 pub fn spawn_on_main<Fut, R>(
203 &self,
204 f: impl FnOnce(AsyncWindowContext) -> Fut + Send + 'static,
205 ) -> Task<R>
206 where
207 Fut: Future<Output = R> + 'static,
208 R: Send + 'static,
209 {
210 let this = self.clone();
211 self.executor.spawn_on_main(|| f(this))
212 }
213
214 pub fn run_on_main<R>(
215 &self,
216 f: impl FnOnce(&mut MainThread<WindowContext>) -> R + Send + 'static,
217 ) -> Task<Result<R>>
218 where
219 R: Send + 'static,
220 {
221 self.update(|cx| cx.run_on_main(f))
222 .unwrap_or_else(|error| Task::ready(Err(error)))
223 }
224}
225
226impl Context for AsyncWindowContext {
227 type ModelContext<'a, T> = ModelContext<'a, T>;
228 type Result<T> = Result<T>;
229
230 fn build_model<T>(
231 &mut self,
232 build_model: impl FnOnce(&mut Self::ModelContext<'_, T>) -> T,
233 ) -> Result<Model<T>>
234 where
235 T: 'static + Send,
236 {
237 self.app
238 .update_window(self.window, |cx| cx.build_model(build_model))
239 }
240
241 fn update_model<T: 'static, R>(
242 &mut self,
243 handle: &Model<T>,
244 update: impl FnOnce(&mut T, &mut Self::ModelContext<'_, T>) -> R,
245 ) -> Result<R> {
246 self.app
247 .update_window(self.window, |cx| cx.update_model(handle, update))
248 }
249}
250
251impl VisualContext for AsyncWindowContext {
252 type ViewContext<'a, V: 'static> = ViewContext<'a, V>;
253
254 fn build_view<V>(
255 &mut self,
256 build_view_state: impl FnOnce(&mut Self::ViewContext<'_, V>) -> V,
257 ) -> Self::Result<View<V>>
258 where
259 V: 'static + Send,
260 {
261 self.app
262 .update_window(self.window, |cx| cx.build_view(build_view_state))
263 }
264
265 fn update_view<V: 'static, R>(
266 &mut self,
267 view: &View<V>,
268 update: impl FnOnce(&mut V, &mut Self::ViewContext<'_, V>) -> R,
269 ) -> Self::Result<R> {
270 self.app
271 .update_window(self.window, |cx| cx.update_view(view, update))
272 }
273}
274
275#[cfg(test)]
276mod tests {
277 use super::*;
278
279 #[test]
280 fn test_async_app_context_send_sync() {
281 fn assert_send_sync<T: Send + Sync>() {}
282 assert_send_sync::<AsyncAppContext>();
283 }
284}