diff --git a/crates/gpui3/src/app.rs b/crates/gpui3/src/app.rs index a6f83a6fc77303f03dbeea2387f95c2045ca2c22..d27fc6a3f6f6a1d9313bd423d33fab1d19eba251 100644 --- a/crates/gpui3/src/app.rs +++ b/crates/gpui3/src/app.rs @@ -14,19 +14,19 @@ use crate::{ }; use anyhow::{anyhow, Result}; use collections::{HashMap, VecDeque}; -use futures::{future, Future}; +use futures::Future; use parking_lot::Mutex; use slotmap::SlotMap; use smallvec::SmallVec; use std::{ any::{type_name, Any, TypeId}, - marker::PhantomData, + mem, sync::{Arc, Weak}, }; use util::ResultExt; #[derive(Clone)] -pub struct App(Arc>>); +pub struct App(Arc>>); impl App { pub fn production() -> Self { @@ -44,8 +44,7 @@ impl App { let entities = EntityMap::new(); let unit_entity = entities.redeem(entities.reserve(), ()); Self(Arc::new_cyclic(|this| { - Mutex::new(AppContext { - thread: PhantomData, + Mutex::new(MainThread::new(AppContext { this: this.clone(), platform: MainThreadOnly::new(platform, dispatcher.clone()), dispatcher, @@ -59,13 +58,13 @@ impl App { pending_effects: Default::default(), observers: Default::default(), layout_id_buffer: Default::default(), - }) + })) })) } pub fn run(self, on_finish_launching: F) where - F: 'static + FnOnce(&mut AppContext), + F: 'static + FnOnce(&mut MainThread), { let this = self.clone(); let platform = self.0.lock().platform.clone(); @@ -76,12 +75,10 @@ impl App { } } -type Handlers = - SmallVec<[Arc) -> bool + Send + Sync + 'static>; 2]>; +type Handlers = SmallVec<[Arc bool + Send + Sync + 'static>; 2]>; -pub struct AppContext { - thread: PhantomData, - this: Weak>>, +pub struct AppContext { + this: Weak>>, platform: MainThreadOnly, dispatcher: Arc, text_system: Arc, @@ -92,39 +89,89 @@ pub struct AppContext { pub(crate) entities: EntityMap, pub(crate) windows: SlotMap>, pub(crate) pending_effects: VecDeque, - pub(crate) observers: HashMap>, + pub(crate) observers: HashMap, pub(crate) layout_id_buffer: Vec, // We recycle this memory across layout requests. } -impl AppContext { - // TODO: Better names for these? - #[inline] - pub fn downcast(&self) -> &AppContext<()> { - // Any `Thread` can become `()`. - // - // Can't do this in a blanket `Deref` impl, as it infinitely recurses. - unsafe { std::mem::transmute::<&AppContext, &AppContext<()>>(self) } +impl AppContext { + fn update(&mut self, update: impl FnOnce(&mut Self) -> R) -> R { + self.pending_updates += 1; + let result = update(self); + if self.pending_updates == 1 { + self.flush_effects(); + } + self.pending_updates -= 1; + result } - #[inline] - pub fn downcast_mut(&mut self) -> &mut AppContext<()> { - // Any `Thread` can become `()`. - // - // Can't do this in a blanket `DerefMut` impl, as it infinitely recurses. - unsafe { std::mem::transmute::<&mut AppContext, &mut AppContext<()>>(self) } + pub(crate) fn update_window( + &mut self, + id: WindowId, + update: impl FnOnce(&mut WindowContext) -> R, + ) -> Result { + self.update(|cx| { + let mut window = cx + .windows + .get_mut(id) + .ok_or_else(|| anyhow!("window not found"))? + .take() + .unwrap(); + + let result = update(&mut WindowContext::mutable(cx, &mut window)); + + cx.windows + .get_mut(id) + .ok_or_else(|| anyhow!("window not found"))? + .replace(window); + + Ok(result) + }) } - pub fn text_system(&self) -> &Arc { - &self.text_system + fn flush_effects(&mut self) { + while let Some(effect) = self.pending_effects.pop_front() { + match effect { + Effect::Notify(entity_id) => self.apply_notify_effect(entity_id), + } + } + + let dirty_window_ids = self + .windows + .iter() + .filter_map(|(window_id, window)| { + let window = window.as_ref().unwrap(); + if window.dirty { + Some(window_id) + } else { + None + } + }) + .collect::>(); + + for dirty_window_id in dirty_window_ids { + self.update_window(dirty_window_id, |cx| cx.draw()) + .unwrap() + .log_err(); + } + } + + fn apply_notify_effect(&mut self, updated_entity: EntityId) { + if let Some(mut handlers) = self.observers.remove(&updated_entity) { + handlers.retain(|handler| handler(self)); + if let Some(new_handlers) = self.observers.remove(&updated_entity) { + handlers.extend(new_handlers); + } + self.observers.insert(updated_entity, handlers); + } } - pub fn to_async(&self) -> AsyncContext { - AsyncContext(self.this.clone()) + pub fn to_async(&self) -> AsyncContext { + AsyncContext(unsafe { mem::transmute(self.this.clone()) }) } pub fn run_on_main( &self, - f: impl FnOnce(&mut AppContext) -> R + Send + 'static, + f: impl FnOnce(&mut MainThread) -> R + Send + 'static, ) -> impl Future where R: Send + 'static, @@ -132,16 +179,15 @@ impl AppContext { let this = self.this.upgrade().unwrap(); run_on_main(self.dispatcher.clone(), move || { let cx = &mut *this.lock(); - let main_thread_cx = unsafe { - std::mem::transmute::<&mut AppContext, &mut AppContext>(cx) - }; - main_thread_cx.update(|cx| f(cx)) + cx.update(|cx| { + f(unsafe { mem::transmute::<&mut AppContext, &mut MainThread>(cx) }) + }) }) } pub fn spawn_on_main( &self, - f: impl FnOnce(&mut AppContext) -> F + Send + 'static, + f: impl FnOnce(&mut MainThread) -> F + Send + 'static, ) -> impl Future where F: Future + 'static, @@ -150,13 +196,16 @@ impl AppContext { let this = self.this.upgrade().unwrap(); spawn_on_main(self.dispatcher.clone(), move || { let cx = &mut *this.lock(); - let main_thread_cx = unsafe { - std::mem::transmute::<&mut AppContext, &mut AppContext>(cx) - }; - main_thread_cx.update(|cx| f(cx)) + cx.update(|cx| { + f(unsafe { mem::transmute::<&mut AppContext, &mut MainThread>(cx) }) + }) }) } + pub fn text_system(&self) -> &Arc { + &self.text_system + } + pub fn text_style(&self) -> TextStyle { let mut style = TextStyle::default(); for refinement in &self.text_style_stack { @@ -204,77 +253,6 @@ impl AppContext { .and_then(|stack| stack.pop()) .expect("state stack underflow"); } - - pub(crate) fn update_window( - &mut self, - id: WindowId, - update: impl FnOnce(&mut WindowContext) -> R, - ) -> Result { - self.update(|cx| { - let mut window = cx - .windows - .get_mut(id) - .ok_or_else(|| anyhow!("window not found"))? - .take() - .unwrap(); - - let result = update(&mut WindowContext::mutable(cx.downcast_mut(), &mut window)); - - cx.windows - .get_mut(id) - .ok_or_else(|| anyhow!("window not found"))? - .replace(window); - - Ok(result) - }) - } - - fn update(&mut self, update: impl FnOnce(&mut Self) -> R) -> R { - self.pending_updates += 1; - let result = update(self); - if self.pending_updates == 1 { - self.flush_effects(); - } - self.pending_updates -= 1; - result - } - - fn flush_effects(&mut self) { - while let Some(effect) = self.pending_effects.pop_front() { - match effect { - Effect::Notify(entity_id) => self.apply_notify_effect(entity_id), - } - } - - let dirty_window_ids = self - .windows - .iter() - .filter_map(|(window_id, window)| { - let window = window.as_ref().unwrap(); - if window.dirty { - Some(window_id) - } else { - None - } - }) - .collect::>(); - - for dirty_window_id in dirty_window_ids { - self.update_window(dirty_window_id, |cx| cx.draw()) - .unwrap() - .log_err(); - } - } - - fn apply_notify_effect(&mut self, updated_entity: EntityId) { - if let Some(mut handlers) = self.observers.remove(&updated_entity) { - handlers.retain(|handler| handler(self)); - if let Some(new_handlers) = self.observers.remove(&updated_entity) { - handlers.extend(new_handlers); - } - self.observers.insert(updated_entity, handlers); - } - } } impl Context for AppContext { @@ -302,7 +280,15 @@ impl Context for AppContext { } } -impl AppContext { +impl MainThread { + fn update(&mut self, update: impl FnOnce(&mut Self) -> R) -> R { + self.0.update(|cx| { + update(unsafe { + std::mem::transmute::<&mut AppContext, &mut MainThread>(cx) + }) + }) + } + pub(crate) fn platform(&self) -> &dyn Platform { self.platform.borrow_on_main_thread() } @@ -320,8 +306,7 @@ impl AppContext { let id = cx.windows.insert(None); let handle = WindowHandle::new(id); let mut window = Window::new(handle.into(), options, cx); - let root_view = - build_root_view(&mut WindowContext::mutable(cx.downcast_mut(), &mut window)); + let root_view = build_root_view(&mut WindowContext::mutable(cx, &mut window)); window.root_view.replace(root_view.into_any()); cx.windows.get_mut(id).unwrap().replace(window); handle diff --git a/crates/gpui3/src/app/async_context.rs b/crates/gpui3/src/app/async_context.rs index f9c5d6f656838e79f923a504ee34bed4c9afdf8a..1f4cf537776bc4a3b4d9e1658a327b72cbd1b348 100644 --- a/crates/gpui3/src/app/async_context.rs +++ b/crates/gpui3/src/app/async_context.rs @@ -4,10 +4,10 @@ use parking_lot::Mutex; use std::sync::Weak; #[derive(Clone)] -pub struct AsyncContext(pub(crate) Weak>>); +pub struct AsyncContext(pub(crate) Weak>); impl Context for AsyncContext { - type EntityContext<'a, 'b, T: Send + Sync + 'static> = ModelContext<'a, T>; + type EntityContext<'a, 'b, T: 'static + Send + Sync> = ModelContext<'a, T>; type Result = Result; fn entity( @@ -36,7 +36,7 @@ impl Context for AsyncContext { } } -impl AsyncContext { +impl AsyncContext { pub fn update_window( &self, handle: AnyWindowHandle, diff --git a/crates/gpui3/src/app/model_context.rs b/crates/gpui3/src/app/model_context.rs index 67b90db97160b5c0a5689685a42be3953e52cffd..b16d29057a60dd7aad13da24a4fb7d1eea5d7cd9 100644 --- a/crates/gpui3/src/app/model_context.rs +++ b/crates/gpui3/src/app/model_context.rs @@ -1,8 +1,8 @@ use crate::{AppContext, Context, Effect, EntityId, Handle, Reference, WeakHandle}; use std::{marker::PhantomData, sync::Arc}; -pub struct ModelContext<'a, T, Thread = ()> { - app: Reference<'a, AppContext>, +pub struct ModelContext<'a, T> { + app: Reference<'a, AppContext>, entity_type: PhantomData, entity_id: EntityId, } diff --git a/crates/gpui3/src/gpui3.rs b/crates/gpui3/src/gpui3.rs index 401c69fc71564d53b2c10fa4db97377b6babc5bd..d62b42ed747edc31dcddffec669cf5fd30ea239b 100644 --- a/crates/gpui3/src/gpui3.rs +++ b/crates/gpui3/src/gpui3.rs @@ -45,7 +45,7 @@ pub use view::*; pub use window::*; pub trait Context { - type EntityContext<'a, 'w, T: Send + Sync + 'static>; + type EntityContext<'a, 'w, T: 'static + Send + Sync>; type Result; fn entity( @@ -60,6 +60,29 @@ pub trait Context { ) -> Self::Result; } +#[repr(transparent)] +pub struct MainThread(T); + +impl MainThread { + fn new(value: T) -> Self { + Self(value) + } +} + +impl Deref for MainThread { + type Target = T; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl DerefMut for MainThread { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} + pub trait StackContext { fn app(&mut self) -> &mut AppContext; @@ -154,8 +177,6 @@ impl<'a, T> DerefMut for Reference<'a, T> { } } -pub struct MainThread; - pub(crate) struct MainThreadOnly { dispatcher: Arc, value: Arc, diff --git a/crates/gpui3/src/view.rs b/crates/gpui3/src/view.rs index 7b510c6674023353304e79a1444b7a4cb03dc24a..5c7f7a766d278158c56df7a4ffec58d8ad3036fb 100644 --- a/crates/gpui3/src/view.rs +++ b/crates/gpui3/src/view.rs @@ -1,15 +1,14 @@ use parking_lot::Mutex; use crate::{ - AnyElement, Element, Handle, IntoAnyElement, Layout, LayoutId, MainThread, Result, ViewContext, + AnyElement, Element, Handle, IntoAnyElement, Layout, LayoutId, Result, ViewContext, WindowContext, }; use std::{any::Any, marker::PhantomData, sync::Arc}; -pub struct View { +pub struct View { state: Handle, - render: - Arc) -> AnyElement + Send + Sync + 'static>, + render: Arc) -> AnyElement + Send + Sync + 'static>, parent_state_type: PhantomData

