use crate::{ AnyView, AnyWindowHandle, AppContext, BackgroundExecutor, Context, ForegroundExecutor, Model, ModelContext, Render, Result, Task, View, ViewContext, VisualContext, WindowContext, }; use anyhow::{anyhow, Context as _}; 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 Result = Result; fn build_model( &mut self, build_model: impl FnOnce(&mut 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 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)) } fn update_window(&mut self, window: AnyWindowHandle, f: F) -> Result where F: FnOnce(AnyView, &mut WindowContext<'_>) -> T, { let app = self.app.upgrade().context("app was released")?; let mut lock = app.borrow_mut(); lock.update_window(window, f) } } 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 update_window( &self, handle: AnyWindowHandle, update: impl FnOnce(AnyView, &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, 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( &mut self, update: impl FnOnce(AnyView, &mut WindowContext) -> R, ) -> Result { self.app.update_window(self.window, update) } pub fn on_next_frame(&mut self, f: impl FnOnce(&mut WindowContext) + 'static) { self.window.update(self, |_, cx| cx.on_next_frame(f)).ok(); } pub fn read_global( &mut self, read: impl FnOnce(&G, &WindowContext) -> R, ) -> Result { self.window.update(self, |_, cx| read(cx.global(), cx)) } pub fn update_global( &mut self, update: impl FnOnce(&mut G, &mut WindowContext) -> R, ) -> Result where G: 'static, { self.window.update(self, |_, cx| cx.update_global(update)) } pub fn spawn(&self, f: impl FnOnce(AsyncWindowContext) -> Fut) -> Task where Fut: Future + 'static, R: 'static, { self.foreground_executor.spawn(f(self.clone())) } } impl Context for AsyncWindowContext { type Result = Result; fn build_model( &mut self, build_model: impl FnOnce(&mut ModelContext<'_, T>) -> T, ) -> Result> where T: 'static, { self.window .update(self, |_, cx| cx.build_model(build_model)) } fn update_model( &mut self, handle: &Model, update: impl FnOnce(&mut T, &mut ModelContext<'_, T>) -> R, ) -> Result { self.window .update(self, |_, cx| cx.update_model(handle, update)) } fn update_window(&mut self, window: AnyWindowHandle, update: F) -> Result where F: FnOnce(AnyView, &mut WindowContext<'_>) -> T, { self.app.update_window(window, update) } } impl VisualContext for AsyncWindowContext { fn build_view( &mut self, build_view_state: impl FnOnce(&mut ViewContext<'_, V>) -> V, ) -> Self::Result> where V: 'static, { self.window .update(self, |_, cx| cx.build_view(build_view_state)) } fn update_view( &mut self, view: &View, update: impl FnOnce(&mut V, &mut ViewContext<'_, V>) -> R, ) -> Self::Result { self.window .update(self, |_, cx| cx.update_view(view, update)) } fn replace_root_view( &mut self, build_view: impl FnOnce(&mut ViewContext<'_, V>) -> V, ) -> Self::Result> where V: Render, { self.window .update(self, |_, cx| cx.replace_root_view(build_view)) } }