async_context.rs

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