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:
Demonthos authored and GitHub committed 2022-07-07 00:50:22 -04:00
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
}