async_context.rs

  1use crate::{
  2    AnyWindowHandle, AppContext, Context, Executor, MainThread, Model, ModelContext, Result, Task,
  3    WindowContext,
  4};
  5use anyhow::anyhow;
  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
 28            .app
 29            .upgrade()
 30            .ok_or_else(|| anyhow!("app was released"))?;
 31        let mut lock = app.lock(); // Need this to compile
 32        Ok(lock.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 Self::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 lock = app.lock(); // Need this to compile
 45        Ok(lock.update_model(handle, update))
 46    }
 47}
 48
 49impl AsyncAppContext {
 50    pub fn refresh(&mut self) -> Result<()> {
 51        let app = self
 52            .app
 53            .upgrade()
 54            .ok_or_else(|| anyhow!("app was released"))?;
 55        let mut lock = app.lock(); // Need this to compile
 56        lock.refresh();
 57        Ok(())
 58    }
 59
 60    pub fn executor(&self) -> &Executor {
 61        &self.executor
 62    }
 63
 64    pub fn update<R>(&self, f: impl FnOnce(&mut AppContext) -> R) -> Result<R> {
 65        let app = self
 66            .app
 67            .upgrade()
 68            .ok_or_else(|| anyhow!("app was released"))?;
 69        let mut lock = app.lock();
 70        Ok(f(&mut *lock))
 71    }
 72
 73    pub fn read_window<R>(
 74        &self,
 75        handle: AnyWindowHandle,
 76        update: impl FnOnce(&WindowContext) -> R,
 77    ) -> Result<R> {
 78        let app = self
 79            .app
 80            .upgrade()
 81            .ok_or_else(|| anyhow!("app was released"))?;
 82        let mut app_context = app.lock();
 83        app_context.read_window(handle.id, update)
 84    }
 85
 86    pub fn update_window<R>(
 87        &self,
 88        handle: AnyWindowHandle,
 89        update: impl FnOnce(&mut WindowContext) -> R,
 90    ) -> Result<R> {
 91        let app = self
 92            .app
 93            .upgrade()
 94            .ok_or_else(|| anyhow!("app was released"))?;
 95        let mut app_context = app.lock();
 96        app_context.update_window(handle.id, update)
 97    }
 98
 99    pub fn spawn<Fut, R>(&self, f: impl FnOnce(AsyncAppContext) -> Fut + Send + 'static) -> Task<R>
100    where
101        Fut: Future<Output = R> + Send + 'static,
102        R: Send + 'static,
103    {
104        let this = self.clone();
105        self.executor.spawn(async move { f(this).await })
106    }
107
108    pub fn spawn_on_main<Fut, R>(
109        &self,
110        f: impl FnOnce(AsyncAppContext) -> Fut + Send + 'static,
111    ) -> Task<R>
112    where
113        Fut: Future<Output = R> + 'static,
114        R: Send + 'static,
115    {
116        let this = self.clone();
117        self.executor.spawn_on_main(|| f(this))
118    }
119
120    pub fn run_on_main<R>(
121        &self,
122        f: impl FnOnce(&mut MainThread<AppContext>) -> R + Send + 'static,
123    ) -> Result<Task<R>>
124    where
125        R: Send + 'static,
126    {
127        let app = self
128            .app
129            .upgrade()
130            .ok_or_else(|| anyhow!("app was released"))?;
131        let mut app_context = app.lock();
132        Ok(app_context.run_on_main(f))
133    }
134
135    pub fn has_global<G: 'static>(&self) -> Result<bool> {
136        let app = self
137            .app
138            .upgrade()
139            .ok_or_else(|| anyhow!("app was released"))?;
140        let lock = app.lock(); // Need this to compile
141        Ok(lock.has_global::<G>())
142    }
143
144    pub fn read_global<G: 'static, R>(&self, read: impl FnOnce(&G, &AppContext) -> R) -> Result<R> {
145        let app = self
146            .app
147            .upgrade()
148            .ok_or_else(|| anyhow!("app was released"))?;
149        let lock = app.lock(); // Need this to compile
150        Ok(read(lock.global(), &lock))
151    }
152
153    pub fn try_read_global<G: 'static, R>(
154        &self,
155        read: impl FnOnce(&G, &AppContext) -> R,
156    ) -> Option<R> {
157        let app = self.app.upgrade()?;
158        let lock = app.lock(); // Need this to compile
159        Some(read(lock.try_global()?, &lock))
160    }
161
162    pub fn update_global<G: 'static, R>(
163        &mut self,
164        update: impl FnOnce(&mut G, &mut AppContext) -> R,
165    ) -> Result<R> {
166        let app = self
167            .app
168            .upgrade()
169            .ok_or_else(|| anyhow!("app was released"))?;
170        let mut lock = app.lock(); // Need this to compile
171        Ok(lock.update_global(update))
172    }
173}
174
175#[derive(Clone, Deref, DerefMut)]
176pub struct AsyncWindowContext {
177    #[deref]
178    #[deref_mut]
179    app: AsyncAppContext,
180    window: AnyWindowHandle,
181}
182
183impl AsyncWindowContext {
184    pub(crate) fn new(app: AsyncAppContext, window: AnyWindowHandle) -> Self {
185        Self { app, window }
186    }
187
188    pub fn update<R>(&self, update: impl FnOnce(&mut WindowContext) -> R) -> Result<R> {
189        self.app.update_window(self.window, update)
190    }
191
192    pub fn on_next_frame(&mut self, f: impl FnOnce(&mut WindowContext) + Send + 'static) {
193        self.app
194            .update_window(self.window, |cx| cx.on_next_frame(f))
195            .ok();
196    }
197
198    pub fn read_global<G: 'static, R>(
199        &self,
200        read: impl FnOnce(&G, &WindowContext) -> R,
201    ) -> Result<R> {
202        self.app
203            .read_window(self.window, |cx| read(cx.global(), cx))
204    }
205
206    pub fn update_global<G, R>(
207        &mut self,
208        update: impl FnOnce(&mut G, &mut WindowContext) -> R,
209    ) -> Result<R>
210    where
211        G: 'static,
212    {
213        self.app
214            .update_window(self.window, |cx| cx.update_global(update))
215    }
216}
217
218impl Context for AsyncWindowContext {
219    type ModelContext<'a, T> = ModelContext<'a, T>;
220    type Result<T> = Result<T>;
221
222    fn build_model<T>(
223        &mut self,
224        build_model: impl FnOnce(&mut Self::ModelContext<'_, T>) -> T,
225    ) -> Result<Model<T>>
226    where
227        T: 'static + Send,
228    {
229        self.app
230            .update_window(self.window, |cx| cx.build_model(build_model))
231    }
232
233    fn update_model<T: 'static, R>(
234        &mut self,
235        handle: &Model<T>,
236        update: impl FnOnce(&mut T, &mut Self::ModelContext<'_, T>) -> R,
237    ) -> Result<R> {
238        self.app
239            .update_window(self.window, |cx| cx.update_model(handle, update))
240    }
241}
242
243#[cfg(test)]
244mod tests {
245    use super::*;
246
247    #[test]
248    fn test_async_app_context_send_sync() {
249        fn assert_send_sync<T: Send + Sync>() {}
250        assert_send_sync::<AsyncAppContext>();
251    }
252}