async_context.rs

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