1use crate::{
2 AnyWindowHandle, AppContext, Context, Executor, MainThread, Model, ModelContext, Result, Task,
3 WindowContext,
4};
5use anyhow::anyhow;
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
28 .app
29 .upgrade()
30 .ok_or_else(|| anyhow!("app was released"))?;
31 let mut lock = app.lock(); // Need this to compile
32 Ok(lock.build_model(build_model))
33 }
34
35 fn update_model<T: 'static, R>(
36 &mut self,
37 handle: &Model<T>,
38 update: impl FnOnce(&mut T, &mut Self::ModelContext<'_, T>) -> R,
39 ) -> Self::Result<R> {
40 let app = self
41 .app
42 .upgrade()
43 .ok_or_else(|| anyhow!("app was released"))?;
44 let mut lock = app.lock(); // Need this to compile
45 Ok(lock.update_model(handle, update))
46 }
47}
48
49impl AsyncAppContext {
50 pub fn refresh(&mut self) -> Result<()> {
51 let app = self
52 .app
53 .upgrade()
54 .ok_or_else(|| anyhow!("app was released"))?;
55 let mut lock = app.lock(); // Need this to compile
56 lock.refresh();
57 Ok(())
58 }
59
60 pub fn executor(&self) -> &Executor {
61 &self.executor
62 }
63
64 pub fn update<R>(&self, f: impl FnOnce(&mut AppContext) -> R) -> Result<R> {
65 let app = self
66 .app
67 .upgrade()
68 .ok_or_else(|| anyhow!("app was released"))?;
69 let mut lock = app.lock();
70 Ok(f(&mut *lock))
71 }
72
73 pub fn read_window<R>(
74 &self,
75 handle: AnyWindowHandle,
76 update: impl FnOnce(&WindowContext) -> R,
77 ) -> Result<R> {
78 let app = self
79 .app
80 .upgrade()
81 .ok_or_else(|| anyhow!("app was released"))?;
82 let mut app_context = app.lock();
83 app_context.read_window(handle.id, update)
84 }
85
86 pub fn update_window<R>(
87 &self,
88 handle: AnyWindowHandle,
89 update: impl FnOnce(&mut WindowContext) -> R,
90 ) -> Result<R> {
91 let app = self
92 .app
93 .upgrade()
94 .ok_or_else(|| anyhow!("app was released"))?;
95 let mut app_context = app.lock();
96 app_context.update_window(handle.id, update)
97 }
98
99 pub fn spawn<Fut, R>(&self, f: impl FnOnce(AsyncAppContext) -> Fut + Send + 'static) -> Task<R>
100 where
101 Fut: Future<Output = R> + Send + 'static,
102 R: Send + 'static,
103 {
104 let this = self.clone();
105 self.executor.spawn(async move { f(this).await })
106 }
107
108 pub fn spawn_on_main<Fut, R>(
109 &self,
110 f: impl FnOnce(AsyncAppContext) -> Fut + Send + 'static,
111 ) -> Task<R>
112 where
113 Fut: Future<Output = R> + 'static,
114 R: Send + 'static,
115 {
116 let this = self.clone();
117 self.executor.spawn_on_main(|| f(this))
118 }
119
120 pub fn run_on_main<R>(
121 &self,
122 f: impl FnOnce(&mut MainThread<AppContext>) -> R + Send + 'static,
123 ) -> Result<Task<R>>
124 where
125 R: Send + 'static,
126 {
127 let app = self
128 .app
129 .upgrade()
130 .ok_or_else(|| anyhow!("app was released"))?;
131 let mut app_context = app.lock();
132 Ok(app_context.run_on_main(f))
133 }
134
135 pub fn has_global<G: 'static>(&self) -> Result<bool> {
136 let app = self
137 .app
138 .upgrade()
139 .ok_or_else(|| anyhow!("app was released"))?;
140 let lock = app.lock(); // Need this to compile
141 Ok(lock.has_global::<G>())
142 }
143
144 pub fn read_global<G: 'static, R>(&self, read: impl FnOnce(&G, &AppContext) -> R) -> Result<R> {
145 let app = self
146 .app
147 .upgrade()
148 .ok_or_else(|| anyhow!("app was released"))?;
149 let lock = app.lock(); // Need this to compile
150 Ok(read(lock.global(), &lock))
151 }
152
153 pub fn try_read_global<G: 'static, R>(
154 &self,
155 read: impl FnOnce(&G, &AppContext) -> R,
156 ) -> Option<R> {
157 let app = self.app.upgrade()?;
158 let lock = app.lock(); // Need this to compile
159 Some(read(lock.try_global()?, &lock))
160 }
161
162 pub fn update_global<G: 'static, R>(
163 &mut self,
164 update: impl FnOnce(&mut G, &mut AppContext) -> R,
165 ) -> Result<R> {
166 let app = self
167 .app
168 .upgrade()
169 .ok_or_else(|| anyhow!("app was released"))?;
170 let mut lock = app.lock(); // Need this to compile
171 Ok(lock.update_global(update))
172 }
173}
174
175#[derive(Clone, Deref, DerefMut)]
176pub struct AsyncWindowContext {
177 #[deref]
178 #[deref_mut]
179 app: AsyncAppContext,
180 window: AnyWindowHandle,
181}
182
183impl AsyncWindowContext {
184 pub(crate) fn new(app: AsyncAppContext, window: AnyWindowHandle) -> Self {
185 Self { app, window }
186 }
187
188 pub fn update<R>(&self, update: impl FnOnce(&mut WindowContext) -> R) -> Result<R> {
189 self.app.update_window(self.window, update)
190 }
191
192 pub fn on_next_frame(&mut self, f: impl FnOnce(&mut WindowContext) + Send + 'static) {
193 self.app
194 .update_window(self.window, |cx| cx.on_next_frame(f))
195 .ok();
196 }
197
198 pub fn read_global<G: 'static, R>(
199 &self,
200 read: impl FnOnce(&G, &WindowContext) -> R,
201 ) -> Result<R> {
202 self.app
203 .read_window(self.window, |cx| read(cx.global(), cx))
204 }
205
206 pub fn update_global<G, R>(
207 &mut self,
208 update: impl FnOnce(&mut G, &mut WindowContext) -> R,
209 ) -> Result<R>
210 where
211 G: 'static,
212 {
213 self.app
214 .update_window(self.window, |cx| cx.update_global(update))
215 }
216}
217
218impl Context for AsyncWindowContext {
219 type ModelContext<'a, T> = ModelContext<'a, T>;
220 type Result<T> = Result<T>;
221
222 fn build_model<T>(
223 &mut self,
224 build_model: impl FnOnce(&mut Self::ModelContext<'_, T>) -> T,
225 ) -> Result<Model<T>>
226 where
227 T: 'static + Send,
228 {
229 self.app
230 .update_window(self.window, |cx| cx.build_model(build_model))
231 }
232
233 fn update_model<T: 'static, R>(
234 &mut self,
235 handle: &Model<T>,
236 update: impl FnOnce(&mut T, &mut Self::ModelContext<'_, T>) -> R,
237 ) -> Result<R> {
238 self.app
239 .update_window(self.window, |cx| cx.update_model(handle, update))
240 }
241}
242
243#[cfg(test)]
244mod tests {
245 use super::*;
246
247 #[test]
248 fn test_async_app_context_send_sync() {
249 fn assert_send_sync<T: Send + Sync>() {}
250 assert_send_sync::<AsyncAppContext>();
251 }
252}