1use crate::{
2 AnyView, AnyWindowHandle, AppCell, AppContext, BackgroundExecutor, Context, ForegroundExecutor,
3 Model, ModelContext, Render, Result, Task, View, ViewContext, VisualContext, WindowContext,
4 WindowHandle,
5};
6use anyhow::{anyhow, Context as _};
7use derive_more::{Deref, DerefMut};
8use std::{future::Future, rc::Weak};
9
10#[derive(Clone)]
11pub struct AsyncAppContext {
12 pub(crate) app: Weak<AppCell>,
13 pub(crate) background_executor: BackgroundExecutor,
14 pub(crate) foreground_executor: ForegroundExecutor,
15}
16
17impl Context for AsyncAppContext {
18 type Result<T> = Result<T>;
19
20 fn build_model<T: 'static>(
21 &mut self,
22 build_model: impl FnOnce(&mut ModelContext<'_, T>) -> T,
23 ) -> Self::Result<Model<T>>
24 where
25 T: 'static,
26 {
27 let app = self
28 .app
29 .upgrade()
30 .ok_or_else(|| anyhow!("app was released"))?;
31 dbg!("BUILD MODEL A");
32 let mut app = app.borrow_mut();
33 Ok(app.build_model(build_model))
34 }
35
36 fn update_model<T: 'static, R>(
37 &mut self,
38 handle: &Model<T>,
39 update: impl FnOnce(&mut T, &mut ModelContext<'_, T>) -> R,
40 ) -> Self::Result<R> {
41 let app = self
42 .app
43 .upgrade()
44 .ok_or_else(|| anyhow!("app was released"))?;
45 dbg!("UPDATE MODEL B");
46 let mut app = app.borrow_mut();
47 Ok(app.update_model(handle, update))
48 }
49
50 fn update_window<T, F>(&mut self, window: AnyWindowHandle, f: F) -> Result<T>
51 where
52 F: FnOnce(AnyView, &mut WindowContext<'_>) -> T,
53 {
54 let app = self.app.upgrade().context("app was released")?;
55 dbg!("UPDATE WINDOW C");
56 let mut lock = app.borrow_mut();
57 lock.update_window(window, f)
58 }
59}
60
61impl AsyncAppContext {
62 pub fn refresh(&mut self) -> Result<()> {
63 let app = self
64 .app
65 .upgrade()
66 .ok_or_else(|| anyhow!("app was released"))?;
67 dbg!("REFRESH");
68 let mut lock = app.borrow_mut();
69 lock.refresh();
70 Ok(())
71 }
72
73 pub fn background_executor(&self) -> &BackgroundExecutor {
74 &self.background_executor
75 }
76
77 pub fn foreground_executor(&self) -> &ForegroundExecutor {
78 &self.foreground_executor
79 }
80
81 pub fn update<R>(&self, f: impl FnOnce(&mut AppContext) -> R) -> Result<R> {
82 let app = self
83 .app
84 .upgrade()
85 .ok_or_else(|| anyhow!("app was released"))?;
86 let mut lock = app.borrow_mut();
87 Ok(f(&mut *lock))
88 }
89
90 pub fn open_window<V>(
91 &self,
92 options: crate::WindowOptions,
93 build_root_view: impl FnOnce(&mut WindowContext) -> View<V>,
94 ) -> Result<WindowHandle<V>>
95 where
96 V: Render,
97 {
98 let app = self
99 .app
100 .upgrade()
101 .ok_or_else(|| anyhow!("app was released"))?;
102 let mut lock = app.borrow_mut();
103 Ok(lock.open_window(options, build_root_view))
104 }
105
106 pub fn spawn<Fut, R>(&self, f: impl FnOnce(AsyncAppContext) -> Fut) -> Task<R>
107 where
108 Fut: Future<Output = R> + 'static,
109 R: 'static,
110 {
111 self.foreground_executor.spawn(f(self.clone()))
112 }
113
114 pub fn has_global<G: 'static>(&self) -> Result<bool> {
115 let app = self
116 .app
117 .upgrade()
118 .ok_or_else(|| anyhow!("app was released"))?;
119 let app = app.borrow_mut();
120 Ok(app.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
125 .app
126 .upgrade()
127 .ok_or_else(|| anyhow!("app was released"))?;
128 dbg!("read global");
129 let app = app.borrow_mut();
130 Ok(read(app.global(), &app))
131 }
132
133 pub fn try_read_global<G: 'static, R>(
134 &self,
135 read: impl FnOnce(&G, &AppContext) -> R,
136 ) -> Option<R> {
137 let app = self.app.upgrade()?;
138 dbg!("try read global");
139 let app = app.borrow_mut();
140 Some(read(app.try_global()?, &app))
141 }
142
143 pub fn update_global<G: 'static, R>(
144 &mut self,
145 update: impl FnOnce(&mut G, &mut AppContext) -> R,
146 ) -> Result<R> {
147 let app = self
148 .app
149 .upgrade()
150 .ok_or_else(|| anyhow!("app was released"))?;
151 dbg!("update global");
152 let mut app = app.borrow_mut();
153 Ok(app.update_global(update))
154 }
155}
156
157#[derive(Clone, Deref, DerefMut)]
158pub struct AsyncWindowContext {
159 #[deref]
160 #[deref_mut]
161 app: AsyncAppContext,
162 window: AnyWindowHandle,
163}
164
165impl AsyncWindowContext {
166 pub(crate) fn new(app: AsyncAppContext, window: AnyWindowHandle) -> Self {
167 Self { app, window }
168 }
169
170 pub fn update<R>(
171 &mut self,
172 update: impl FnOnce(AnyView, &mut WindowContext) -> R,
173 ) -> Result<R> {
174 self.app.update_window(self.window, update)
175 }
176
177 pub fn on_next_frame(&mut self, f: impl FnOnce(&mut WindowContext) + 'static) {
178 self.window.update(self, |_, cx| cx.on_next_frame(f)).ok();
179 }
180
181 pub fn read_global<G: 'static, R>(
182 &mut self,
183 read: impl FnOnce(&G, &WindowContext) -> R,
184 ) -> Result<R> {
185 self.window.update(self, |_, cx| read(cx.global(), cx))
186 }
187
188 pub fn update_global<G, R>(
189 &mut self,
190 update: impl FnOnce(&mut G, &mut WindowContext) -> R,
191 ) -> Result<R>
192 where
193 G: 'static,
194 {
195 self.window.update(self, |_, cx| cx.update_global(update))
196 }
197
198 pub fn spawn<Fut, R>(&self, f: impl FnOnce(AsyncWindowContext) -> Fut) -> Task<R>
199 where
200 Fut: Future<Output = R> + 'static,
201 R: 'static,
202 {
203 self.foreground_executor.spawn(f(self.clone()))
204 }
205}
206
207impl Context for AsyncWindowContext {
208 type Result<T> = Result<T>;
209
210 fn build_model<T>(
211 &mut self,
212 build_model: impl FnOnce(&mut ModelContext<'_, T>) -> T,
213 ) -> Result<Model<T>>
214 where
215 T: 'static,
216 {
217 self.window
218 .update(self, |_, cx| cx.build_model(build_model))
219 }
220
221 fn update_model<T: 'static, R>(
222 &mut self,
223 handle: &Model<T>,
224 update: impl FnOnce(&mut T, &mut ModelContext<'_, T>) -> R,
225 ) -> Result<R> {
226 self.window
227 .update(self, |_, cx| cx.update_model(handle, update))
228 }
229
230 fn update_window<T, F>(&mut self, window: AnyWindowHandle, update: F) -> Result<T>
231 where
232 F: FnOnce(AnyView, &mut WindowContext<'_>) -> T,
233 {
234 self.app.update_window(window, update)
235 }
236}
237
238impl VisualContext for AsyncWindowContext {
239 fn build_view<V>(
240 &mut self,
241 build_view_state: impl FnOnce(&mut ViewContext<'_, V>) -> V,
242 ) -> Self::Result<View<V>>
243 where
244 V: 'static,
245 {
246 self.window
247 .update(self, |_, cx| cx.build_view(build_view_state))
248 }
249
250 fn update_view<V: 'static, R>(
251 &mut self,
252 view: &View<V>,
253 update: impl FnOnce(&mut V, &mut ViewContext<'_, V>) -> R,
254 ) -> Self::Result<R> {
255 self.window
256 .update(self, |_, cx| cx.update_view(view, update))
257 }
258
259 fn replace_root_view<V>(
260 &mut self,
261 build_view: impl FnOnce(&mut ViewContext<'_, V>) -> V,
262 ) -> Self::Result<View<V>>
263 where
264 V: Render,
265 {
266 self.window
267 .update(self, |_, cx| cx.replace_root_view(build_view))
268 }
269}