From ed95d4a3463465eceb5c613232e6fc2f771f2fdc Mon Sep 17 00:00:00 2001 From: PolyMeilex Date: Sun, 8 Dec 2024 00:30:25 +0100 Subject: [PATCH] nuon: Remove Widget::children_tree & Widget::diff --- .../playing_scene/top_bar/widget/looper.rs | 4 +- .../top_bar/widget/progress_bar.rs | 4 +- .../top_bar/widget/speed_pill.rs | 4 +- nuon/src/lib.rs | 40 ++------ nuon/src/tree.rs | 91 ++++++++++++------- nuon/src/widget/button.rs | 4 +- 6 files changed, 76 insertions(+), 71 deletions(-) diff --git a/neothesia/src/scene/playing_scene/top_bar/widget/looper.rs b/neothesia/src/scene/playing_scene/top_bar/widget/looper.rs index 446bca2..ed19853 100644 --- a/neothesia/src/scene/playing_scene/top_bar/widget/looper.rs +++ b/neothesia/src/scene/playing_scene/top_bar/widget/looper.rs @@ -123,7 +123,7 @@ impl Widget for Looper { tree: &Tree, _ctx: &RenderCtx, ) { - let state = tree.state(); + let state = tree.state.get(); let bg = &layout.children[0]; @@ -160,7 +160,7 @@ impl Widget for Looper { tree: &mut Tree, ctx: &mut UpdateCtx, ) { - let state = tree.state_mut(); + let state = tree.state.get_mut(); let player = ctx.globals.get::(); match event { diff --git a/neothesia/src/scene/playing_scene/top_bar/widget/progress_bar.rs b/neothesia/src/scene/playing_scene/top_bar/widget/progress_bar.rs index 65ceaa4..3841818 100644 --- a/neothesia/src/scene/playing_scene/top_bar/widget/progress_bar.rs +++ b/neothesia/src/scene/playing_scene/top_bar/widget/progress_bar.rs @@ -73,7 +73,7 @@ impl Widget for ProgressBar { tree: &Tree, ctx: &RenderCtx, ) { - let _state = tree.state(); + let _state = tree.state.get(); let player = ctx.globals.get::(); let progress_w = layout.w * player.percentage(); @@ -107,7 +107,7 @@ impl Widget for ProgressBar { tree: &mut Tree, ctx: &mut UpdateCtx, ) { - let state = tree.state_mut(); + let state = tree.state.get_mut(); match event { Event::CursorMoved { position } => { diff --git a/neothesia/src/scene/playing_scene/top_bar/widget/speed_pill.rs b/neothesia/src/scene/playing_scene/top_bar/widget/speed_pill.rs index afbb367..1919667 100644 --- a/neothesia/src/scene/playing_scene/top_bar/widget/speed_pill.rs +++ b/neothesia/src/scene/playing_scene/top_bar/widget/speed_pill.rs @@ -77,7 +77,7 @@ impl Widget for SpeedPill { fn layout(&self, tree: &mut Tree, parent: &ParentLayout, ctx: &LayoutCtx) -> Node { let minus = self.children[0].as_widget().layout( - tree.children[0].remap_mut(), + &mut tree.children[0], &ParentLayout { x: parent.x, y: parent.y + 5.0, @@ -87,7 +87,7 @@ impl Widget for SpeedPill { ctx, ); let plus = self.children[1].as_widget().layout( - tree.children[1].remap_mut(), + &mut tree.children[1], &ParentLayout { x: parent.x + minus.w, y: parent.y + 5.0, diff --git a/nuon/src/lib.rs b/nuon/src/lib.rs index 506fddc..81ae173 100644 --- a/nuon/src/lib.rs +++ b/nuon/src/lib.rs @@ -4,7 +4,7 @@ use std::{ collections::HashMap, }; -pub use tree::Tree; +pub use tree::{Tree, TreeState}; pub use widget::*; pub use euclid; @@ -100,12 +100,9 @@ pub struct ParentLayout { pub trait WidgetAny { fn state_type_id(&self) -> TypeId; - fn state(&self) -> Box; + fn state(&self) -> TreeState; fn children(&self) -> &[Element]; - fn children_tree(&self) -> Vec; - - fn diff(&self, tree: &mut Tree); fn layout(&self, tree: &mut Tree, avalilable: &ParentLayout, ctx: &LayoutCtx) -> Node; fn render(&self, renderer: &mut dyn Renderer, layout: &Node, tree: &Tree, ctx: &RenderCtx); @@ -117,28 +114,20 @@ impl> WidgetAny for W { TypeId::of::() } - fn state(&self) -> Box { - Widget::state(self) + fn state(&self) -> TreeState { + TreeState::new(Widget::state(self)) } fn children(&self) -> &[Element] { Widget::children(self) } - fn children_tree(&self) -> Vec { - Widget::children_tree(self) - } - - fn diff(&self, tree: &mut Tree) { - Widget::diff(self, tree) - } - fn layout(&self, tree: &mut Tree, parent: &ParentLayout, ctx: &LayoutCtx) -> Node { - Widget::layout(self, tree.remap_mut(), parent, ctx) + Widget::layout(self, tree.cast_mut(), parent, ctx) } fn render(&self, renderer: &mut dyn Renderer, layout: &Node, tree: &Tree, ctx: &RenderCtx) { - Widget::render(self, renderer, layout, tree.remap_ref(), ctx) + Widget::render(self, renderer, layout, tree.cast_ref(), ctx) } fn update( @@ -148,32 +137,21 @@ impl> WidgetAny for W { tree: &mut Tree, ctx: &mut UpdateCtx, ) { - Widget::update(self, event, layout, tree.remap_mut(), ctx) + Widget::update(self, event, layout, tree.cast_mut(), ctx) } } pub trait Widget { type State: Any + Default; - fn state(&self) -> Box { - Box::new(Self::State::default()) + fn state(&self) -> Self::State { + Self::State::default() } fn children(&self) -> &[Element] { &[] } - fn children_tree(&self) -> Vec { - self.children() - .iter() - .map(|w| Tree::new(w.as_widget())) - .collect() - } - - fn diff(&self, tree: &mut Tree) { - tree.diff_children(self.children()); - } - fn layout(&self, tree: &mut Tree, parent: &ParentLayout, ctx: &LayoutCtx) -> Node { widget::stack::stack_layout(self, tree, parent, ctx) } diff --git a/nuon/src/tree.rs b/nuon/src/tree.rs index 698b0de..9d4093e 100644 --- a/nuon/src/tree.rs +++ b/nuon/src/tree.rs @@ -8,73 +8,104 @@ use crate::{Element, WidgetAny}; pub struct UnknownState; struct NullTreeState; -pub struct Tree { - pub state: Box, - pub children: Vec, +#[track_caller] +fn type_check_assert(state_type_id: TypeId) { + if TypeId::of::() != TypeId::of::() { + assert_eq!(TypeId::of::(), state_type_id); + } else { + // Always allow cast to unknown + } +} + +pub struct TreeState { + state: Box, _ph: PhantomData, } -impl Tree { - pub fn remap(self) -> Tree { - if TypeId::of::() != TypeId::of::() { - assert_eq!(TypeId::of::(), self.state_type_id()); +impl TreeState { + pub(crate) fn new(state: impl Any) -> Self { + Self { + state: Box::new(state), + _ph: PhantomData, } + } - // SAFTETY: T is only in phantom data - unsafe { std::mem::transmute(self) } + pub fn get(&self) -> &T { + self.state.downcast_ref::().unwrap() } - pub fn remap_ref(&self) -> &Tree { - if TypeId::of::() != TypeId::of::() { - assert_eq!(TypeId::of::(), self.state_type_id()); - } + pub fn get_mut(&mut self) -> &mut T { + self.state.downcast_mut::().unwrap() + } + + fn state_type_id(&self) -> TypeId { + self.state.as_ref().type_id() + } + fn cast(self) -> TreeState { + type_check_assert::(self.state_type_id()); // SAFTETY: T is only in phantom data unsafe { std::mem::transmute(self) } } +} - pub fn remap_mut(&mut self) -> &mut Tree { - if TypeId::of::() != TypeId::of::() { - assert_eq!(TypeId::of::(), self.state_type_id()); - } +pub struct Tree { + pub state: TreeState, + pub children: Vec, + _ph: PhantomData, +} +impl Tree { + #[expect(unused)] + pub(crate) fn cast(self) -> Tree { + type_check_assert::(self.state.state_type_id()); // SAFTETY: T is only in phantom data unsafe { std::mem::transmute(self) } } - pub fn state(&self) -> &T { - self.state.downcast_ref::().unwrap() + pub(crate) fn cast_ref(&self) -> &Tree { + type_check_assert::(self.state.state_type_id()); + // SAFTETY: T is only in phantom data + unsafe { std::mem::transmute(self) } } - pub fn state_mut(&mut self) -> &mut T { - self.state.downcast_mut::().unwrap() + pub(crate) fn cast_mut(&mut self) -> &mut Tree { + type_check_assert::(self.state.state_type_id()); + // SAFTETY: T is only in phantom data + unsafe { std::mem::transmute(self) } } pub fn null() -> Self { Self { - state: Box::new(NullTreeState), + state: TreeState::new(Box::new(NullTreeState)), children: Vec::new(), _ph: PhantomData, } } pub fn new(widget: &dyn WidgetAny) -> Self { + let children = widget + .children() + .iter() + .map(|w| Tree::new(w.as_widget())) + .collect(); + Self { - state: widget.state(), - children: widget.children_tree(), + state: widget.state().cast(), + children, _ph: PhantomData, } } pub fn diff(&mut self, new: &dyn WidgetAny) { - if self.state_type_id() == new.state_type_id() { - new.diff(self.remap_mut()); + if self.state.state_type_id() == new.state_type_id() { + self.diff_children(new.children()); } else { *self = Self::new(new); } } - pub fn diff_children(&mut self, new_children: &[Element]) { + fn diff_children(&mut self, new_children: &[Element]) { if self.children.len() > new_children.len() { self.children.truncate(new_children.len()); } @@ -87,12 +118,8 @@ impl Tree { self.children.extend( new_children[self.children.len()..] .iter() - .map(|widget| Self::new(widget.as_widget()).remap()), + .map(|widget| Tree::new(widget.as_widget())), ); } } - - pub fn state_type_id(&self) -> TypeId { - self.state.as_ref().type_id() - } } diff --git a/nuon/src/widget/button.rs b/nuon/src/widget/button.rs index ebb69be..fdd0c68 100644 --- a/nuon/src/widget/button.rs +++ b/nuon/src/widget/button.rs @@ -111,7 +111,7 @@ impl Widget for Button { tree: &Tree, _ctx: &RenderCtx, ) { - let state = tree.state(); + let state = tree.state.get(); renderer.rounded_quad( layout.x, @@ -146,7 +146,7 @@ impl Widget for Button { tree: &mut Tree, ctx: &mut UpdateCtx, ) { - let state = tree.state_mut(); + let state = tree.state.get_mut(); match event { Event::CursorMoved { position } => {