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