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 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}