use crate::{ AnyWindowHandle, AppContext, BackgroundExecutor, Context, ForegroundExecutor, Model, ModelContext, Result, Task, WindowContext, }; use anyhow::anyhow; use derive_more::{Deref, DerefMut}; use std::{cell::RefCell, future::Future, rc::Weak}; #[derive(Clone)] pub struct AsyncAppContext { pub(crate) app: Weak>, pub(crate) background_executor: BackgroundExecutor, pub(crate) foreground_executor: ForegroundExecutor, } impl Context for AsyncAppContext { type ModelContext<'a, T> = ModelContext<'a, T>; type Result = Result; fn build_model( &mut self, build_model: impl FnOnce(&mut Self::ModelContext<'_, T>) -> T, ) -> Self::Result> where T: 'static, { let app = self .app .upgrade() .ok_or_else(|| anyhow!("app was released"))?; let mut app = app.borrow_mut(); Ok(app.build_model(build_model)) } fn update_model( &mut self, handle: &Model, update: impl FnOnce(&mut T, &mut Self::ModelContext<'_, T>) -> R, ) -> Self::Result { let app = self .app .upgrade() .ok_or_else(|| anyhow!("app was released"))?; let mut app = app.borrow_mut(); Ok(app.update_model(handle, update)) } } impl AsyncAppContext { pub fn refresh(&mut self) -> Result<()> { let app = self .app .upgrade() .ok_or_else(|| anyhow!("app was released"))?; let mut lock = app.borrow_mut(); lock.refresh(); Ok(()) } pub fn background_executor(&self) -> &BackgroundExecutor { &self.background_executor } pub fn foreground_executor(&self) -> &ForegroundExecutor { &self.foreground_executor } pub fn update(&self, f: impl FnOnce(&mut AppContext) -> R) -> Result { let app = self .app .upgrade() .ok_or_else(|| anyhow!("app was released"))?; let mut lock = app.borrow_mut(); Ok(f(&mut *lock)) } pub fn read_window( &self, handle: AnyWindowHandle, update: impl FnOnce(&WindowContext) -> R, ) -> Result { let app = self .app .upgrade() .ok_or_else(|| anyhow!("app was released"))?; let app_context = app.borrow(); app_context.read_window(handle.id, update) } pub fn update_window( &self, handle: AnyWindowHandle, update: impl FnOnce(&mut WindowContext) -> R, ) -> Result { let app = self .app .upgrade() .ok_or_else(|| anyhow!("app was released"))?; let mut app_context = app.borrow_mut(); app_context.update_window(handle.id, update) } pub fn spawn(&self, f: impl FnOnce(AsyncAppContext) -> Fut) -> Task where Fut: Future + 'static, R: 'static, { self.foreground_executor.spawn(f(self.clone())) } pub fn has_global(&self) -> Result { let app = self .app .upgrade() .ok_or_else(|| anyhow!("app was released"))?; let app = app.borrow_mut(); Ok(app.has_global::()) } pub fn read_global(&self, read: impl FnOnce(&G, &AppContext) -> R) -> Result { let app = self .app .upgrade() .ok_or_else(|| anyhow!("app was released"))?; let app = app.borrow_mut(); // Need this to compile Ok(read(app.global(), &app)) } pub fn try_read_global( &self, read: impl FnOnce(&G, &AppContext) -> R, ) -> Option { let app = self.app.upgrade()?; let app = app.borrow_mut(); Some(read(app.try_global()?, &app)) } pub fn update_global( &mut self, update: impl FnOnce(&mut G, &mut AppContext) -> R, ) -> Result { let app = self .app .upgrade() .ok_or_else(|| anyhow!("app was released"))?; let mut app = app.borrow_mut(); Ok(app.update_global(update)) } } #[derive(Clone, Deref, DerefMut)] pub struct AsyncWindowContext { #[deref] #[deref_mut] app: AsyncAppContext, window: AnyWindowHandle, } impl AsyncWindowContext { pub(crate) fn new(app: AsyncAppContext, window: AnyWindowHandle) -> Self { Self { app, window } } pub fn update(&self, update: impl FnOnce(&mut WindowContext) -> R) -> Result { self.app.update_window(self.window, update) } pub fn on_next_frame(&mut self, f: impl FnOnce(&mut WindowContext) + Send + 'static) { self.app .update_window(self.window, |cx| cx.on_next_frame(f)) .ok(); } pub fn read_global( &self, read: impl FnOnce(&G, &WindowContext) -> R, ) -> Result { self.app .read_window(self.window, |cx| read(cx.global(), cx)) } pub fn update_global( &mut self, update: impl FnOnce(&mut G, &mut WindowContext) -> R, ) -> Result where G: 'static, { self.app .update_window(self.window, |cx| cx.update_global(update)) } } impl Context for AsyncWindowContext { type ModelContext<'a, T> = ModelContext<'a, T>; type Result = Result; fn build_model( &mut self, build_model: impl FnOnce(&mut Self::ModelContext<'_, T>) -> T, ) -> Result> where T: 'static, { self.app .update_window(self.window, |cx| cx.build_model(build_model)) } fn update_model( &mut self, handle: &Model, update: impl FnOnce(&mut T, &mut Self::ModelContext<'_, T>) -> R, ) -> Result { self.app .update_window(self.window, |cx| cx.update_model(handle, update)) } }