async_context.rs

  1use crate::{
  2    AnyView, AnyWindowHandle, AppCell, AppContext, BackgroundExecutor, Context, DismissEvent,
  3    FocusableView, ForegroundExecutor, Model, ModelContext, Render, Result, Task, View,
  4    ViewContext, VisualContext, WindowContext, 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 new_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.new_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<T, R>(
 71        &self,
 72        window: &WindowHandle<T>,
 73        read: impl FnOnce(View<T>, &AppContext) -> R,
 74    ) -> Result<R>
 75    where
 76        T: 'static,
 77    {
 78        let app = self.app.upgrade().context("app was released")?;
 79        let lock = app.borrow();
 80        lock.read_window(window, read)
 81    }
 82}
 83
 84impl AsyncAppContext {
 85    /// Schedules all windows in the application to be redrawn.
 86    pub fn refresh(&mut self) -> Result<()> {
 87        let app = self
 88            .app
 89            .upgrade()
 90            .ok_or_else(|| anyhow!("app was released"))?;
 91        let mut lock = app.borrow_mut();
 92        lock.refresh();
 93        Ok(())
 94    }
 95
 96    /// Get an executor which can be used to spawn futures in the background.
 97    pub fn background_executor(&self) -> &BackgroundExecutor {
 98        &self.background_executor
 99    }
100
101    /// Get an executor which can be used to spawn futures in the foreground.
102    pub fn foreground_executor(&self) -> &ForegroundExecutor {
103        &self.foreground_executor
104    }
105
106    /// Invoke the given function in the context of the app, then flush any effects produced during its invocation.
107    pub fn update<R>(&self, f: impl FnOnce(&mut AppContext) -> R) -> Result<R> {
108        let app = self
109            .app
110            .upgrade()
111            .ok_or_else(|| anyhow!("app was released"))?;
112        let mut lock = app.borrow_mut();
113        Ok(f(&mut lock))
114    }
115
116    /// Open a window with the given options based on the root view returned by the given function.
117    pub fn open_window<V>(
118        &self,
119        options: crate::WindowOptions,
120        build_root_view: impl FnOnce(&mut WindowContext) -> View<V>,
121    ) -> Result<WindowHandle<V>>
122    where
123        V: 'static + Render,
124    {
125        let app = self
126            .app
127            .upgrade()
128            .ok_or_else(|| anyhow!("app was released"))?;
129        let mut lock = app.borrow_mut();
130        Ok(lock.open_window(options, build_root_view))
131    }
132
133    /// Schedule a future to be polled in the background.
134    pub fn spawn<Fut, R>(&self, f: impl FnOnce(AsyncAppContext) -> Fut) -> Task<R>
135    where
136        Fut: Future<Output = R> + 'static,
137        R: 'static,
138    {
139        self.foreground_executor.spawn(f(self.clone()))
140    }
141
142    pub fn has_global<G: 'static>(&self) -> Result<bool> {
143        let app = self
144            .app
145            .upgrade()
146            .ok_or_else(|| anyhow!("app was released"))?;
147        let app = app.borrow_mut();
148        Ok(app.has_global::<G>())
149    }
150
151    pub fn read_global<G: 'static, R>(&self, read: impl FnOnce(&G, &AppContext) -> R) -> Result<R> {
152        let app = self
153            .app
154            .upgrade()
155            .ok_or_else(|| anyhow!("app was released"))?;
156        let app = app.borrow_mut();
157        Ok(read(app.global(), &app))
158    }
159
160    pub fn try_read_global<G: 'static, R>(
161        &self,
162        read: impl FnOnce(&G, &AppContext) -> R,
163    ) -> Option<R> {
164        let app = self.app.upgrade()?;
165        let app = app.borrow_mut();
166        Some(read(app.try_global()?, &app))
167    }
168
169    pub fn update_global<G: 'static, R>(
170        &mut self,
171        update: impl FnOnce(&mut G, &mut AppContext) -> R,
172    ) -> Result<R> {
173        let app = self
174            .app
175            .upgrade()
176            .ok_or_else(|| anyhow!("app was released"))?;
177        let mut app = app.borrow_mut();
178        Ok(app.update_global(update))
179    }
180}
181
182#[derive(Clone, Deref, DerefMut)]
183pub struct AsyncWindowContext {
184    #[deref]
185    #[deref_mut]
186    app: AsyncAppContext,
187    window: AnyWindowHandle,
188}
189
190impl AsyncWindowContext {
191    pub fn window_handle(&self) -> AnyWindowHandle {
192        self.window
193    }
194
195    pub(crate) fn new(app: AsyncAppContext, window: AnyWindowHandle) -> Self {
196        Self { app, window }
197    }
198
199    pub fn update<R>(
200        &mut self,
201        update: impl FnOnce(AnyView, &mut WindowContext) -> R,
202    ) -> Result<R> {
203        self.app.update_window(self.window, update)
204    }
205
206    pub fn on_next_frame(&mut self, f: impl FnOnce(&mut WindowContext) + 'static) {
207        self.window.update(self, |_, cx| cx.on_next_frame(f)).ok();
208    }
209
210    pub fn read_global<G: 'static, R>(
211        &mut self,
212        read: impl FnOnce(&G, &WindowContext) -> R,
213    ) -> Result<R> {
214        self.window.update(self, |_, cx| read(cx.global(), cx))
215    }
216
217    pub fn update_global<G, R>(
218        &mut self,
219        update: impl FnOnce(&mut G, &mut WindowContext) -> R,
220    ) -> Result<R>
221    where
222        G: 'static,
223    {
224        self.window.update(self, |_, cx| cx.update_global(update))
225    }
226
227    pub fn spawn<Fut, R>(&self, f: impl FnOnce(AsyncWindowContext) -> Fut) -> Task<R>
228    where
229        Fut: Future<Output = R> + 'static,
230        R: 'static,
231    {
232        self.foreground_executor.spawn(f(self.clone()))
233    }
234}
235
236impl Context for AsyncWindowContext {
237    type Result<T> = Result<T>;
238
239    fn new_model<T>(
240        &mut self,
241        build_model: impl FnOnce(&mut ModelContext<'_, T>) -> T,
242    ) -> Result<Model<T>>
243    where
244        T: 'static,
245    {
246        self.window.update(self, |_, cx| cx.new_model(build_model))
247    }
248
249    fn update_model<T: 'static, R>(
250        &mut self,
251        handle: &Model<T>,
252        update: impl FnOnce(&mut T, &mut ModelContext<'_, T>) -> R,
253    ) -> Result<R> {
254        self.window
255            .update(self, |_, cx| cx.update_model(handle, update))
256    }
257
258    fn update_window<T, F>(&mut self, window: AnyWindowHandle, update: F) -> Result<T>
259    where
260        F: FnOnce(AnyView, &mut WindowContext<'_>) -> T,
261    {
262        self.app.update_window(window, update)
263    }
264
265    fn read_model<T, R>(
266        &self,
267        handle: &Model<T>,
268        read: impl FnOnce(&T, &AppContext) -> R,
269    ) -> Self::Result<R>
270    where
271        T: 'static,
272    {
273        self.app.read_model(handle, read)
274    }
275
276    fn read_window<T, R>(
277        &self,
278        window: &WindowHandle<T>,
279        read: impl FnOnce(View<T>, &AppContext) -> R,
280    ) -> Result<R>
281    where
282        T: 'static,
283    {
284        self.app.read_window(window, read)
285    }
286}
287
288impl VisualContext for AsyncWindowContext {
289    fn new_view<V>(
290        &mut self,
291        build_view_state: impl FnOnce(&mut ViewContext<'_, V>) -> V,
292    ) -> Self::Result<View<V>>
293    where
294        V: 'static + Render,
295    {
296        self.window
297            .update(self, |_, cx| cx.new_view(build_view_state))
298    }
299
300    fn update_view<V: 'static, R>(
301        &mut self,
302        view: &View<V>,
303        update: impl FnOnce(&mut V, &mut ViewContext<'_, V>) -> R,
304    ) -> Self::Result<R> {
305        self.window
306            .update(self, |_, cx| cx.update_view(view, update))
307    }
308
309    fn replace_root_view<V>(
310        &mut self,
311        build_view: impl FnOnce(&mut ViewContext<'_, V>) -> V,
312    ) -> Self::Result<View<V>>
313    where
314        V: 'static + Render,
315    {
316        self.window
317            .update(self, |_, cx| cx.replace_root_view(build_view))
318    }
319
320    fn focus_view<V>(&mut self, view: &View<V>) -> Self::Result<()>
321    where
322        V: FocusableView,
323    {
324        self.window.update(self, |_, cx| {
325            view.read(cx).focus_handle(cx).clone().focus(cx);
326        })
327    }
328
329    fn dismiss_view<V>(&mut self, view: &View<V>) -> Self::Result<()>
330    where
331        V: crate::ManagedView,
332    {
333        self.window
334            .update(self, |_, cx| view.update(cx, |_, cx| cx.emit(DismissEvent)))
335    }
336}