1use crate::{
2 AnyWindowHandle, AppContext, Context, Executor, Handle, MainThread, ModelContext, Result, Task,
3 ViewContext, 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 EntityContext<'a, 'w, T: 'static + Send + Sync> = ModelContext<'a, T>;
18 type Result<T> = Result<T>;
19
20 fn entity<T: Send + Sync + 'static>(
21 &mut self,
22 build_entity: impl FnOnce(&mut Self::EntityContext<'_, '_, T>) -> T,
23 ) -> Self::Result<Handle<T>> {
24 let app = self
25 .app
26 .upgrade()
27 .ok_or_else(|| anyhow!("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: Send + Sync + '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
38 .app
39 .upgrade()
40 .ok_or_else(|| anyhow!("app was released"))?;
41 let mut lock = app.lock(); // Need this to compile
42 Ok(lock.update_entity(handle, update))
43 }
44}
45
46impl AsyncAppContext {
47 pub fn refresh(&mut self) -> Result<()> {
48 let app = self
49 .app
50 .upgrade()
51 .ok_or_else(|| anyhow!("app was released"))?;
52 let mut lock = app.lock(); // Need this to compile
53 lock.refresh();
54 Ok(())
55 }
56
57 pub fn executor(&self) -> &Executor {
58 &self.executor
59 }
60
61 pub fn update<R>(&self, f: impl FnOnce(&mut AppContext) -> R) -> Result<R> {
62 let app = self
63 .app
64 .upgrade()
65 .ok_or_else(|| anyhow!("app was released"))?;
66 let mut lock = app.lock();
67 Ok(f(&mut *lock))
68 }
69
70 pub fn read_window<R>(
71 &self,
72 handle: AnyWindowHandle,
73 update: impl FnOnce(&WindowContext) -> R,
74 ) -> Result<R> {
75 let app = self
76 .app
77 .upgrade()
78 .ok_or_else(|| anyhow!("app was released"))?;
79 let mut app_context = app.lock();
80 app_context.read_window(handle.id, update)
81 }
82
83 pub fn update_window<R>(
84 &self,
85 handle: AnyWindowHandle,
86 update: impl FnOnce(&mut WindowContext) -> R,
87 ) -> Result<R> {
88 let app = self
89 .app
90 .upgrade()
91 .ok_or_else(|| anyhow!("app was released"))?;
92 let mut app_context = app.lock();
93 app_context.update_window(handle.id, update)
94 }
95
96 pub fn spawn<Fut, R>(&self, f: impl FnOnce(AsyncAppContext) -> Fut + Send + 'static) -> Task<R>
97 where
98 Fut: Future<Output = R> + Send + 'static,
99 R: Send + 'static,
100 {
101 let this = self.clone();
102 self.executor.spawn(async move { f(this).await })
103 }
104
105 pub fn spawn_on_main<Fut, R>(
106 &self,
107 f: impl FnOnce(AsyncAppContext) -> Fut + Send + 'static,
108 ) -> Task<R>
109 where
110 Fut: Future<Output = R> + 'static,
111 R: Send + 'static,
112 {
113 let this = self.clone();
114 self.executor.spawn_on_main(|| f(this))
115 }
116
117 pub fn run_on_main<R>(
118 &self,
119 f: impl FnOnce(&mut MainThread<AppContext>) -> R + Send + 'static,
120 ) -> Result<Task<R>>
121 where
122 R: Send + 'static,
123 {
124 let app = self
125 .app
126 .upgrade()
127 .ok_or_else(|| anyhow!("app was released"))?;
128 let mut app_context = app.lock();
129 Ok(app_context.run_on_main(f))
130 }
131
132 pub fn has_global<G: 'static + Send + Sync>(&self) -> Result<bool> {
133 let app = self
134 .app
135 .upgrade()
136 .ok_or_else(|| anyhow!("app was released"))?;
137 let lock = app.lock(); // Need this to compile
138 Ok(lock.has_global::<G>())
139 }
140
141 pub fn read_global<G: 'static + Send + Sync, R>(
142 &self,
143 read: impl FnOnce(&G, &AppContext) -> R,
144 ) -> 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 + Send + Sync, 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 + Send + Sync, 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 + Send + Sync, 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: 'static + Send + Sync, R>(
207 &mut self,
208 update: impl FnOnce(&mut G, &mut WindowContext) -> R,
209 ) -> Result<R> {
210 self.app
211 .update_window(self.window, |cx| cx.update_global(update))
212 }
213}
214
215impl Context for AsyncWindowContext {
216 type EntityContext<'a, 'w, T: 'static + Send + Sync> = ViewContext<'a, 'w, T>;
217 type Result<T> = Result<T>;
218
219 fn entity<R: Send + Sync + 'static>(
220 &mut self,
221 build_entity: impl FnOnce(&mut Self::EntityContext<'_, '_, R>) -> R,
222 ) -> Result<Handle<R>> {
223 self.app
224 .update_window(self.window, |cx| cx.entity(build_entity))
225 }
226
227 fn update_entity<T: Send + Sync + 'static, R>(
228 &mut self,
229 handle: &Handle<T>,
230 update: impl FnOnce(&mut T, &mut Self::EntityContext<'_, '_, T>) -> R,
231 ) -> Result<R> {
232 self.app
233 .update_window(self.window, |cx| cx.update_entity(handle, update))
234 }
235}