, } diff --git a/crates/gpui3/src/window.rs b/crates/gpui3/src/window.rs index 85cd5d3311c85ec125f74f80ec7ae268b0ad1593..25b4dc1df1c6ccdf0b698e88596e128e5ecb804d 100644 --- a/crates/gpui3/src/window.rs +++ b/crates/gpui3/src/window.rs @@ -1,10 +1,9 @@ use crate::{ px, AnyView, AppContext, AvailableSpace, Bounds, Context, Effect, Element, EntityId, Handle, - LayoutId, MainThread, MainThreadOnly, Pixels, Platform, PlatformWindow, Point, Reference, - Scene, Size, StackContext, Style, TaffyLayoutEngine, WeakHandle, WindowOptions, + LayoutId, MainThread, MainThreadOnly, Pixels, PlatformWindow, Point, Reference, Scene, Size, + StackContext, Style, TaffyLayoutEngine, WeakHandle, WindowOptions, }; use anyhow::Result; -use derive_more::{Deref, DerefMut}; use std::{any::TypeId, marker::PhantomData, sync::Arc}; use util::ResultExt; @@ -26,7 +25,7 @@ impl Window { pub fn new( handle: AnyWindowHandle, options: WindowOptions, - cx: &mut AppContext, + cx: &mut MainThread, ) -> Self { let platform_window = cx.platform().open_window(handle, options); let mouse_position = platform_window.mouse_position(); @@ -62,19 +61,14 @@ impl Window { } } -#[derive(Deref, DerefMut)] -pub struct WindowContext<'a, 'w, Thread = ()> { - thread: PhantomData, - #[deref] - #[deref_mut] - app: Reference<'a, AppContext>, +pub struct WindowContext<'a, 'w> { + app: Reference<'a, AppContext>, window: Reference<'w, Window>, } impl<'a, 'w> WindowContext<'a, 'w> { pub(crate) fn mutable(app: &'a mut AppContext, window: &'w mut Window) -> Self { Self { - thread: PhantomData, app: Reference::Mutable(app), window: Reference::Mutable(window), } @@ -157,7 +151,7 @@ impl<'a, 'w> WindowContext<'a, 'w> { } } -impl WindowContext<'_, '_, MainThread> { +impl MainThread> { // todo!("implement other methods that use platform window") fn platform_window(&self) -> &dyn PlatformWindow { self.window.platform_window.borrow_on_main_thread().as_ref() @@ -165,14 +159,14 @@ impl WindowContext<'_, '_, MainThread> { } impl Context for WindowContext<'_, '_> { - type EntityContext<'a, 'w, T: Send + Sync + 'static> = ViewContext<'a, 'w, T>; + type EntityContext<'a, 'w, T: 'static + Send + Sync> = ViewContext<'a, 'w, T>; type Result = T; fn entity( &mut self, build_entity: impl FnOnce(&mut Self::EntityContext<'_, '_, T>) -> T, ) -> Handle { - let slot = self.entities.reserve(); + let slot = self.app.entities.reserve(); let entity = build_entity(&mut ViewContext::mutable( &mut *self.app, &mut self.window, @@ -196,18 +190,32 @@ impl Context for WindowContext<'_, '_> { } } +impl<'a, 'w> std::ops::Deref for WindowContext<'a, 'w> { + type Target = AppContext; + + fn deref(&self) -> &Self::Target { + &self.app + } +} + +impl<'a, 'w> std::ops::DerefMut for WindowContext<'a, 'w> { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.app + } +} + impl StackContext for ViewContext<'_, '_, S> { fn app(&mut self) -> &mut AppContext { - &mut *self.app + &mut *self.window_cx.app } fn with_text_style(&mut self, style: crate::TextStyleRefinement, f: F) -> R where F: FnOnce(&mut Self) -> R, { - self.push_text_style(style); + self.window_cx.app.push_text_style(style); let result = f(self); - self.pop_text_style(); + self.window_cx.app.pop_text_style(); result } @@ -215,21 +223,17 @@ impl StackContext for ViewContext<'_, '_, S> { where F: FnOnce(&mut Self) -> R, { - self.push_state(state); + self.window_cx.app.push_state(state); let result = f(self); - self.pop_state::(); + self.window_cx.app.pop_state::(); result } } -#[derive(Deref, DerefMut)] -pub struct ViewContext<'a, 'w, S, Thread = ()> { - #[deref] - #[deref_mut] - window_cx: WindowContext<'a, 'w, Thread>, +pub struct ViewContext<'a, 'w, S> { + window_cx: WindowContext<'a, 'w>, entity_type: PhantomData, entity_id: EntityId, - thread: PhantomData, } impl<'a, 'w, S: Send + Sync + 'static> ViewContext<'a, 'w, S> { @@ -238,7 +242,6 @@ impl<'a, 'w, S: Send + Sync + 'static> ViewContext<'a, 'w, S> { window_cx: WindowContext::mutable(app, window), entity_id, entity_type: PhantomData, - thread: PhantomData, } } @@ -290,8 +293,8 @@ impl<'a, 'w, S: Send + Sync + 'static> ViewContext<'a, 'w, S> { } } -impl<'a, 'w, S: 'static> Context for ViewContext<'a, 'w, S> { - type EntityContext<'b, 'c, U: Send + Sync + 'static> = ViewContext<'b, 'c, U>; +impl<'a, 'w, S> Context for ViewContext<'a, 'w, S> { + type EntityContext<'b, 'c, U: 'static + Send + Sync> = ViewContext<'b, 'c, U>; type Result = U; fn entity( @@ -310,7 +313,19 @@ impl<'a, 'w, S: 'static> Context for ViewContext<'a, 'w, S> { } } -impl ViewContext<'_, '_, S, MainThread> {} +impl<'a, 'w, S: 'static> std::ops::Deref for ViewContext<'a, 'w, S> { + type Target = WindowContext<'a, 'w>; + + fn deref(&self) -> &Self::Target { + &self.window_cx + } +} + +impl<'a, 'w, S: 'static> std::ops::DerefMut for ViewContext<'a, 'w, S> { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.window_cx + } +} // #[derive(Clone, Copy, Eq, PartialEq, Hash)] slotmap::new_key_type! { pub struct WindowId; } diff --git a/crates/storybook2/src/workspace.rs b/crates/storybook2/src/workspace.rs index 19b3711db5353ed86d346bb4e88c819ad40da9e1..7190035f22fd85c7bcc73187dfcec3c005c55ecf 100644 --- a/crates/storybook2/src/workspace.rs +++ b/crates/storybook2/src/workspace.rs @@ -1,6 +1,6 @@ use crate::{ collab_panel::{collab_panel, CollabPanel}, - theme::{theme, themed}, + theme::theme, themes::rose_pine_dawn, }; use gpui3::{