1use crate::{
2 AnyView, AnyWindowHandle, AppContext, Context, Executor, MainThread, Model, ModelContext,
3 Render, 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, mem, 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 WindowContext<'a> = WindowContext<'a>;
18 type ModelContext<'a, T> = ModelContext<'a, T>;
19 type Result<T> = Result<T>;
20
21 fn build_model<T: 'static>(
22 &mut self,
23 build_model: impl FnOnce(&mut Self::ModelContext<'_, T>) -> T,
24 ) -> Self::Result<Model<T>>
25 where
26 T: 'static + Send,
27 {
28 let app = self.app.upgrade().context("app was released")?;
29 let mut lock = app.lock(); // Need this to compile
30 Ok(lock.build_model(build_model))
31 }
32
33 fn update_model<T: 'static, R>(
34 &mut self,
35 handle: &Model<T>,
36 update: impl FnOnce(&mut T, &mut Self::ModelContext<'_, T>) -> R,
37 ) -> Self::Result<R> {
38 let app = self.app.upgrade().context("app was released")?;
39 let mut lock = app.lock(); // Need this to compile
40 Ok(lock.update_model(handle, update))
41 }
42
43 fn update_window<T, F>(&mut self, window: AnyWindowHandle, f: F) -> Result<T>
44 where
45 F: FnOnce(AnyView, &mut Self::WindowContext<'_>) -> T,
46 {
47 let app = self.app.upgrade().context("app was released")?;
48 let mut lock = app.lock(); // Need this to compile
49 lock.update_window(window, f)
50 }
51}
52
53impl AsyncAppContext {
54 pub fn refresh(&mut self) -> Result<()> {
55 let app = self.app.upgrade().context("app was released")?;
56 let mut lock = app.lock(); // Need this to compile
57 lock.refresh();
58 Ok(())
59 }
60
61 pub fn executor(&self) -> &Executor {
62 &self.executor
63 }
64
65 pub fn update<R>(&self, f: impl FnOnce(&mut AppContext) -> R) -> Result<R> {
66 let app = self.app.upgrade().context("app was released")?;
67 let mut lock = app.lock();
68 Ok(f(&mut *lock))
69 }
70
71 pub fn spawn<Fut, R>(&self, f: impl FnOnce(AsyncAppContext) -> Fut + Send + 'static) -> Task<R>
72 where
73 Fut: Future<Output = R> + Send + 'static,
74 R: Send + 'static,
75 {
76 let this = self.clone();
77 self.executor.spawn(async move { f(this).await })
78 }
79
80 pub fn spawn_on_main<Fut, R>(
81 &self,
82 f: impl FnOnce(MainThread<AsyncAppContext>) -> Fut + Send + 'static,
83 ) -> Task<R>
84 where
85 Fut: Future<Output = R> + 'static,
86 R: Send + 'static,
87 {
88 let this = self.clone();
89 self.executor.spawn_on_main(|| f(MainThread(this)))
90 }
91
92 pub fn run_on_main<R>(
93 &self,
94 f: impl FnOnce(&mut MainThread<AppContext>) -> R + Send + 'static,
95 ) -> Result<Task<R>>
96 where
97 R: Send + 'static,
98 {
99 let app = self.app.upgrade().context("app was released")?;
100 let mut app_context = app.lock();
101 Ok(app_context.run_on_main(f))
102 }
103
104 pub fn has_global<G: 'static>(&self) -> Result<bool> {
105 let app = self.app.upgrade().context("app was released")?;
106 let lock = app.lock(); // Need this to compile
107 Ok(lock.has_global::<G>())
108 }
109
110 pub fn read_global<G: 'static, R>(&self, read: impl FnOnce(&G, &AppContext) -> R) -> Result<R> {
111 let app = self.app.upgrade().context("app was released")?;
112 let lock = app.lock(); // Need this to compile
113 Ok(read(lock.global(), &lock))
114 }
115
116 pub fn try_read_global<G: 'static, R>(
117 &self,
118 read: impl FnOnce(&G, &AppContext) -> R,
119 ) -> Option<R> {
120 let app = self.app.upgrade()?;
121 let lock = app.lock(); // Need this to compile
122 Some(read(lock.try_global()?, &lock))
123 }
124
125 pub fn update_global<G: 'static, R>(
126 &mut self,
127 update: impl FnOnce(&mut G, &mut AppContext) -> R,
128 ) -> Result<R> {
129 let app = self.app.upgrade().context("app was released")?;
130 let mut lock = app.lock(); // Need this to compile
131 Ok(lock.update_global(update))
132 }
133}
134
135impl MainThread<AsyncAppContext> {
136 pub fn update<R>(&self, f: impl FnOnce(&mut MainThread<AppContext>) -> R) -> Result<R> {
137 let app = self.app.upgrade().context("app was released")?;
138 let cx = &mut *app.lock();
139 let cx = unsafe { mem::transmute::<&mut AppContext, &mut MainThread<AppContext>>(cx) };
140 Ok(f(cx))
141 }
142
143 /// Opens a new window with the given option and the root view returned by the given function.
144 /// The function is invoked with a `WindowContext`, which can be used to interact with window-specific
145 /// functionality.
146 pub fn open_window<V: Render>(
147 &mut self,
148 options: crate::WindowOptions,
149 build_root_view: impl FnOnce(&mut MainThread<WindowContext>) -> View<V> + Send + 'static,
150 ) -> Result<WindowHandle<V>> {
151 let app = self.app.upgrade().context("app was released")?;
152 let cx = &mut *app.lock();
153 let cx = unsafe { mem::transmute::<&mut AppContext, &mut MainThread<AppContext>>(cx) };
154 Ok(cx.open_window(options, build_root_view))
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>(
172 &mut self,
173 update: impl FnOnce(AnyView, &mut WindowContext) -> R,
174 ) -> Result<R> {
175 self.app.update_window(self.window, update)
176 }
177
178 pub fn on_next_frame(&mut self, f: impl FnOnce(&mut WindowContext) + Send + 'static) {
179 self.app
180 .update_window(self.window, |_root, cx| cx.on_next_frame(f))
181 .ok();
182 }
183
184 pub fn read_global<G: 'static, R>(
185 &mut self,
186 read: impl FnOnce(&G, &WindowContext) -> R,
187 ) -> Result<R> {
188 self.app
189 .update_window(self.window, |_, cx| read(cx.global(), cx))
190 }
191
192 pub fn update_global<G, R>(
193 &mut self,
194 update: impl FnOnce(&mut G, &mut WindowContext) -> R,
195 ) -> Result<R>
196 where
197 G: 'static,
198 {
199 self.app
200 .update_window(self.window, |_, cx| cx.update_global(update))
201 }
202
203 pub fn spawn<Fut, R>(
204 &self,
205 f: impl FnOnce(AsyncWindowContext) -> Fut + Send + 'static,
206 ) -> Task<R>
207 where
208 Fut: Future<Output = R> + Send + 'static,
209 R: Send + 'static,
210 {
211 let this = self.clone();
212 self.executor.spawn(async move { f(this).await })
213 }
214
215 pub fn spawn_on_main<Fut, R>(
216 &self,
217 f: impl FnOnce(AsyncWindowContext) -> Fut + Send + 'static,
218 ) -> Task<R>
219 where
220 Fut: Future<Output = R> + 'static,
221 R: Send + 'static,
222 {
223 let this = self.clone();
224 self.executor.spawn_on_main(|| f(this))
225 }
226
227 pub fn run_on_main<R>(
228 &mut self,
229 f: impl FnOnce(&mut MainThread<WindowContext>) -> R + Send + 'static,
230 ) -> Task<Result<R>>
231 where
232 R: Send + 'static,
233 {
234 self.update(|_, cx| cx.run_on_main(f))
235 .unwrap_or_else(|error| Task::ready(Err(error)))
236 }
237}
238
239impl Context for AsyncWindowContext {
240 type WindowContext<'a> = WindowContext<'a>;
241 type ModelContext<'a, T> = ModelContext<'a, T>;
242
243 type Result<T> = Result<T>;
244
245 fn build_model<T>(
246 &mut self,
247 build_model: impl FnOnce(&mut Self::ModelContext<'_, T>) -> T,
248 ) -> Result<Model<T>>
249 where
250 T: 'static + Send,
251 {
252 self.app
253 .update_window(self.window, |_, cx| cx.build_model(build_model))
254 }
255
256 fn update_model<T: 'static, R>(
257 &mut self,
258 handle: &Model<T>,
259 update: impl FnOnce(&mut T, &mut Self::ModelContext<'_, T>) -> R,
260 ) -> Result<R> {
261 self.app
262 .update_window(self.window, |_, cx| cx.update_model(handle, update))
263 }
264
265 fn update_window<T, F>(&mut self, window: AnyWindowHandle, update: F) -> Result<T>
266 where
267 F: FnOnce(AnyView, &mut Self::WindowContext<'_>) -> T,
268 {
269 self.app.update_window(window, update)
270 }
271}
272
273impl VisualContext for AsyncWindowContext {
274 type ViewContext<'a, V: 'static> = ViewContext<'a, V>;
275
276 fn build_view<V>(
277 &mut self,
278 build_view_state: impl FnOnce(&mut Self::ViewContext<'_, V>) -> V,
279 ) -> Self::Result<View<V>>
280 where
281 V: 'static + Send,
282 {
283 self.app
284 .update_window(self.window, |_, cx| cx.build_view(build_view_state))
285 }
286
287 fn update_view<V: 'static, R>(
288 &mut self,
289 view: &View<V>,
290 update: impl FnOnce(&mut V, &mut Self::ViewContext<'_, V>) -> R,
291 ) -> Self::Result<R> {
292 self.app
293 .update_window(self.window, |_, cx| cx.update_view(view, update))
294 }
295
296 fn replace_root_view<V>(
297 &mut self,
298 build_view: impl FnOnce(&mut Self::ViewContext<'_, V>) -> V,
299 ) -> Self::Result<View<V>>
300 where
301 V: 'static + Send + Render,
302 {
303 self.app
304 .update_window(self.window, |_, cx| cx.replace_root_view(build_view))
305 }
306}
307
308#[cfg(test)]
309mod tests {
310 use super::*;
311
312 #[test]
313 fn test_async_app_context_send_sync() {
314 fn assert_send_sync<T: Send + Sync>() {}
315 assert_send_sync::<AsyncAppContext>();
316 }
317}