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