Allow Multiple dependencies for states in the RealDom (native core) (#412)
* WIP multable deps * WIP: refactor and genralize state macro * add traversable trait * update tui to use elementid to index dom
This commit is contained in:
1 parent
c271fc132e
commit
4a5ae758ee
19 files changed
+990
-1103
No files matched your search
@@ -0,0 +1,256 @@
|
||||
use anymap::AnyMap;
|
||||
use dioxus::core as dioxus_core;
|
||||
use dioxus::prelude::*;
|
||||
use dioxus_native_core::node_ref::*;
|
||||
use dioxus_native_core::real_dom::*;
|
||||
use dioxus_native_core::state::{ChildDepState, NodeDepState, ParentDepState, State};
|
||||
use dioxus_native_core_macro::State;
|
||||
|
||||
macro_rules! dep {
|
||||
( child( $name:ty, $dep:ty ) ) => {
|
||||
impl ChildDepState for $name {
|
||||
type Ctx = ();
|
||||
type DepState = $dep;
|
||||
const NODE_MASK: NodeMask = NodeMask::ALL;
|
||||
fn reduce<'a>(
|
||||
&mut self,
|
||||
_: NodeView,
|
||||
_: impl Iterator<Item = &'a Self::DepState>,
|
||||
_: &Self::Ctx,
|
||||
) -> bool
|
||||
where
|
||||
Self::DepState: 'a,
|
||||
{
|
||||
self.0 += 1;
|
||||
true
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
( parent( $name:ty, $dep:ty ) ) => {
|
||||
impl ParentDepState for $name {
|
||||
type Ctx = ();
|
||||
type DepState = $dep;
|
||||
const NODE_MASK: NodeMask = NodeMask::ALL;
|
||||
fn reduce(
|
||||
&mut self,
|
||||
_: NodeView,
|
||||
_: Option<&Self::DepState>,
|
||||
_: &Self::Ctx,
|
||||
) -> bool {
|
||||
self.0 += 1;
|
||||
true
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
( node( $name:ty, ($($l:lifetime),*), $dep:ty ) ) => {
|
||||
impl<$($l),*> NodeDepState<$dep> for $name {
|
||||
type Ctx = ();
|
||||
const NODE_MASK: NodeMask = NodeMask::ALL;
|
||||
fn reduce(
|
||||
&mut self,
|
||||
_: NodeView,
|
||||
_: $dep,
|
||||
_: &Self::Ctx,
|
||||
) -> bool {
|
||||
self.0 += 1;
|
||||
true
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! test_state{
|
||||
( $s:ty, child: ( $( $child:ident ),* ), node: ( $( $node:ident ),* ), parent: ( $( $parent:ident ),* ) ) => {
|
||||
#[test]
|
||||
fn state_reduce_initally_called_minimally() {
|
||||
#[allow(non_snake_case)]
|
||||
fn Base(cx: Scope) -> Element {
|
||||
rsx!(cx, div {
|
||||
div{
|
||||
div{
|
||||
p{}
|
||||
}
|
||||
p{
|
||||
"hello"
|
||||
}
|
||||
div{
|
||||
h1{}
|
||||
}
|
||||
p{
|
||||
"world"
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
let vdom = VirtualDom::new(Base);
|
||||
|
||||
let mutations = vdom.create_vnodes(rsx! {
|
||||
div {
|
||||
div{
|
||||
div{
|
||||
p{}
|
||||
}
|
||||
p{
|
||||
"hello"
|
||||
}
|
||||
div{
|
||||
h1{}
|
||||
}
|
||||
p{
|
||||
"world"
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
let mut dom: RealDom<$s> = RealDom::new();
|
||||
|
||||
let nodes_updated = dom.apply_mutations(vec![mutations]);
|
||||
let _to_rerender = dom.update_state(&vdom, nodes_updated, AnyMap::new());
|
||||
|
||||
dom.traverse_depth_first(|n| {
|
||||
$(
|
||||
assert_eq!(n.state.$child.0, 1);
|
||||
)*
|
||||
$(
|
||||
assert_eq!(n.state.$node.0, 1);
|
||||
)*
|
||||
$(
|
||||
assert_eq!(n.state.$parent.0, 1);
|
||||
)*
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mod node_depends_on_child_and_parent {
|
||||
use super::*;
|
||||
#[derive(Debug, Clone, Default, PartialEq)]
|
||||
struct Node(i32);
|
||||
dep!(node(Node, ('a, 'b), (&'a Child, &'b Parent)));
|
||||
|
||||
#[derive(Debug, Clone, Default, PartialEq)]
|
||||
struct Child(i32);
|
||||
dep!(child(Child, Child));
|
||||
|
||||
#[derive(Debug, Clone, Default, PartialEq)]
|
||||
struct Parent(i32);
|
||||
dep!(parent(Parent, Parent));
|
||||
|
||||
#[derive(Debug, Clone, Default, State)]
|
||||
struct StateTester {
|
||||
#[node_dep_state((child, parent))]
|
||||
node: Node,
|
||||
#[child_dep_state(child)]
|
||||
child: Child,
|
||||
#[parent_dep_state(parent)]
|
||||
parent: Parent,
|
||||
}
|
||||
|
||||
test_state!(StateTester, child: (child), node: (node), parent: (parent));
|
||||
}
|
||||
|
||||
mod child_depends_on_node_that_depends_on_parent {
|
||||
use super::*;
|
||||
#[derive(Debug, Clone, Default, PartialEq)]
|
||||
struct Node(i32);
|
||||
dep!(node(Node, ('a), (&'a Parent,)));
|
||||
|
||||
#[derive(Debug, Clone, Default, PartialEq)]
|
||||
struct Child(i32);
|
||||
dep!(child(Child, Node));
|
||||
|
||||
#[derive(Debug, Clone, Default, PartialEq)]
|
||||
struct Parent(i32);
|
||||
dep!(parent(Parent, Parent));
|
||||
|
||||
#[derive(Debug, Clone, Default, State)]
|
||||
struct StateTester {
|
||||
#[node_dep_state(parent)]
|
||||
node: Node,
|
||||
#[child_dep_state(node)]
|
||||
child: Child,
|
||||
#[parent_dep_state(parent)]
|
||||
parent: Parent,
|
||||
}
|
||||
|
||||
test_state!(StateTester, child: (child), node: (node), parent: (parent));
|
||||
}
|
||||
|
||||
mod parent_depends_on_node_that_depends_on_child {
|
||||
use super::*;
|
||||
#[derive(Debug, Clone, Default, PartialEq)]
|
||||
struct Node(i32);
|
||||
dep!(node(Node, ('a), (&'a Child,)));
|
||||
|
||||
#[derive(Debug, Clone, Default, PartialEq)]
|
||||
struct Child(i32);
|
||||
dep!(child(Child, Child));
|
||||
|
||||
#[derive(Debug, Clone, Default, PartialEq)]
|
||||
struct Parent(i32);
|
||||
dep!(parent(Parent, Node));
|
||||
|
||||
#[derive(Debug, Clone, Default, State)]
|
||||
struct StateTester {
|
||||
#[node_dep_state(child)]
|
||||
node: Node,
|
||||
#[child_dep_state(child)]
|
||||
child: Child,
|
||||
#[parent_dep_state(node)]
|
||||
parent: Parent,
|
||||
}
|
||||
|
||||
test_state!(StateTester, child: (child), node: (node), parent: (parent));
|
||||
}
|
||||
|
||||
mod node_depends_on_other_node_state {
|
||||
use super::*;
|
||||
#[derive(Debug, Clone, Default, PartialEq)]
|
||||
struct Node1(i32);
|
||||
dep!(node(Node1, ('a), (&'a Node2,)));
|
||||
|
||||
#[derive(Debug, Clone, Default, PartialEq)]
|
||||
struct Node2(i32);
|
||||
dep!(node(Node2, (), ()));
|
||||
|
||||
#[derive(Debug, Clone, Default, State)]
|
||||
struct StateTester {
|
||||
#[node_dep_state((node2))]
|
||||
node1: Node1,
|
||||
#[node_dep_state()]
|
||||
node2: Node2,
|
||||
}
|
||||
|
||||
test_state!(StateTester, child: (), node: (node1, node2), parent: ());
|
||||
}
|
||||
|
||||
mod node_child_and_parent_state_depends_on_self {
|
||||
use super::*;
|
||||
#[derive(Debug, Clone, Default, PartialEq)]
|
||||
struct Node(i32);
|
||||
dep!(node(Node, (), ()));
|
||||
|
||||
#[derive(Debug, Clone, Default, PartialEq)]
|
||||
struct Child(i32);
|
||||
dep!(child(Child, Child));
|
||||
|
||||
#[derive(Debug, Clone, Default, PartialEq)]
|
||||
struct Parent(i32);
|
||||
dep!(parent(Parent, Parent));
|
||||
|
||||
#[derive(Debug, Clone, Default, State)]
|
||||
struct StateTester {
|
||||
#[node_dep_state()]
|
||||
node: Node,
|
||||
#[child_dep_state(child)]
|
||||
child: Child,
|
||||
#[parent_dep_state(parent)]
|
||||
parent: Parent,
|
||||
}
|
||||
|
||||
test_state!(StateTester, child: (child), node: (node), parent: (parent));
|
||||
}
|
||||
@@ -51,8 +51,8 @@ fn remove_node() {
|
||||
|
||||
assert_eq!(dom.size(), 2);
|
||||
assert!(&dom.contains_node(&VNode::Element(&root_div)));
|
||||
assert_eq!(dom[1].height, 1);
|
||||
assert_eq!(dom[2].height, 2);
|
||||
assert_eq!(dom[ElementId(1)].height, 1);
|
||||
assert_eq!(dom[ElementId(2)].height, 2);
|
||||
|
||||
let vdom = VirtualDom::new(Base);
|
||||
let mutations = vdom.diff_lazynodes(
|
||||
@@ -80,7 +80,7 @@ fn remove_node() {
|
||||
|
||||
assert_eq!(dom.size(), 1);
|
||||
assert!(&dom.contains_node(&VNode::Element(&new_root_div)));
|
||||
assert_eq!(dom[1].height, 1);
|
||||
assert_eq!(dom[ElementId(1)].height, 1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -113,7 +113,7 @@ fn add_node() {
|
||||
|
||||
assert_eq!(dom.size(), 1);
|
||||
assert!(&dom.contains_node(&VNode::Element(&root_div)));
|
||||
assert_eq!(dom[1].height, 1);
|
||||
assert_eq!(dom[ElementId(1)].height, 1);
|
||||
|
||||
let vdom = VirtualDom::new(Base);
|
||||
let mutations = vdom.diff_lazynodes(
|
||||
@@ -152,6 +152,6 @@ fn add_node() {
|
||||
|
||||
assert_eq!(dom.size(), 2);
|
||||
assert!(&dom.contains_node(&VNode::Element(&new_root_div)));
|
||||
assert_eq!(dom[1].height, 1);
|
||||
assert_eq!(dom[2].height, 2);
|
||||
assert_eq!(dom[ElementId(1)].height, 1);
|
||||
assert_eq!(dom[ElementId(2)].height, 2);
|
||||
}
|
||||
@@ -40,7 +40,7 @@ fn initial_build_simple() {
|
||||
};
|
||||
assert_eq!(dom.size(), 1);
|
||||
assert!(&dom.contains_node(&VNode::Element(&root_div)));
|
||||
assert_eq!(dom[1].height, 1);
|
||||
assert_eq!(dom[ElementId(1)].height, 1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -119,10 +119,10 @@ fn initial_build_with_children() {
|
||||
};
|
||||
assert_eq!(dom.size(), 6);
|
||||
assert!(&dom.contains_node(&VNode::Element(&root_div)));
|
||||
assert_eq!(dom[1].height, 1);
|
||||
assert_eq!(dom[2].height, 2);
|
||||
assert_eq!(dom[3].height, 3);
|
||||
assert_eq!(dom[4].height, 3);
|
||||
assert_eq!(dom[5].height, 4);
|
||||
assert_eq!(dom[6].height, 3);
|
||||
assert_eq!(dom[ElementId(1)].height, 1);
|
||||
assert_eq!(dom[ElementId(2)].height, 2);
|
||||
assert_eq!(dom[ElementId(3)].height, 3);
|
||||
assert_eq!(dom[ElementId(4)].height, 3);
|
||||
assert_eq!(dom[ElementId(5)].height, 4);
|
||||
assert_eq!(dom[ElementId(6)].height, 3);
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
use anymap::AnyMap;
|
||||
use dioxus::core as dioxus_core;
|
||||
use dioxus::core::ElementId;
|
||||
use dioxus::core::{AttributeValue, DomEdit, Mutations};
|
||||
use dioxus::prelude::*;
|
||||
use dioxus_native_core::node_ref::*;
|
||||
@@ -49,13 +50,14 @@ impl ChildDepState for ChildDepCallCounter {
|
||||
const NODE_MASK: NodeMask = NodeMask::ALL;
|
||||
fn reduce<'a>(
|
||||
&mut self,
|
||||
_: NodeView,
|
||||
node: NodeView,
|
||||
_: impl Iterator<Item = &'a Self::DepState>,
|
||||
_: &Self::Ctx,
|
||||
) -> bool
|
||||
where
|
||||
Self::DepState: 'a,
|
||||
{
|
||||
println!("{self:?} {:?}: {} {:?}", node.tag(), node.id(), node.text());
|
||||
self.0 += 1;
|
||||
true
|
||||
}
|
||||
@@ -80,11 +82,10 @@ impl ParentDepState for ParentDepCallCounter {
|
||||
|
||||
#[derive(Debug, Clone, Default)]
|
||||
struct NodeDepCallCounter(u32);
|
||||
impl NodeDepState for NodeDepCallCounter {
|
||||
impl NodeDepState<()> for NodeDepCallCounter {
|
||||
type Ctx = ();
|
||||
type DepState = ();
|
||||
const NODE_MASK: NodeMask = NodeMask::ALL;
|
||||
fn reduce(&mut self, _node: NodeView, _sibling: &Self::DepState, _ctx: &Self::Ctx) -> bool {
|
||||
fn reduce(&mut self, _node: NodeView, _sibling: (), _ctx: &Self::Ctx) -> bool {
|
||||
self.0 += 1;
|
||||
true
|
||||
}
|
||||
@@ -133,11 +134,10 @@ impl ParentDepState for PushedDownStateTester {
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Default)]
|
||||
struct NodeStateTester(Option<String>, Vec<(String, String)>);
|
||||
impl NodeDepState for NodeStateTester {
|
||||
impl NodeDepState<()> for NodeStateTester {
|
||||
type Ctx = u32;
|
||||
type DepState = ();
|
||||
const NODE_MASK: NodeMask = NodeMask::new_with_attrs(AttributeMask::All).with_tag();
|
||||
fn reduce(&mut self, node: NodeView, _sibling: &Self::DepState, ctx: &Self::Ctx) -> bool {
|
||||
fn reduce(&mut self, node: NodeView, _sibling: (), ctx: &Self::Ctx) -> bool {
|
||||
assert_eq!(*ctx, 42);
|
||||
*self = NodeStateTester(
|
||||
node.tag().map(|s| s.to_string()),
|
||||
@@ -187,7 +187,7 @@ fn state_initial() {
|
||||
ctx.insert(42u32);
|
||||
let _to_rerender = dom.update_state(&vdom, nodes_updated, ctx);
|
||||
|
||||
let root_div = &dom[1];
|
||||
let root_div = &dom[ElementId(1)];
|
||||
assert_eq!(root_div.state.bubbled.0, Some("div".to_string()));
|
||||
assert_eq!(
|
||||
root_div.state.bubbled.1,
|
||||
@@ -204,7 +204,7 @@ fn state_initial() {
|
||||
assert_eq!(root_div.state.node.0, Some("div".to_string()));
|
||||
assert_eq!(root_div.state.node.1, vec![]);
|
||||
|
||||
let child_p = &dom[2];
|
||||
let child_p = &dom[ElementId(2)];
|
||||
assert_eq!(child_p.state.bubbled.0, Some("p".to_string()));
|
||||
assert_eq!(child_p.state.bubbled.1, Vec::new());
|
||||
assert_eq!(child_p.state.pushed.0, Some("p".to_string()));
|
||||
@@ -221,7 +221,7 @@ fn state_initial() {
|
||||
vec![("color".to_string(), "red".to_string())]
|
||||
);
|
||||
|
||||
let child_h1 = &dom[3];
|
||||
let child_h1 = &dom[ElementId(3)];
|
||||
assert_eq!(child_h1.state.bubbled.0, Some("h1".to_string()));
|
||||
assert_eq!(child_h1.state.bubbled.1, Vec::new());
|
||||
assert_eq!(child_h1.state.pushed.0, Some("h1".to_string()));
|
||||
@@ -236,64 +236,6 @@ fn state_initial() {
|
||||
assert_eq!(child_h1.state.node.1, vec![]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn state_reduce_initally_called_minimally() {
|
||||
#[allow(non_snake_case)]
|
||||
fn Base(cx: Scope) -> Element {
|
||||
rsx!(cx, div {
|
||||
div{
|
||||
div{
|
||||
p{}
|
||||
}
|
||||
p{
|
||||
"hello"
|
||||
}
|
||||
div{
|
||||
h1{}
|
||||
}
|
||||
p{
|
||||
"world"
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
let vdom = VirtualDom::new(Base);
|
||||
|
||||
let mutations = vdom.create_vnodes(rsx! {
|
||||
div {
|
||||
div{
|
||||
div{
|
||||
p{}
|
||||
}
|
||||
p{
|
||||
"hello"
|
||||
}
|
||||
div{
|
||||
h1{}
|
||||
}
|
||||
p{
|
||||
"world"
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
let mut dom: RealDom<CallCounterState> = RealDom::new();
|
||||
|
||||
let nodes_updated = dom.apply_mutations(vec![mutations]);
|
||||
let _to_rerender = dom.update_state(&vdom, nodes_updated, AnyMap::new());
|
||||
|
||||
dom.traverse_depth_first(|n| {
|
||||
assert_eq!(n.state.part1.child_counter.0, 1);
|
||||
assert_eq!(n.state.child_counter.0, 1);
|
||||
assert_eq!(n.state.part2.parent_counter.0, 1);
|
||||
assert_eq!(n.state.parent_counter.0, 1);
|
||||
assert_eq!(n.state.part3.node_counter.0, 1);
|
||||
assert_eq!(n.state.node_counter.0, 1);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn state_reduce_parent_called_minimally_on_update() {
|
||||
#[allow(non_snake_case)]
|
||||
@@ -446,11 +388,15 @@ struct UnorderedDependanciesState {
|
||||
|
||||
#[derive(Debug, Clone, Default, PartialEq)]
|
||||
struct ADepCallCounter(usize, BDepCallCounter);
|
||||
impl NodeDepState for ADepCallCounter {
|
||||
impl<'a> NodeDepState<(&'a BDepCallCounter,)> for ADepCallCounter {
|
||||
type Ctx = ();
|
||||
type DepState = BDepCallCounter;
|
||||
const NODE_MASK: NodeMask = NodeMask::NONE;
|
||||
fn reduce(&mut self, _node: NodeView, sibling: &Self::DepState, _ctx: &Self::Ctx) -> bool {
|
||||
fn reduce(
|
||||
&mut self,
|
||||
_node: NodeView,
|
||||
(sibling,): (&'a BDepCallCounter,),
|
||||
_ctx: &Self::Ctx,
|
||||
) -> bool {
|
||||
self.0 += 1;
|
||||
self.1 = sibling.clone();
|
||||
true
|
||||
@@ -459,11 +405,15 @@ impl NodeDepState for ADepCallCounter {
|
||||
|
||||
#[derive(Debug, Clone, Default, PartialEq)]
|
||||
struct BDepCallCounter(usize, CDepCallCounter);
|
||||
impl NodeDepState for BDepCallCounter {
|
||||
impl<'a> NodeDepState<(&'a CDepCallCounter,)> for BDepCallCounter {
|
||||
type Ctx = ();
|
||||
type DepState = CDepCallCounter;
|
||||
const NODE_MASK: NodeMask = NodeMask::NONE;
|
||||
fn reduce(&mut self, _node: NodeView, sibling: &Self::DepState, _ctx: &Self::Ctx) -> bool {
|
||||
fn reduce(
|
||||
&mut self,
|
||||
_node: NodeView,
|
||||
(sibling,): (&'a CDepCallCounter,),
|
||||
_ctx: &Self::Ctx,
|
||||
) -> bool {
|
||||
self.0 += 1;
|
||||
self.1 = sibling.clone();
|
||||
true
|
||||
@@ -472,11 +422,10 @@ impl NodeDepState for BDepCallCounter {
|
||||
|
||||
#[derive(Debug, Clone, Default, PartialEq)]
|
||||
struct CDepCallCounter(usize);
|
||||
impl NodeDepState for CDepCallCounter {
|
||||
impl NodeDepState<()> for CDepCallCounter {
|
||||
type Ctx = ();
|
||||
type DepState = ();
|
||||
const NODE_MASK: NodeMask = NodeMask::ALL;
|
||||
fn reduce(&mut self, _node: NodeView, _sibling: &Self::DepState, _ctx: &Self::Ctx) -> bool {
|
||||
fn reduce(&mut self, _node: NodeView, _sibling: (), _ctx: &Self::Ctx) -> bool {
|
||||
self.0 += 1;
|
||||
true
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user