async_context.rs

  1use crate::{
  2    AnyWindowHandle, AppContext, Context, Executor, Handle, MainThread, ModelContext, Result, Task,
  3    ViewContext, 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 EntityContext<'a, 'w, T: 'static + Send + Sync> = ModelContext<'a, T>;
 18    type Result<T> = Result<T>;
 19
 20    fn entity<T: Send + Sync + 'static>(
 21        &mut self,
 22        build_entity: impl FnOnce(&mut Self::EntityContext<'_, '_, T>) -> T,
 23    ) -> Self::Result<Handle<T>> {
 24        let app = self
 25            .app
 26            .upgrade()
 27            .ok_or_else(|| anyhow!("app was released"))?;
 28        let mut lock = app.lock(); // Need this to compile
 29        Ok(lock.entity(build_entity))
 30    }
 31
 32    fn update_entity<T: Send + Sync + 'static, R>(
 33        &mut self,
 34        handle: &Handle<T>,
 35        update: impl FnOnce(&mut T, &mut Self::EntityContext<'_, '_, T>) -> R,
 36    ) -> Self::Result<R> {
 37        let app = self
 38            .app
 39            .upgrade()
 40            .ok_or_else(|| anyhow!("app was released"))?;
 41        let mut lock = app.lock(); // Need this to compile
 42        Ok(lock.update_entity(handle, update))
 43    }
 44}
 45
 46impl AsyncAppContext {
 47    pub fn refresh(&mut self) -> Result<()> {
 48        let app = self
 49            .app
 50            .upgrade()
 51            .ok_or_else(|| anyhow!("app was released"))?;
 52        let mut lock = app.lock(); // Need this to compile
 53        lock.refresh();
 54        Ok(())
 55    }
 56
 57    pub fn executor(&self) -> &Executor {
 58        &self.executor
 59    }
 60
 61    pub fn update<R>(&self, f: impl FnOnce(&mut AppContext) -> R) -> Result<R> {
 62        let app = self
 63            .app
 64            .upgrade()
 65            .ok_or_else(|| anyhow!("app was released"))?;
 66        let mut lock = app.lock();
 67        Ok(f(&mut *lock))
 68    }
 69
 70    pub fn read_window<R>(
 71        &self,
 72        handle: AnyWindowHandle,
 73        update: impl FnOnce(&WindowContext) -> R,
 74    ) -> Result<R> {
 75        let app = self
 76            .app
 77            .upgrade()
 78            .ok_or_else(|| anyhow!("app was released"))?;
 79        let mut app_context = app.lock();
 80        app_context.read_window(handle.id, update)
 81    }
 82
 83    pub fn update_window<R>(
 84        &self,
 85        handle: AnyWindowHandle,
 86        update: impl FnOnce(&mut WindowContext) -> R,
 87    ) -> Result<R> {
 88        let app = self
 89            .app
 90            .upgrade()
 91            .ok_or_else(|| anyhow!("app was released"))?;
 92        let mut app_context = app.lock();
 93        app_context.update_window(handle.id, update)
 94    }
 95
 96    pub fn spawn<Fut, R>(&self, f: impl FnOnce(AsyncAppContext) -> Fut + Send + 'static) -> Task<R>
 97    where
 98        Fut: Future<Output = R> + Send + 'static,
 99        R: Send + 'static,
100    {
101        let this = self.clone();
102        self.executor.spawn(async move { f(this).await })
103    }
104
105    pub fn spawn_on_main<Fut, R>(
106        &self,
107        f: impl FnOnce(AsyncAppContext) -> Fut + Send + 'static,
108    ) -> Task<R>
109    where
110        Fut: Future<Output = R> + 'static,
111        R: Send + 'static,
112    {
113        let this = self.clone();
114        self.executor.spawn_on_main(|| f(this))
115    }
116
117    pub fn run_on_main<R>(
118        &self,
119        f: impl FnOnce(&mut MainThread<AppContext>) -> R + Send + 'static,
120    ) -> Result<Task<R>>
121    where
122        R: Send + 'static,
123    {
124        let app = self
125            .app
126            .upgrade()
127            .ok_or_else(|| anyhow!("app was released"))?;
128        let mut app_context = app.lock();
129        Ok(app_context.run_on_main(f))
130    }
131
132    pub fn has_global<G: 'static + Send + Sync>(&self) -> Result<bool> {
133        let app = self
134            .app
135            .upgrade()
136            .ok_or_else(|| anyhow!("app was released"))?;
137        let lock = app.lock(); // Need this to compile
138        Ok(lock.has_global::<G>())
139    }
140
141    pub fn read_global<G: 'static + Send + Sync, R>(
142        &self,
143        read: impl FnOnce(&G, &AppContext) -> R,
144    ) -> 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 + Send + Sync, 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 + Send + Sync, 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 + Send + Sync, 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: 'static + Send + Sync, R>(
207        &mut self,
208        update: impl FnOnce(&mut G, &mut WindowContext) -> R,
209    ) -> Result<R> {
210        self.app
211            .update_window(self.window, |cx| cx.update_global(update))
212    }
213}
214
215impl Context for AsyncWindowContext {
216    type EntityContext<'a, 'w, T: 'static + Send + Sync> = ViewContext<'a, 'w, T>;
217    type Result<T> = Result<T>;
218
219    fn entity<R: Send + Sync + 'static>(
220        &mut self,
221        build_entity: impl FnOnce(&mut Self::EntityContext<'_, '_, R>) -> R,
222    ) -> Result<Handle<R>> {
223        self.app
224            .update_window(self.window, |cx| cx.entity(build_entity))
225    }
226
227    fn update_entity<T: Send + Sync + 'static, R>(
228        &mut self,
229        handle: &Handle<T>,
230        update: impl FnOnce(&mut T, &mut Self::EntityContext<'_, '_, T>) -> R,
231    ) -> Result<R> {
232        self.app
233            .update_window(self.window, |cx| cx.update_entity(handle, update))
234    }
235}