async_context.rs

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