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