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(pub(crate) Weak<Mutex<AppContext>>);
 12
 13impl Context for AsyncAppContext {
 14    type BorrowedContext<'a, 'w> = AppContext;
 15    type EntityContext<'a, 'w, T: 'static + Send + Sync> = ModelContext<'a, T>;
 16    type Result<T> = Result<T>;
 17
 18    fn refresh(&mut self) -> Self::Result<()> {
 19        let app = self
 20            .0
 21            .upgrade()
 22            .ok_or_else(|| anyhow!("app was released"))?;
 23        let mut lock = app.lock(); // Need this to compile
 24        lock.refresh();
 25        Ok(())
 26    }
 27
 28    fn entity<T: Send + Sync + 'static>(
 29        &mut self,
 30        build_entity: impl FnOnce(&mut Self::EntityContext<'_, '_, T>) -> T,
 31    ) -> Self::Result<Handle<T>> {
 32        let app = self
 33            .0
 34            .upgrade()
 35            .ok_or_else(|| anyhow!("app was released"))?;
 36        let mut lock = app.lock(); // Need this to compile
 37        Ok(lock.entity(build_entity))
 38    }
 39
 40    fn update_entity<T: Send + Sync + 'static, R>(
 41        &mut self,
 42        handle: &Handle<T>,
 43        update: impl FnOnce(&mut T, &mut Self::EntityContext<'_, '_, T>) -> R,
 44    ) -> Self::Result<R> {
 45        let app = self
 46            .0
 47            .upgrade()
 48            .ok_or_else(|| anyhow!("app was released"))?;
 49        let mut lock = app.lock(); // Need this to compile
 50        Ok(lock.update_entity(handle, update))
 51    }
 52
 53    fn read_global<G: 'static + Send + Sync, R>(
 54        &self,
 55        read: impl FnOnce(&G, &Self::BorrowedContext<'_, '_>) -> R,
 56    ) -> Self::Result<R> {
 57        let app = self
 58            .0
 59            .upgrade()
 60            .ok_or_else(|| anyhow!("app was released"))?;
 61        let lock = app.lock(); // Need this to compile
 62        Ok(lock.read_global(read))
 63    }
 64
 65    fn update_global<G: 'static + Send + Sync, R>(
 66        &mut self,
 67        update: impl FnOnce(&mut G, &mut Self::BorrowedContext<'_, '_>) -> R,
 68    ) -> Self::Result<R> {
 69        let app = self
 70            .0
 71            .upgrade()
 72            .ok_or_else(|| anyhow!("app was released"))?;
 73        let mut lock = app.lock(); // Need this to compile
 74        Ok(lock.update_global(update))
 75    }
 76}
 77
 78impl AsyncAppContext {
 79    pub fn executor(&self) -> Result<Executor> {
 80        let app = self
 81            .0
 82            .upgrade()
 83            .ok_or_else(|| anyhow!("app was released"))?;
 84        let lock = app.lock(); // Need this to compile
 85        Ok(lock.executor().clone())
 86    }
 87
 88    pub fn read_window<R>(
 89        &self,
 90        handle: AnyWindowHandle,
 91        update: impl FnOnce(&WindowContext) -> R,
 92    ) -> Result<R> {
 93        let app = self
 94            .0
 95            .upgrade()
 96            .ok_or_else(|| anyhow!("app was released"))?;
 97        let mut app_context = app.lock();
 98        app_context.read_window(handle.id, update)
 99    }
100
101    pub fn update_window<R>(
102        &self,
103        handle: AnyWindowHandle,
104        update: impl FnOnce(&mut WindowContext) -> R,
105    ) -> Result<R> {
106        let app = self
107            .0
108            .upgrade()
109            .ok_or_else(|| anyhow!("app was released"))?;
110        let mut app_context = app.lock();
111        app_context.update_window(handle.id, update)
112    }
113
114    pub fn spawn<Fut, R>(
115        &self,
116        f: impl FnOnce(AsyncAppContext) -> Fut + Send + 'static,
117    ) -> Result<Task<R>>
118    where
119        Fut: Future<Output = R> + Send + 'static,
120        R: Send + 'static,
121    {
122        let app = self
123            .0
124            .upgrade()
125            .ok_or_else(|| anyhow!("app was released"))?;
126        let app_context = app.lock();
127        Ok(app_context.spawn(f))
128    }
129
130    pub fn run_on_main<R>(
131        &self,
132        f: impl FnOnce(&mut MainThread<AppContext>) -> R + Send + 'static,
133    ) -> Result<Task<R>>
134    where
135        R: Send + 'static,
136    {
137        let app = self
138            .0
139            .upgrade()
140            .ok_or_else(|| anyhow!("app was released"))?;
141        let mut app_context = app.lock();
142        Ok(app_context.run_on_main(f))
143    }
144}
145
146#[derive(Clone, Deref, DerefMut)]
147pub struct AsyncWindowContext {
148    #[deref]
149    #[deref_mut]
150    app: AsyncAppContext,
151    window: AnyWindowHandle,
152}
153
154impl AsyncWindowContext {
155    pub(crate) fn new(app: AsyncAppContext, window: AnyWindowHandle) -> Self {
156        Self { app, window }
157    }
158
159    pub fn update<R>(&self, update: impl FnOnce(&mut WindowContext) -> R) -> Result<R> {
160        self.app.update_window(self.window, update)
161    }
162
163    pub fn on_next_frame(&mut self, f: impl FnOnce(&mut WindowContext) + Send + 'static) {
164        self.app
165            .update_window(self.window, |cx| cx.on_next_frame(f))
166            .ok();
167    }
168}
169
170impl Context for AsyncWindowContext {
171    type BorrowedContext<'a, 'w> = WindowContext<'a, 'w>;
172    type EntityContext<'a, 'w, T: 'static + Send + Sync> = ViewContext<'a, 'w, T>;
173    type Result<T> = Result<T>;
174
175    fn refresh(&mut self) -> Self::Result<()> {
176        self.app.refresh()
177    }
178
179    fn entity<R: Send + Sync + 'static>(
180        &mut self,
181        build_entity: impl FnOnce(&mut Self::EntityContext<'_, '_, R>) -> R,
182    ) -> Result<Handle<R>> {
183        self.app
184            .update_window(self.window, |cx| cx.entity(build_entity))
185    }
186
187    fn update_entity<T: Send + Sync + 'static, R>(
188        &mut self,
189        handle: &Handle<T>,
190        update: impl FnOnce(&mut T, &mut Self::EntityContext<'_, '_, T>) -> R,
191    ) -> Result<R> {
192        self.app
193            .update_window(self.window, |cx| cx.update_entity(handle, update))
194    }
195
196    fn read_global<G: 'static + Send + Sync, R>(
197        &self,
198        read: impl FnOnce(&G, &Self::BorrowedContext<'_, '_>) -> R,
199    ) -> Result<R> {
200        self.app.read_window(self.window, |cx| cx.read_global(read))
201    }
202
203    fn update_global<G: 'static + Send + Sync, R>(
204        &mut self,
205        update: impl FnOnce(&mut G, &mut Self::BorrowedContext<'_, '_>) -> R,
206    ) -> Result<R> {
207        self.app
208            .update_window(self.window, |cx| cx.update_global(update))
209    }
210}