Introduce Tag and State opaque types in iced_pure::widget::tree

This commit is contained in:
Héctor Ramón Jiménez 2022-02-16 15:44:50 +07:00
parent cff891833b
commit 35e9b75e41
No known key found for this signature in database
GPG key ID: 140CC052C94F138E
16 changed files with 101 additions and 197 deletions

View file

@ -37,15 +37,7 @@ use iced_native::mouse;
use iced_native::renderer; use iced_native::renderer;
use iced_native::{Clipboard, Hasher, Length, Point, Rectangle, Shell}; use iced_native::{Clipboard, Hasher, Length, Point, Rectangle, Shell};
use std::any::{self, Any};
pub trait Widget<Message, Renderer> { pub trait Widget<Message, Renderer> {
fn tag(&self) -> any::TypeId;
fn state(&self) -> Box<dyn Any>;
fn children_state(&self) -> Vec<Tree>;
fn width(&self) -> Length; fn width(&self) -> Length;
fn height(&self) -> Length; fn height(&self) -> Length;
@ -68,6 +60,18 @@ pub trait Widget<Message, Renderer> {
viewport: &Rectangle, viewport: &Rectangle,
); );
fn tag(&self) -> tree::Tag {
tree::Tag::stateless()
}
fn state(&self) -> tree::State {
tree::State::None
}
fn children(&self) -> Vec<Tree> {
Vec::new()
}
fn diff(&self, _tree: &mut Tree) {} fn diff(&self, _tree: &mut Tree) {}
fn mouse_interaction( fn mouse_interaction(

View file

@ -1,4 +1,5 @@
use crate::widget::{Element, Tree, Widget}; use crate::widget::tree::{self, Tree};
use crate::widget::{Element, Widget};
use iced_native::event::{self, Event}; use iced_native::event::{self, Event};
use iced_native::layout; use iced_native::layout;
@ -10,8 +11,6 @@ use iced_native::{
}; };
use iced_style::button::StyleSheet; use iced_style::button::StyleSheet;
use std::any::Any;
pub use button::State; pub use button::State;
pub struct Button<'a, Message, Renderer> { pub struct Button<'a, Message, Renderer> {
@ -77,22 +76,22 @@ where
Message: 'static + Clone, Message: 'static + Clone,
Renderer: 'static + iced_native::Renderer, Renderer: 'static + iced_native::Renderer,
{ {
fn tag(&self) -> std::any::TypeId { fn tag(&self) -> tree::Tag {
std::any::TypeId::of::<State>() tree::Tag::of::<State>()
} }
fn state(&self) -> Box<dyn Any> { fn state(&self) -> tree::State {
Box::new(State::new()) tree::State::new(State::new())
}
fn children(&self) -> Vec<Tree> {
vec![Tree::new(&self.content)]
} }
fn diff(&self, tree: &mut Tree) { fn diff(&self, tree: &mut Tree) {
tree.diff_children(std::slice::from_ref(&self.content)) tree.diff_children(std::slice::from_ref(&self.content))
} }
fn children_state(&self) -> Vec<Tree> {
vec![Tree::new(&self.content)]
}
fn width(&self) -> Length { fn width(&self) -> Length {
self.width self.width
} }

View file

@ -7,8 +7,6 @@ use iced_native::renderer;
use iced_native::text; use iced_native::text;
use iced_native::{Clipboard, Hasher, Length, Point, Rectangle, Shell}; use iced_native::{Clipboard, Hasher, Length, Point, Rectangle, Shell};
use std::any::{self, Any};
pub use iced_native::widget::Checkbox; pub use iced_native::widget::Checkbox;
impl<'a, Message, Renderer> Widget<Message, Renderer> impl<'a, Message, Renderer> Widget<Message, Renderer>
@ -16,20 +14,6 @@ impl<'a, Message, Renderer> Widget<Message, Renderer>
where where
Renderer: text::Renderer, Renderer: text::Renderer,
{ {
fn tag(&self) -> any::TypeId {
any::TypeId::of::<()>()
}
fn state(&self) -> Box<dyn Any> {
Box::new(())
}
fn diff(&self, _tree: &mut Tree) {}
fn children_state(&self) -> Vec<Tree> {
Vec::new()
}
fn width(&self) -> Length { fn width(&self) -> Length {
<Self as iced_native::Widget<Message, Renderer>>::width(self) <Self as iced_native::Widget<Message, Renderer>>::width(self)
} }

View file

@ -9,7 +9,6 @@ use iced_native::{
Alignment, Clipboard, Hasher, Length, Padding, Point, Rectangle, Shell, Alignment, Clipboard, Hasher, Length, Padding, Point, Rectangle, Shell,
}; };
use std::any::{self, Any};
use std::u32; use std::u32;
pub struct Column<'a, Message, Renderer> { pub struct Column<'a, Message, Renderer> {
@ -86,22 +85,14 @@ impl<'a, Message, Renderer> Widget<Message, Renderer>
where where
Renderer: iced_native::Renderer, Renderer: iced_native::Renderer,
{ {
fn tag(&self) -> any::TypeId { fn children(&self) -> Vec<Tree> {
any::TypeId::of::<()>() self.children.iter().map(Tree::new).collect()
}
fn state(&self) -> Box<dyn Any> {
Box::new(())
} }
fn diff(&self, tree: &mut Tree) { fn diff(&self, tree: &mut Tree) {
tree.diff_children(&self.children); tree.diff_children(&self.children);
} }
fn children_state(&self) -> Vec<Tree> {
self.children.iter().map(Tree::new).collect()
}
fn width(&self) -> Length { fn width(&self) -> Length {
self.width self.width
} }

View file

@ -11,7 +11,6 @@ use iced_native::{
Clipboard, Hasher, Layout, Length, Padding, Point, Rectangle, Shell, Clipboard, Hasher, Layout, Length, Padding, Point, Rectangle, Shell,
}; };
use std::any::{self, Any};
use std::hash::Hash; use std::hash::Hash;
use std::u32; use std::u32;
@ -124,22 +123,14 @@ impl<'a, Message, Renderer> Widget<Message, Renderer>
where where
Renderer: iced_native::Renderer, Renderer: iced_native::Renderer,
{ {
fn tag(&self) -> any::TypeId { fn children(&self) -> Vec<Tree> {
any::TypeId::of::<()>() vec![Tree::new(&self.content)]
}
fn state(&self) -> Box<dyn Any> {
Box::new(())
} }
fn diff(&self, tree: &mut Tree) { fn diff(&self, tree: &mut Tree) {
tree.diff_children(std::slice::from_ref(&self.content)) tree.diff_children(std::slice::from_ref(&self.content))
} }
fn children_state(&self) -> Vec<Tree> {
vec![Tree::new(&self.content)]
}
fn width(&self) -> Length { fn width(&self) -> Length {
self.width self.width
} }

View file

@ -1,4 +1,5 @@
use crate::widget::{Tree, Widget}; use crate::widget::tree::{self, Tree};
use crate::widget::Widget;
use iced_native::event::{self, Event}; use iced_native::event::{self, Event};
use iced_native::layout::{self, Layout}; use iced_native::layout::{self, Layout};
@ -6,8 +7,6 @@ use iced_native::mouse;
use iced_native::renderer; use iced_native::renderer;
use iced_native::{Clipboard, Hasher, Length, Point, Rectangle, Shell}; use iced_native::{Clipboard, Hasher, Length, Point, Rectangle, Shell};
use std::any::{self, Any};
pub struct Element<'a, Message, Renderer> { pub struct Element<'a, Message, Renderer> {
widget: Box<dyn Widget<Message, Renderer> + 'a>, widget: Box<dyn Widget<Message, Renderer> + 'a>,
} }
@ -66,22 +65,22 @@ where
A: 'a, A: 'a,
B: 'a, B: 'a,
{ {
fn tag(&self) -> any::TypeId { fn tag(&self) -> tree::Tag {
self.widget.tag() self.widget.tag()
} }
fn state(&self) -> Box<dyn Any> { fn state(&self) -> tree::State {
self.widget.state() self.widget.state()
} }
fn children(&self) -> Vec<Tree> {
self.widget.children()
}
fn diff(&self, tree: &mut Tree) { fn diff(&self, tree: &mut Tree) {
self.widget.diff(tree) self.widget.diff(tree)
} }
fn children_state(&self) -> Vec<Tree> {
self.widget.children_state()
}
fn width(&self) -> Length { fn width(&self) -> Length {
self.widget.width() self.widget.width()
} }

View file

@ -6,7 +6,6 @@ use iced_native::renderer;
use iced_native::widget::image; use iced_native::widget::image;
use iced_native::{Hasher, Length, Point, Rectangle}; use iced_native::{Hasher, Length, Point, Rectangle};
use std::any::{self, Any};
use std::hash::Hash; use std::hash::Hash;
pub use image::Image; pub use image::Image;
@ -16,20 +15,6 @@ where
Handle: Clone + Hash, Handle: Clone + Hash,
Renderer: iced_native::image::Renderer<Handle = Handle>, Renderer: iced_native::image::Renderer<Handle = Handle>,
{ {
fn tag(&self) -> any::TypeId {
any::TypeId::of::<()>()
}
fn state(&self) -> Box<dyn Any> {
Box::new(())
}
fn children_state(&self) -> Vec<Tree> {
Vec::new()
}
fn diff(&self, _tree: &mut Tree) {}
fn width(&self) -> Length { fn width(&self) -> Length {
<Self as iced_native::Widget<Message, Renderer>>::width(self) <Self as iced_native::Widget<Message, Renderer>>::width(self)
} }

View file

@ -7,8 +7,6 @@ use iced_native::renderer;
use iced_native::text; use iced_native::text;
use iced_native::{Clipboard, Hasher, Length, Point, Rectangle, Shell}; use iced_native::{Clipboard, Hasher, Length, Point, Rectangle, Shell};
use std::any::{self, Any};
pub use iced_native::widget::Radio; pub use iced_native::widget::Radio;
impl<'a, Message, Renderer> Widget<Message, Renderer> impl<'a, Message, Renderer> Widget<Message, Renderer>
@ -17,20 +15,6 @@ where
Message: Clone, Message: Clone,
Renderer: text::Renderer, Renderer: text::Renderer,
{ {
fn tag(&self) -> any::TypeId {
any::TypeId::of::<()>()
}
fn state(&self) -> Box<dyn Any> {
Box::new(())
}
fn diff(&self, _tree: &mut Tree) {}
fn children_state(&self) -> Vec<Tree> {
Vec::new()
}
fn width(&self) -> Length { fn width(&self) -> Length {
<Self as iced_native::Widget<Message, Renderer>>::width(self) <Self as iced_native::Widget<Message, Renderer>>::width(self)
} }

View file

@ -9,8 +9,6 @@ use iced_native::{
Alignment, Clipboard, Hasher, Length, Padding, Point, Rectangle, Shell, Alignment, Clipboard, Hasher, Length, Padding, Point, Rectangle, Shell,
}; };
use std::any::{self, Any};
pub struct Row<'a, Message, Renderer> { pub struct Row<'a, Message, Renderer> {
spacing: u16, spacing: u16,
padding: Padding, padding: Padding,
@ -77,22 +75,14 @@ impl<'a, Message, Renderer> Widget<Message, Renderer>
where where
Renderer: iced_native::Renderer, Renderer: iced_native::Renderer,
{ {
fn tag(&self) -> any::TypeId { fn children(&self) -> Vec<Tree> {
any::TypeId::of::<()>() self.children.iter().map(Tree::new).collect()
}
fn state(&self) -> Box<dyn Any> {
Box::new(())
} }
fn diff(&self, tree: &mut Tree) { fn diff(&self, tree: &mut Tree) {
tree.diff_children(&self.children) tree.diff_children(&self.children)
} }
fn children_state(&self) -> Vec<Tree> {
self.children.iter().map(Tree::new).collect()
}
fn width(&self) -> Length { fn width(&self) -> Length {
self.width self.width
} }

View file

@ -1,4 +1,4 @@
use crate::widget::Tree; use crate::widget::tree::{self, Tree};
use crate::{Element, Widget}; use crate::{Element, Widget};
use iced_native::event::{self, Event}; use iced_native::event::{self, Event};
@ -10,8 +10,6 @@ use iced_native::{Clipboard, Hasher, Length, Point, Rectangle, Shell};
pub use iced_style::scrollable::StyleSheet; pub use iced_style::scrollable::StyleSheet;
use std::any::{self, Any};
/// A widget that can vertically display an infinite amount of content with a /// A widget that can vertically display an infinite amount of content with a
/// scrollbar. /// scrollbar.
#[allow(missing_debug_implementations)] #[allow(missing_debug_implementations)]
@ -92,22 +90,22 @@ impl<'a, Message, Renderer> Widget<Message, Renderer>
where where
Renderer: iced_native::Renderer, Renderer: iced_native::Renderer,
{ {
fn tag(&self) -> any::TypeId { fn tag(&self) -> tree::Tag {
any::TypeId::of::<scrollable::State>() tree::Tag::of::<scrollable::State>()
} }
fn state(&self) -> Box<dyn Any> { fn state(&self) -> tree::State {
Box::new(scrollable::State::new()) tree::State::new(scrollable::State::new())
}
fn children(&self) -> Vec<Tree> {
vec![Tree::new(&self.content)]
} }
fn diff(&self, tree: &mut Tree) { fn diff(&self, tree: &mut Tree) {
tree.diff_children(std::slice::from_ref(&self.content)) tree.diff_children(std::slice::from_ref(&self.content))
} }
fn children_state(&self) -> Vec<Tree> {
vec![Tree::new(&self.content)]
}
fn width(&self) -> Length { fn width(&self) -> Length {
self.content.as_widget().width() self.content.as_widget().width()
} }

View file

@ -1,7 +1,8 @@
//! Display an interactive selector of a single value from a range of values. //! Display an interactive selector of a single value from a range of values.
//! //!
//! A [`Slider`] has some local [`State`]. //! A [`Slider`] has some local [`State`].
use crate::{Element, Tree, Widget}; use crate::widget::tree::{self, Tree};
use crate::{Element, Widget};
use iced_native::event::{self, Event}; use iced_native::event::{self, Event};
use iced_native::layout; use iced_native::layout;
@ -12,7 +13,6 @@ use iced_native::{
Clipboard, Hasher, Layout, Length, Point, Rectangle, Shell, Size, Clipboard, Hasher, Layout, Length, Point, Rectangle, Shell, Size,
}; };
use std::any::{self, Any};
use std::ops::RangeInclusive; use std::ops::RangeInclusive;
pub use iced_style::slider::{Handle, HandleShape, Style, StyleSheet}; pub use iced_style::slider::{Handle, HandleShape, Style, StyleSheet};
@ -143,16 +143,12 @@ where
Message: Clone, Message: Clone,
Renderer: iced_native::Renderer, Renderer: iced_native::Renderer,
{ {
fn tag(&self) -> any::TypeId { fn tag(&self) -> tree::Tag {
any::TypeId::of::<slider::State>() tree::Tag::of::<slider::State>()
} }
fn state(&self) -> Box<dyn Any> { fn state(&self) -> tree::State {
Box::new(slider::State::new()) tree::State::new(slider::State::new())
}
fn children_state(&self) -> Vec<Tree> {
Vec::new()
} }
fn width(&self) -> Length { fn width(&self) -> Length {

View file

@ -7,8 +7,6 @@ use iced_native::renderer;
use iced_native::text; use iced_native::text;
use iced_native::{Clipboard, Hasher, Length, Point, Rectangle, Shell}; use iced_native::{Clipboard, Hasher, Length, Point, Rectangle, Shell};
use std::any::{self, Any};
pub use iced_native::widget::Space; pub use iced_native::widget::Space;
impl<'a, Message, Renderer> Widget<Message, Renderer> for Space impl<'a, Message, Renderer> Widget<Message, Renderer> for Space
@ -16,20 +14,6 @@ where
Message: Clone, Message: Clone,
Renderer: text::Renderer, Renderer: text::Renderer,
{ {
fn tag(&self) -> any::TypeId {
any::TypeId::of::<()>()
}
fn state(&self) -> Box<dyn Any> {
Box::new(())
}
fn diff(&self, _tree: &mut Tree) {}
fn children_state(&self) -> Vec<Tree> {
Vec::new()
}
fn width(&self) -> Length { fn width(&self) -> Length {
<Self as iced_native::Widget<Message, Renderer>>::width(self) <Self as iced_native::Widget<Message, Renderer>>::width(self)
} }

View file

@ -5,28 +5,12 @@ use iced_native::renderer;
use iced_native::text; use iced_native::text;
use iced_native::{Hasher, Length, Point, Rectangle}; use iced_native::{Hasher, Length, Point, Rectangle};
use std::any::{self, Any};
pub use iced_native::widget::Text; pub use iced_native::widget::Text;
impl<Message, Renderer> Widget<Message, Renderer> for Text<Renderer> impl<Message, Renderer> Widget<Message, Renderer> for Text<Renderer>
where where
Renderer: text::Renderer, Renderer: text::Renderer,
{ {
fn tag(&self) -> any::TypeId {
any::TypeId::of::<()>()
}
fn state(&self) -> Box<dyn Any> {
Box::new(())
}
fn diff(&self, _tree: &mut Tree) {}
fn children_state(&self) -> Vec<Tree> {
Vec::new()
}
fn width(&self) -> Length { fn width(&self) -> Length {
<Self as iced_native::Widget<Message, Renderer>>::width(self) <Self as iced_native::Widget<Message, Renderer>>::width(self)
} }

View file

@ -1,4 +1,5 @@
use crate::widget::{Element, Tree, Widget}; use crate::widget::tree::{self, Tree};
use crate::widget::{Element, Widget};
use iced_native::event::{self, Event}; use iced_native::event::{self, Event};
use iced_native::layout::{self, Layout}; use iced_native::layout::{self, Layout};
@ -12,8 +13,6 @@ use iced_native::{
pub use iced_style::text_input::StyleSheet; pub use iced_style::text_input::StyleSheet;
use std::any::{self, Any};
/// A field that can be filled with text. /// A field that can be filled with text.
/// ///
/// # Example /// # Example
@ -138,18 +137,12 @@ where
Message: Clone, Message: Clone,
Renderer: iced_native::text::Renderer, Renderer: iced_native::text::Renderer,
{ {
fn tag(&self) -> any::TypeId { fn tag(&self) -> tree::Tag {
any::TypeId::of::<text_input::State>() tree::Tag::of::<text_input::State>()
} }
fn state(&self) -> Box<dyn Any> { fn state(&self) -> tree::State {
Box::new(text_input::State::new()) tree::State::new(text_input::State::new())
}
fn diff(&self, _tree: &mut Tree) {}
fn children_state(&self) -> Vec<Tree> {
Vec::new()
} }
fn width(&self) -> Length { fn width(&self) -> Length {

View file

@ -8,8 +8,6 @@ use iced_native::renderer;
use iced_native::text; use iced_native::text;
use iced_native::{Clipboard, Hasher, Length, Point, Rectangle, Shell}; use iced_native::{Clipboard, Hasher, Length, Point, Rectangle, Shell};
use std::any::{self, Any};
pub use iced_native::widget::toggler::{Style, StyleSheet, Toggler}; pub use iced_native::widget::toggler::{Style, StyleSheet, Toggler};
impl<'a, Message, Renderer> Widget<Message, Renderer> impl<'a, Message, Renderer> Widget<Message, Renderer>
@ -17,18 +15,6 @@ impl<'a, Message, Renderer> Widget<Message, Renderer>
where where
Renderer: text::Renderer, Renderer: text::Renderer,
{ {
fn tag(&self) -> any::TypeId {
any::TypeId::of::<()>()
}
fn state(&self) -> Box<dyn Any> {
Box::new(())
}
fn children_state(&self) -> Vec<Tree> {
Vec::new()
}
fn width(&self) -> Length { fn width(&self) -> Length {
<Self as iced_native::Widget<Message, Renderer>>::width(self) <Self as iced_native::Widget<Message, Renderer>>::width(self)
} }

View file

@ -3,7 +3,7 @@ use crate::widget::Element;
use std::any::{self, Any}; use std::any::{self, Any};
pub struct Tree { pub struct Tree {
pub tag: any::TypeId, pub tag: Tag,
pub state: State, pub state: State,
pub children: Vec<Tree>, pub children: Vec<Tree>,
} }
@ -11,8 +11,8 @@ pub struct Tree {
impl Tree { impl Tree {
pub fn empty() -> Self { pub fn empty() -> Self {
Self { Self {
tag: any::TypeId::of::<()>(), tag: Tag::stateless(),
state: State(Box::new(())), state: State::None,
children: Vec::new(), children: Vec::new(),
} }
} }
@ -22,8 +22,8 @@ impl Tree {
) -> Self { ) -> Self {
Self { Self {
tag: element.as_widget().tag(), tag: element.as_widget().tag(),
state: State(element.as_widget().state()), state: element.as_widget().state(),
children: element.as_widget().children_state(), children: element.as_widget().children(),
} }
} }
@ -60,20 +60,56 @@ impl Tree {
} }
} }
pub struct State(Box<dyn Any>); #[derive(Debug, Clone, Copy, PartialOrd, Ord, PartialEq, Eq, Hash)]
pub struct Tag(any::TypeId);
impl Tag {
pub fn of<T>() -> Self
where
T: 'static,
{
Self(any::TypeId::of::<T>())
}
pub fn stateless() -> Self {
Self::of::<()>()
}
}
pub enum State {
None,
Some(Box<dyn Any>),
}
impl State { impl State {
pub fn new<T>(state: T) -> Self
where
T: 'static,
{
State::Some(Box::new(state))
}
pub fn downcast_ref<T>(&self) -> &T pub fn downcast_ref<T>(&self) -> &T
where where
T: 'static, T: 'static,
{ {
self.0.downcast_ref().expect("Downcast widget state") match self {
State::None => panic!("Downcast on stateless state"),
State::Some(state) => {
state.downcast_ref().expect("Downcast widget state")
}
}
} }
pub fn downcast_mut<T>(&mut self) -> &mut T pub fn downcast_mut<T>(&mut self) -> &mut T
where where
T: 'static, T: 'static,
{ {
self.0.downcast_mut().expect("Downcast widget state") match self {
State::None => panic!("Downcast on stateless state"),
State::Some(state) => {
state.downcast_mut().expect("Downcast widget state")
}
}
} }
} }