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