async_context.rs

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