1
0
Evan Almloff 2 жил өмнө
parent
commit
ad33f2ce96

+ 6 - 3
packages/native-core-macro/src/lib.rs

@@ -189,7 +189,7 @@ impl Struct {
         let members = fields
             .iter()
             .enumerate()
-            .filter_map(|(i, f)| Member::parse(f, i as u64))
+            .filter_map(|(i, f)| Member::parse(&name, f, i as u64))
             .collect();
         Self { name, members }
     }
@@ -296,12 +296,15 @@ struct Member {
 }
 
 impl Member {
-    fn parse(field: &Field, id: u64) -> Option<Self> {
+    fn parse(parent: &Ident, field: &Field, id: u64) -> Option<Self> {
         Some(Self {
             id,
             ty: field.ty.clone(),
             unit_type: Ident::new(
-                ("_Unit".to_string() + field.ty.to_token_stream().to_string().as_str()).as_str(),
+                ("_Unit".to_string()
+                    + parent.to_token_stream().to_string().as_str()
+                    + field.ty.to_token_stream().to_string().as_str())
+                .as_str(),
                 Span::call_site(),
             )
             .into(),

+ 146 - 161
packages/native-core-macro/tests/called_minimally_on_build.rs

@@ -71,48 +71,33 @@ macro_rules! test_state{
         fn state_reduce_initally_called_minimally() {
             #[allow(non_snake_case)]
             fn Base(cx: Scope) -> Element {
-                render!(div {
-                    div{
+                render!{
+                    div {
                         div{
-                            p{}
-                        }
-                        p{
-                            "hello"
-                        }
-                        div{
-                            h1{}
-                        }
-                        p{
-                            "world"
+                            div{
+                                p{}
+                            }
+                            p{
+                                "hello"
+                            }
+                            div{
+                                h1{}
+                            }
+                            p{
+                                "world"
+                            }
                         }
                     }
-                })
+                }
             }
 
-            let vdom = VirtualDom::new(Base);
+            let mut vdom = VirtualDom::new(Base);
 
-            let mutations = vdom.create_vnodes(rsx! {
-                div {
-                    div{
-                        div{
-                            p{}
-                        }
-                        p{
-                            "hello"
-                        }
-                        div{
-                            h1{}
-                        }
-                        p{
-                            "world"
-                        }
-                    }
-                }
-            });
+            let mutations = vdom.rebuild();
 
             let mut dom: RealDom<$s> = RealDom::new();
 
-            let nodes_updated = dom.apply_mutations(vec![mutations]);
+            let (nodes_updated, _) = dom.apply_mutations(mutations);
             let _to_rerender = dom.update_state(nodes_updated, SendAnyMap::new());
 
             dom.traverse_depth_first(|n| {
@@ -130,131 +115,131 @@ macro_rules! test_state{
     }
 }
 
-// mod node_depends_on_child_and_parent {
-//     use super::*;
-//     #[derive(Debug, Clone, Default, PartialEq)]
-//     struct Node(i32);
-//     dep!(node(Node, (Child, 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, (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, (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, (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));
-// }
+mod node_depends_on_child_and_parent {
+    use super::*;
+    #[derive(Debug, Clone, Default, PartialEq)]
+    struct Node(i32);
+    dep!(node(Node, (Child, 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, (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, (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, (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));
+}

+ 0 - 79
packages/native-core-macro/tests/change_nodes.rs

@@ -1,79 +0,0 @@
-// use dioxus::core::ElementId;
-// use dioxus::prelude::*;
-// use dioxus_native_core::real_dom::RealDom;
-// use dioxus_native_core::state::State;
-// use dioxus_native_core::tree::*;
-// use dioxus_native_core::NodeId;
-// use dioxus_native_core_macro::State;
-
-// #[derive(State, Default, Clone)]
-// struct Empty {}
-
-// #[test]
-// fn remove_node() {
-//     #[allow(non_snake_case)]
-//     fn Base(cx: Scope) -> Element {
-//         render!(div {})
-//     }
-
-//     let vdom = VirtualDom::new(Base);
-
-//     let mut dom: RealDom<Empty> = RealDom::new();
-//     let (create, edit) = vdom.diff_lazynodes(
-//         rsx! {
-//             div{
-//                 div{}
-//             }
-//         },
-//         rsx! {
-//             div{}
-//         },
-//     );
-
-//     println!("create: {:#?}", create);
-//     println!("edit: {:#?}", edit);
-
-//     let _to_update = dom.apply_mutations(vec![create]);
-
-//     assert_eq!(dom.tree.height(NodeId(0)), Some(0));
-//     assert_eq!(dom.tree.height(NodeId(1)), Some(1));
-
-//     dom.apply_mutations(vec![edit]);
-
-//     assert_eq!(dom.size(), 3);
-//     assert_eq!(dom.tree.height(NodeId(0)), Some(0));
-// }
-
-// #[test]
-// fn add_node() {
-//     #[allow(non_snake_case)]
-//     fn Base(cx: Scope) -> Element {
-//         render!(div {})
-//     }
-
-//     let vdom = VirtualDom::new(Base);
-
-//     let (create, update) = vdom.diff_lazynodes(
-//         rsx! {
-//             div{}
-//         },
-//         rsx! {
-//             div{
-//                 p{}
-//             }
-//         },
-//     );
-
-//     let mut dom: RealDom<Empty> = RealDom::new();
-
-//     let _to_update = dom.apply_mutations(vec![create]);
-
-//     assert_eq!(dom.size(), 2);
-//     assert_eq!(dom.tree.height(NodeId(2)), Some(1));
-
-//     dom.apply_mutations(vec![update]);
-
-//     assert_eq!(dom.size(), 3);
-//     assert_eq!(dom.tree.height(NodeId(3)), Some(0));
-//     assert_eq!(dom.tree.height(NodeId(0)), Some(1));
-// }

+ 0 - 63
packages/native-core-macro/tests/initial_build.rs

@@ -1,63 +0,0 @@
-// use dioxus::core::ElementId;
-// use dioxus::prelude::*;
-// use dioxus_native_core::real_dom::RealDom;
-// use dioxus_native_core::state::State;
-// use dioxus_native_core::RealNodeId;
-// use dioxus_native_core_macro::State;
-
-// #[derive(Default, Clone, State)]
-// struct Empty {}
-
-// #[test]
-// fn initial_build_simple() {
-//     #[allow(non_snake_case)]
-//     fn Base(cx: Scope) -> Element {
-//         render!(div {})
-//     }
-
-//     let vdom = VirtualDom::new(Base);
-
-//     let mutations = vdom.create_vnodes(rsx! {
-//         div{}
-//     });
-
-//     let mut dom: RealDom<Empty> = RealDom::new();
-
-//     let _to_update = dom.apply_mutations(vec![mutations]);
-
-//     assert_eq!(dom.size(), 2);
-//     assert_eq!(dom[RealNodeId::ElementId(ElementId(2))].node_data.height, 1);
-// }
-
-// #[test]
-// fn initial_build_with_children() {
-//     #[allow(non_snake_case)]
-//     fn Base(cx: Scope) -> Element {
-//         render!(div {})
-//     }
-
-//     let vdom = VirtualDom::new(Base);
-
-//     let mutations = vdom.create_vnodes(rsx! {
-//         div{
-//             div{
-//                 "hello"
-//                 p{
-//                     "world"
-//                 }
-//                 "hello world"
-//             }
-//         }
-//     });
-
-//     let mut dom: RealDom<Empty> = RealDom::new();
-
-//     let _to_update = dom.apply_mutations(vec![mutations]);
-//     assert_eq!(dom.size(), 2);
-//     assert_eq!(dom[RealNodeId::ElementId(ElementId(2))].node_data.height, 1);
-//     assert_eq!(dom[RealNodeId::UnaccessableId(6)].node_data.height, 2);
-//     assert_eq!(dom[RealNodeId::UnaccessableId(5)].node_data.height, 3);
-//     assert_eq!(dom[RealNodeId::UnaccessableId(8)].node_data.height, 3);
-//     assert_eq!(dom[RealNodeId::UnaccessableId(10)].node_data.height, 3);
-//     assert_eq!(dom[RealNodeId::UnaccessableId(9)].node_data.height, 4);
-// }

+ 275 - 310
packages/native-core-macro/tests/persistent_iterator.rs

@@ -1,333 +1,298 @@
-// use dioxus::core_macro::rsx_without_templates;
-// use dioxus::prelude::*;
-// use dioxus_native_core::{
-//     real_dom::{NodeType, RealDom},
-//     state::State,
-//     utils::PersistantElementIter,
-// };
-// use dioxus_native_core_macro::State;
+use dioxus::prelude::*;
+use dioxus_native_core::{
+    real_dom::{ RealDom},
+    node::NodeType,
+    state::State,
+    utils::PersistantElementIter,
+};
+use dioxus_native_core_macro::State;
 
-// #[derive(State, Default, Clone)]
-// struct Empty {}
+#[derive(State, Default, Clone, Debug)]
+struct Empty {}
 
-// #[test]
-// #[allow(unused_variables)]
-// fn traverse() {
-//     #[allow(non_snake_case)]
-//     fn Base(cx: Scope) -> Element {
-//         render!(div {})
-//     }
-//     let vdom = VirtualDom::new(Base);
-//     let mutations = vdom.create_vnodes(rsx! {
-//         div{
-//             div{
-//                 "hello"
-//                 p{
-//                     "world"
-//                 }
-//                 "hello world"
-//             }
-//         }
-//     });
+#[test]
+#[allow(unused_variables)]
+fn traverse() {
+    #[allow(non_snake_case)]
+    fn Base(cx: Scope) -> Element {
+        render!(
+            div{
+                div{
+                    "hello"
+                    p{
+                        "world"
+                    }
+                    "hello world"
+                }
+            }
+        )
+    }
 
-//     let mut rdom: RealDom<Empty> = RealDom::new();
+    let mut vdom = VirtualDom::new(Base);
+    let mutations = vdom.rebuild();
 
-//     let _to_update = rdom.apply_mutations(vec![mutations]);
+    let mut rdom: RealDom<Empty> = RealDom::new();
 
-//     let mut iter = PersistantElementIter::new();
-//     let div_tag = "div".to_string();
-//     assert!(matches!(
-//         &rdom[iter.next(&rdom).id()].node_data.node_type,
-//         NodeType::Element { tag: div_tag, .. }
-//     ));
-//     assert!(matches!(
-//         &rdom[iter.next(&rdom).id()].node_data.node_type,
-//         NodeType::Element { tag: div_tag, .. }
-//     ));
-//     let text1 = "hello".to_string();
-//     assert!(matches!(
-//         &rdom[iter.next(&rdom).id()].node_data.node_type,
-//         NodeType::Text { text: text1, .. }
-//     ));
-//     let p_tag = "p".to_string();
-//     assert!(matches!(
-//         &rdom[iter.next(&rdom).id()].node_data.node_type,
-//         NodeType::Element { tag: p_tag, .. }
-//     ));
-//     let text2 = "world".to_string();
-//     assert!(matches!(
-//         &rdom[iter.next(&rdom).id()].node_data.node_type,
-//         NodeType::Text { text: text2, .. }
-//     ));
-//     let text3 = "hello world".to_string();
-//     assert!(matches!(
-//         &rdom[iter.next(&rdom).id()].node_data.node_type,
-//         NodeType::Text { text: text3, .. }
-//     ));
-//     assert!(matches!(
-//         &rdom[iter.next(&rdom).id()].node_data.node_type,
-//         NodeType::Element { tag: div_tag, .. }
-//     ));
+    let _to_update = rdom.apply_mutations(mutations);
 
-//     assert!(matches!(
-//         &rdom[iter.prev(&rdom).id()].node_data.node_type,
-//         NodeType::Text { text: text3, .. }
-//     ));
-//     assert!(matches!(
-//         &rdom[iter.prev(&rdom).id()].node_data.node_type,
-//         NodeType::Text { text: text2, .. }
-//     ));
-//     assert!(matches!(
-//         &rdom[iter.prev(&rdom).id()].node_data.node_type,
-//         NodeType::Element { tag: p_tag, .. }
-//     ));
-//     assert!(matches!(
-//         &rdom[iter.prev(&rdom).id()].node_data.node_type,
-//         NodeType::Text { text: text1, .. }
-//     ));
-//     assert!(matches!(
-//         &rdom[iter.prev(&rdom).id()].node_data.node_type,
-//         NodeType::Element { tag: div_tag, .. }
-//     ));
-//     assert!(matches!(
-//         &rdom[iter.prev(&rdom).id()].node_data.node_type,
-//         NodeType::Element { tag: div_tag, .. }
-//     ));
-//     assert!(matches!(
-//         &rdom[iter.prev(&rdom).id()].node_data.node_type,
-//         NodeType::Element { tag: div_tag, .. }
-//     ));
-//     assert!(matches!(
-//         &rdom[iter.prev(&rdom).id()].node_data.node_type,
-//         NodeType::Text { text: text3, .. }
-//     ));
-// }
+    let mut iter = PersistantElementIter::new();
+    let div_tag = "div".to_string();
+    assert!(matches!(
+        &rdom[iter.next(&rdom).id()].node_data.node_type,
+        NodeType::Element { tag: div_tag, .. }
+    ));
+    assert!(matches!(
+        &rdom[iter.next(&rdom).id()].node_data.node_type,
+        NodeType::Element { tag: div_tag, .. }
+    ));
+    let text1 = "hello".to_string();
+    assert!(matches!(
+        &rdom[iter.next(&rdom).id()].node_data.node_type,
+        NodeType::Text { text: text1, .. }
+    ));
+    let p_tag = "p".to_string();
+    assert!(matches!(
+        &rdom[iter.next(&rdom).id()].node_data.node_type,
+        NodeType::Element { tag: p_tag, .. }
+    ));
+    let text2 = "world".to_string();
+    assert!(matches!(
+        &rdom[iter.next(&rdom).id()].node_data.node_type,
+        NodeType::Text { text: text2, .. }
+    ));
+    let text3 = "hello world".to_string();
+    assert!(matches!(
+        &rdom[iter.next(&rdom).id()].node_data.node_type,
+        NodeType::Text { text: text3, .. }
+    ));
+    assert!(matches!(
+        &rdom[iter.next(&rdom).id()].node_data.node_type,
+        NodeType::Element { tag: div_tag, .. }
+    ));
 
-// #[test]
-// #[allow(unused_variables)]
-// fn persist_removes() {
-//     #[allow(non_snake_case)]
-//     fn Base(cx: Scope) -> Element {
-//         render!(div {})
-//     }
-//     let vdom = VirtualDom::new(Base);
-//     let (build, update) = vdom.diff_lazynodes(
-//         rsx_without_templates! {
-//             div{
-//                 p{
-//                     key: "1",
-//                     "hello"
-//                 }
-//                 p{
-//                     key: "2",
-//                     "world"
-//                 }
-//                 p{
-//                     key: "3",
-//                     "hello world"
-//                 }
-//             }
-//         },
-//         rsx_without_templates! {
-//             div{
-//                 p{
-//                     key: "1",
-//                     "hello"
-//                 }
-//                 p{
-//                     key: "3",
-//                     "hello world"
-//                 }
-//             }
-//         },
-//     );
+    assert!(matches!(
+        &rdom[iter.prev(&rdom).id()].node_data.node_type,
+        NodeType::Text { text: text3, .. }
+    ));
+    assert!(matches!(
+        &rdom[iter.prev(&rdom).id()].node_data.node_type,
+        NodeType::Text { text: text2, .. }
+    ));
+    assert!(matches!(
+        &rdom[iter.prev(&rdom).id()].node_data.node_type,
+        NodeType::Element { tag: p_tag, .. }
+    ));
+    assert!(matches!(
+        &rdom[iter.prev(&rdom).id()].node_data.node_type,
+        NodeType::Text { text: text1, .. }
+    ));
+    assert!(matches!(
+        &rdom[iter.prev(&rdom).id()].node_data.node_type,
+        NodeType::Element { tag: div_tag, .. }
+    ));
+    assert!(matches!(
+        &rdom[iter.prev(&rdom).id()].node_data.node_type,
+        NodeType::Element { tag: div_tag, .. }
+    ));
+    assert!(matches!(
+        &rdom[iter.prev(&rdom).id()].node_data.node_type,
+        NodeType::Element { tag: div_tag, .. }
+    ));
+    assert!(matches!(
+        &rdom[iter.prev(&rdom).id()].node_data.node_type,
+        NodeType::Text { text: text3, .. }
+    ));
+}
 
-//     let mut rdom: RealDom<Empty> = RealDom::new();
+#[test]
+#[allow(unused_variables)]
+fn persist_removes() {
+    #[allow(non_snake_case)]
+    fn Base(cx: Scope) -> Element {
+        let children = match cx.generation()%2{
+            0=>3,
+            1=>2,
+            _ => unreachable!()
+        };
+        render!(
+            div{
+                (0..children).map(|i|{
+                    rsx!{
+                        p{
+                            key: "{i}",
+                            "{i}"
+                        }
+                    }
+                })
+            }
+        )
+    }
+    let mut vdom = VirtualDom::new(Base);
 
-//     let _to_update = rdom.apply_mutations(vec![build]);
+    let mut rdom: RealDom<Empty> = RealDom::new();
 
-//     // this will end on the node that is removed
-//     let mut iter1 = PersistantElementIter::new();
-//     // this will end on the after node that is removed
-//     let mut iter2 = PersistantElementIter::new();
-//     // div
-//     iter1.next(&rdom).id();
-//     iter2.next(&rdom).id();
-//     // p
-//     iter1.next(&rdom).id();
-//     iter2.next(&rdom).id();
-//     // "hello"
-//     iter1.next(&rdom).id();
-//     iter2.next(&rdom).id();
-//     // p
-//     iter1.next(&rdom).id();
-//     iter2.next(&rdom).id();
-//     // "world"
-//     iter1.next(&rdom).id();
-//     iter2.next(&rdom).id();
-//     // p
-//     iter2.next(&rdom).id();
-//     // "hello world"
-//     iter2.next(&rdom).id();
+    let build = vdom.rebuild();
+    let _to_update = rdom.apply_mutations(build);
 
-//     iter1.prune(&update, &rdom);
-//     iter2.prune(&update, &rdom);
-//     let _to_update = rdom.apply_mutations(vec![update]);
+    // this will end on the node that is removed
+    let mut iter1 = PersistantElementIter::new();
+    // this will end on the after node that is removed
+    let mut iter2 = PersistantElementIter::new();
+    // div
+    iter1.next(&rdom).id();
+    iter2.next(&rdom).id();
+    // p
+    iter1.next(&rdom).id();
+    iter2.next(&rdom).id();
+    // "1"
+    iter1.next(&rdom).id();
+    iter2.next(&rdom).id();
+    // p
+    iter1.next(&rdom).id();
+    iter2.next(&rdom).id();
+    // "2"
+    iter1.next(&rdom).id();
+    iter2.next(&rdom).id();
+    // p
+    iter2.next(&rdom).id();
+    // "3"
+    iter2.next(&rdom).id();
 
-//     let p_tag = "p".to_string();
-//     let idx = iter1.next(&rdom).id();
-//     assert!(matches!(
-//         &rdom[idx].node_data.node_type,
-//         NodeType::Element { tag: p_tag, .. }
-//     ));
-//     let text = "hello world".to_string();
-//     let idx = iter1.next(&rdom).id();
-//     assert!(matches!(
-//         &rdom[idx].node_data.node_type,
-//         NodeType::Text { text, .. }
-//     ));
-//     let div_tag = "div".to_string();
-//     let idx = iter2.next(&rdom).id();
-//     assert!(matches!(
-//         &rdom[idx].node_data.node_type,
-//         NodeType::Element { tag: div_tag, .. }
-//     ));
-// }
+    let update = vdom.rebuild();
+    iter1.prune(&update, &rdom);
+    iter2.prune(&update, &rdom);
+    let _to_update = rdom.apply_mutations(update);
 
-// #[test]
-// #[allow(unused_variables)]
-// fn persist_instertions_before() {
-//     #[allow(non_snake_case)]
-//     fn Base(cx: Scope) -> Element {
-//         render!(div {})
-//     }
-//     let vdom = VirtualDom::new(Base);
-//     let (build, update) = vdom.diff_lazynodes(
-//         rsx_without_templates! {
-//             div{
-//                 p{
-//                     key: "1",
-//                     "hello"
-//                 }
-//                 p{
-//                     key: "3",
-//                     "hello world"
-//                 }
-//             }
-//         },
-//         rsx_without_templates! {
-//             div{
-//                 p{
-//                     key: "1",
-//                     "hello"
-//                 }
-//                 p{
-//                     key: "2",
-//                     "world"
-//                 }
-//                 p{
-//                     key: "3",
-//                     "hello world"
-//                 }
-//             }
-//         },
-//     );
+    let p_tag = "1".to_string();
+    let idx = iter1.next(&rdom).id();
+    assert!(matches!(
+        &rdom[idx].node_data.node_type,
+        NodeType::Element { tag: p_tag, .. }
+    ));
+    let text = "2".to_string();
+    let idx = iter1.next(&rdom).id();
+    assert!(matches!(
+        &rdom[idx].node_data.node_type,
+        NodeType::Text { text, .. }
+    ));
+    let div_tag = "div".to_string();
+    let idx = iter2.next(&rdom).id();
+    assert!(matches!(
+        &rdom[idx].node_data.node_type,
+        NodeType::Element { tag: div_tag, .. }
+    ));
+}
 
-//     let mut rdom: RealDom<Empty> = RealDom::new();
+#[test]
+#[allow(unused_variables)]
+fn persist_instertions_before() {
+    #[allow(non_snake_case)]
+    fn Base(cx: Scope) -> Element {
+        let children = match cx.generation()%2{
+            0=>3,
+            1=>2,
+            _ => unreachable!()
+        };
+        render!(
+            div{
+                (0..children).map(|i|{
+                    rsx!{
+                        p{
+                            key: "{i}",
+                            "{i}"
+                        }
+                    }
+                })
+            }
+        )
+    }
+    let mut vdom = VirtualDom::new(Base);
 
-//     let _to_update = rdom.apply_mutations(vec![build]);
+    let mut rdom: RealDom<Empty> = RealDom::new();
 
-//     let mut iter = PersistantElementIter::new();
-//     // div
-//     iter.next(&rdom).id();
-//     // p
-//     iter.next(&rdom).id();
-//     // "hello"
-//     iter.next(&rdom).id();
-//     // p
-//     iter.next(&rdom).id();
-//     // "hello world"
-//     iter.next(&rdom).id();
+    let build = vdom.rebuild();
+    let _to_update = rdom.apply_mutations(build);
+    
+    let mut iter = PersistantElementIter::new();
+    // div
+    iter.next(&rdom).id();
+    // p
+    iter.next(&rdom).id();
+    // "1"
+    iter.next(&rdom).id();
+    // p
+    iter.next(&rdom).id();
+    // "2"
+    iter.next(&rdom).id();
+    
+    let update = vdom.rebuild();
+    iter.prune(&update, &rdom);
+    let _to_update = rdom.apply_mutations(update);
 
-//     iter.prune(&update, &rdom);
-//     let _to_update = rdom.apply_mutations(vec![update]);
+    let p_tag = "div".to_string();
+    let idx = iter.next(&rdom).id();
+    assert!(matches!(
+        &rdom[idx].node_data.node_type,
+        NodeType::Element { tag: p_tag, .. }
+    ));
+}
 
-//     let p_tag = "div".to_string();
-//     let idx = iter.next(&rdom).id();
-//     assert!(matches!(
-//         &rdom[idx].node_data.node_type,
-//         NodeType::Element { tag: p_tag, .. }
-//     ));
-// }
+#[test]
+#[allow(unused_variables)]
+fn persist_instertions_after() {
+    #[allow(non_snake_case)]
+    fn Base(cx: Scope) -> Element {
+        let children = match cx.generation()%2{
+            0=>3,
+            1=>2,
+            _ => unreachable!()
+        };
+        render!(
+            div{
+                (0..children).map(|i|{
+                    rsx!{
+                        p{
+                            key: "{i}",
+                            "{i}"
+                        }
+                    }
+                })
+            }
+        )
+    }
+    let mut vdom = VirtualDom::new(Base);
 
-// #[test]
-// #[allow(unused_variables)]
-// fn persist_instertions_after() {
-//     #[allow(non_snake_case)]
-//     fn Base(cx: Scope) -> Element {
-//         render!(div {})
-//     }
-//     let vdom = VirtualDom::new(Base);
-//     let (build, update) = vdom.diff_lazynodes(
-//         rsx_without_templates! {
-//             div{
-//                 p{
-//                     key: "1",
-//                     "hello"
-//                 }
-//                 p{
-//                     key: "2",
-//                     "world"
-//                 }
-//             }
-//         },
-//         rsx_without_templates! {
-//             div{
-//                 p{
-//                     key: "1",
-//                     "hello"
-//                 }
-//                 p{
-//                     key: "2",
-//                     "world"
-//                 }
-//                 p{
-//                     key: "3",
-//                     "hello world"
-//                 }
-//             }
-//         },
-//     );
+    let mut rdom: RealDom<Empty> = RealDom::new();
 
-//     let mut rdom: RealDom<Empty> = RealDom::new();
+    let build = vdom.rebuild();
+    let _to_update = rdom.apply_mutations(build);
 
-//     let _to_update = rdom.apply_mutations(vec![build]);
+    let mut iter = PersistantElementIter::new();
+    // div
+    iter.next(&rdom).id();
+    // p
+    iter.next(&rdom).id();
+    // "hello"
+    iter.next(&rdom).id();
+    // p
+    iter.next(&rdom).id();
+    // "world"
+    iter.next(&rdom).id();
 
-//     let mut iter = PersistantElementIter::new();
-//     // div
-//     iter.next(&rdom).id();
-//     // p
-//     iter.next(&rdom).id();
-//     // "hello"
-//     iter.next(&rdom).id();
-//     // p
-//     iter.next(&rdom).id();
-//     // "world"
-//     iter.next(&rdom).id();
+    let update = vdom.rebuild();
+    iter.prune(&update, &rdom);
+    let _to_update = rdom.apply_mutations(update);
 
-//     iter.prune(&update, &rdom);
-//     let _to_update = rdom.apply_mutations(vec![update]);
-
-//     let p_tag = "p".to_string();
-//     let idx = iter.next(&rdom).id();
-//     assert!(matches!(
-//         &rdom[idx].node_data.node_type,
-//         NodeType::Element { tag: p_tag, .. }
-//     ));
-//     let text = "hello world".to_string();
-//     let idx = iter.next(&rdom).id();
-//     assert!(matches!(
-//         &rdom[idx].node_data.node_type,
-//         NodeType::Text { text, .. }
-//     ));
-// }
+    let p_tag = "p".to_string();
+    let idx = iter.next(&rdom).id();
+    assert!(matches!(
+        &rdom[idx].node_data.node_type,
+        NodeType::Element { tag: p_tag, .. }
+    ));
+    let text = "hello world".to_string();
+    let idx = iter.next(&rdom).id();
+    assert!(matches!(
+        &rdom[idx].node_data.node_type,
+        NodeType::Text { text, .. }
+    ));
+}

+ 454 - 516
packages/native-core-macro/tests/update_state.rs

@@ -1,516 +1,454 @@
-// use anymap::AnyMap;
-// use dioxus::core::ElementId;
-// use dioxus::core::{AttributeValue, DomEdit, Mutations};
-// use dioxus::core_macro::rsx_without_templates;
-// use dioxus::prelude::*;
-// use dioxus_native_core::real_dom::*;
-// use dioxus_native_core::state::{ChildDepState, NodeDepState, ParentDepState, State};
-// use dioxus_native_core::{node_ref::*, RealNodeId};
-// use dioxus_native_core_macro::State;
-
-// #[derive(Debug, Clone, Default, State)]
-// struct CallCounterStatePart1 {
-//     #[child_dep_state(child_counter)]
-//     child_counter: ChildDepCallCounter,
-// }
-
-// #[derive(Debug, Clone, Default, State)]
-// struct CallCounterStatePart2 {
-//     #[parent_dep_state(parent_counter)]
-//     parent_counter: ParentDepCallCounter,
-// }
-
-// #[derive(Debug, Clone, Default, State)]
-// struct CallCounterStatePart3 {
-//     #[node_dep_state()]
-//     node_counter: NodeDepCallCounter,
-// }
-
-// #[derive(Debug, Clone, Default, State)]
-// struct CallCounterState {
-//     #[child_dep_state(child_counter)]
-//     child_counter: ChildDepCallCounter,
-//     #[state]
-//     part2: CallCounterStatePart2,
-//     #[parent_dep_state(parent_counter)]
-//     parent_counter: ParentDepCallCounter,
-//     #[state]
-//     part1: CallCounterStatePart1,
-//     #[state]
-//     part3: CallCounterStatePart3,
-//     #[node_dep_state()]
-//     node_counter: NodeDepCallCounter,
-// }
-
-// #[derive(Debug, Clone, Default)]
-// struct ChildDepCallCounter(u32);
-// impl ChildDepState for ChildDepCallCounter {
-//     type Ctx = ();
-//     type DepState = Self;
-//     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
-//     }
-// }
-
-// #[derive(Debug, Clone, Default)]
-// struct ParentDepCallCounter(u32);
-// impl ParentDepState for ParentDepCallCounter {
-//     type Ctx = ();
-//     type DepState = Self;
-//     const NODE_MASK: NodeMask = NodeMask::ALL;
-//     fn reduce(
-//         &mut self,
-//         _node: NodeView,
-//         _parent: Option<&Self::DepState>,
-//         _ctx: &Self::Ctx,
-//     ) -> bool {
-//         self.0 += 1;
-//         true
-//     }
-// }
-
-// #[derive(Debug, Clone, Default)]
-// struct NodeDepCallCounter(u32);
-// impl NodeDepState<()> for NodeDepCallCounter {
-//     type Ctx = ();
-//     const NODE_MASK: NodeMask = NodeMask::ALL;
-//     fn reduce(&mut self, _node: NodeView, _sibling: (), _ctx: &Self::Ctx) -> bool {
-//         self.0 += 1;
-//         true
-//     }
-// }
-
-// #[allow(clippy::vec_box)]
-// #[derive(Debug, Clone, PartialEq, Default)]
-// struct BubbledUpStateTester(Option<String>, Vec<Box<BubbledUpStateTester>>);
-// impl ChildDepState for BubbledUpStateTester {
-//     type Ctx = u32;
-//     type DepState = Self;
-//     const NODE_MASK: NodeMask = NodeMask::new().with_tag();
-//     fn reduce<'a>(
-//         &mut self,
-//         node: NodeView,
-//         children: impl Iterator<Item = &'a Self::DepState>,
-//         ctx: &Self::Ctx,
-//     ) -> bool
-//     where
-//         Self::DepState: 'a,
-//     {
-//         assert_eq!(*ctx, 42);
-//         *self = BubbledUpStateTester(
-//             node.tag().map(|s| s.to_string()),
-//             children.into_iter().map(|c| Box::new(c.clone())).collect(),
-//         );
-//         true
-//     }
-// }
-
-// #[derive(Debug, Clone, PartialEq, Default)]
-// struct PushedDownStateTester(Option<String>, Option<Box<PushedDownStateTester>>);
-// impl ParentDepState for PushedDownStateTester {
-//     type Ctx = u32;
-//     type DepState = Self;
-//     const NODE_MASK: NodeMask = NodeMask::new().with_tag();
-//     fn reduce(&mut self, node: NodeView, parent: Option<&Self::DepState>, ctx: &Self::Ctx) -> bool {
-//         assert_eq!(*ctx, 42);
-//         *self = PushedDownStateTester(
-//             node.tag().map(|s| s.to_string()),
-//             parent.map(|c| Box::new(c.clone())),
-//         );
-//         true
-//     }
-// }
-
-// #[derive(Debug, Clone, PartialEq, Default)]
-// struct NodeStateTester(Option<String>, Vec<(String, String)>);
-// impl NodeDepState<()> for NodeStateTester {
-//     type Ctx = u32;
-//     const NODE_MASK: NodeMask = NodeMask::new_with_attrs(AttributeMask::All).with_tag();
-//     fn reduce(&mut self, node: NodeView, _sibling: (), ctx: &Self::Ctx) -> bool {
-//         assert_eq!(*ctx, 42);
-//         *self = NodeStateTester(
-//             node.tag().map(|s| s.to_string()),
-//             node.attributes()
-//                 .map(|iter| {
-//                     iter.map(|a| {
-//                         (
-//                             a.attribute.name.to_string(),
-//                             a.value.as_text().unwrap().to_string(),
-//                         )
-//                     })
-//                     .collect()
-//                 })
-//                 .unwrap_or_default(),
-//         );
-//         true
-//     }
-// }
-
-// #[derive(State, Clone, Default, Debug)]
-// struct StateTester {
-//     #[child_dep_state(bubbled, u32)]
-//     bubbled: BubbledUpStateTester,
-//     #[parent_dep_state(pushed, u32)]
-//     pushed: PushedDownStateTester,
-//     #[node_dep_state(NONE, u32)]
-//     node: NodeStateTester,
-// }
-
-// #[test]
-// fn state_initial() {
-//     #[allow(non_snake_case)]
-//     fn Base(cx: Scope) -> Element {
-//         render!(div {
-//             p{}
-//             h1{}
-//         })
-//     }
-
-//     let vdom = VirtualDom::new(Base);
-
-//     let mutations = vdom.create_vnodes(rsx! {
-//         div {
-//             p{
-//                 color: "red"
-//             }
-//             h1{}
-//         }
-//     });
-
-//     let mut dom: RealDom<StateTester> = RealDom::new();
-
-//     let nodes_updated = dom.apply_mutations(vec![mutations]);
-//     let mut ctx = AnyMap::new();
-//     ctx.insert(42u32);
-//     let _to_rerender = dom.update_state(nodes_updated, ctx);
-
-//     let root_div = &dom[RealNodeId::ElementId(ElementId(2))];
-//     assert_eq!(root_div.state.bubbled.0, Some("div".to_string()));
-//     assert_eq!(
-//         root_div.state.bubbled.1,
-//         vec![
-//             Box::new(BubbledUpStateTester(Some("p".to_string()), Vec::new())),
-//             Box::new(BubbledUpStateTester(Some("h1".to_string()), Vec::new()))
-//         ]
-//     );
-//     assert_eq!(root_div.state.pushed.0, Some("div".to_string()));
-//     assert_eq!(
-//         root_div.state.pushed.1,
-//         Some(Box::new(PushedDownStateTester(
-//             Some("Root".to_string()),
-//             None
-//         )))
-//     );
-//     assert_eq!(root_div.state.node.0, Some("div".to_string()));
-//     assert_eq!(root_div.state.node.1, vec![]);
-
-//     let child_p = &dom[RealNodeId::UnaccessableId(3)];
-//     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()));
-//     assert_eq!(
-//         child_p.state.pushed.1,
-//         Some(Box::new(PushedDownStateTester(
-//             Some("div".to_string()),
-//             Some(Box::new(PushedDownStateTester(
-//                 Some("Root".to_string()),
-//                 None
-//             )))
-//         )))
-//     );
-//     assert_eq!(child_p.state.node.0, Some("p".to_string()));
-//     assert_eq!(
-//         child_p.state.node.1,
-//         vec![("color".to_string(), "red".to_string())]
-//     );
-
-//     let child_h1 = &dom[RealNodeId::UnaccessableId(4)];
-//     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()));
-//     assert_eq!(
-//         child_h1.state.pushed.1,
-//         Some(Box::new(PushedDownStateTester(
-//             Some("div".to_string()),
-//             Some(Box::new(PushedDownStateTester(
-//                 Some("Root".to_string()),
-//                 None
-//             )))
-//         )))
-//     );
-//     assert_eq!(child_h1.state.node.0, Some("h1".to_string()));
-//     assert_eq!(child_h1.state.node.1, vec![]);
-// }
-
-// #[test]
-// fn state_reduce_parent_called_minimally_on_update() {
-//     #[allow(non_snake_case)]
-//     fn Base(cx: Scope) -> Element {
-//         render!(div {
-//             width: "100%",
-//             div{
-//                 div{
-//                     p{}
-//                 }
-//                 p{
-//                     "hello"
-//                 }
-//                 div{
-//                     h1{}
-//                 }
-//                 p{
-//                     "world"
-//                 }
-//             }
-//         })
-//     }
-
-//     let vdom = VirtualDom::new(Base);
-
-//     let mutations = vdom.create_vnodes(rsx_without_templates! {
-//         div {
-//             width: "100%",
-//             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(nodes_updated, AnyMap::new());
-//     let nodes_updated = dom.apply_mutations(vec![Mutations {
-//         edits: vec![DomEdit::SetAttribute {
-//             root: Some(1),
-//             field: "width",
-//             value: AttributeValue::Text("99%"),
-//             ns: Some("style"),
-//         }],
-//         dirty_scopes: rustc_hash::FxHashSet::default(),
-//         refs: Vec::new(),
-//     }]);
-//     let _to_rerender = dom.update_state(nodes_updated, AnyMap::new());
-
-//     dom.traverse_depth_first(|n| {
-//         assert_eq!(n.state.part2.parent_counter.0, 2);
-//         assert_eq!(n.state.parent_counter.0, 2);
-//     });
-// }
-
-// #[test]
-// fn state_reduce_child_called_minimally_on_update() {
-//     #[allow(non_snake_case)]
-//     fn Base(cx: Scope) -> Element {
-//         cx.render(rsx_without_templates!(div {
-//             div{
-//                 div{
-//                     p{
-//                         width: "100%",
-//                     }
-//                 }
-//                 p{
-//                     "hello"
-//                 }
-//                 div{
-//                     h1{}
-//                 }
-//                 p{
-//                     "world"
-//                 }
-//             }
-//         }))
-//     }
-
-//     let vdom = VirtualDom::new(Base);
-
-//     let mutations = vdom.create_vnodes(rsx_without_templates! {
-//         div {
-//             div{
-//                 div{
-//                     p{
-//                         width: "100%",
-//                     }
-//                 }
-//                 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(nodes_updated, AnyMap::new());
-//     let nodes_updated = dom.apply_mutations(vec![Mutations {
-//         edits: vec![DomEdit::SetAttribute {
-//             root: Some(4),
-//             field: "width",
-//             value: AttributeValue::Text("99%"),
-//             ns: Some("style"),
-//         }],
-//         dirty_scopes: rustc_hash::FxHashSet::default(),
-//         refs: Vec::new(),
-//     }]);
-//     let _to_rerender = dom.update_state(nodes_updated, AnyMap::new());
-
-//     dom.traverse_depth_first(|n| {
-//         assert_eq!(
-//             n.state.part1.child_counter.0,
-//             if let Some(RealNodeId::ElementId(ElementId(id))) = n.node_data.id {
-//                 if id > 4 {
-//                     1
-//                 } else {
-//                     2
-//                 }
-//             } else {
-//                 panic!()
-//             }
-//         );
-//         assert_eq!(
-//             n.state.child_counter.0,
-//             if let Some(RealNodeId::ElementId(ElementId(id))) = n.node_data.id {
-//                 if id > 4 {
-//                     1
-//                 } else {
-//                     2
-//                 }
-//             } else {
-//                 panic!()
-//             }
-//         );
-//     });
-// }
-
-// #[derive(Debug, Clone, Default, State)]
-// struct UnorderedDependanciesState {
-//     #[node_dep_state(c)]
-//     b: BDepCallCounter,
-//     #[node_dep_state()]
-//     c: CDepCallCounter,
-//     #[node_dep_state(b)]
-//     a: ADepCallCounter,
-// }
-
-// #[derive(Debug, Clone, Default, PartialEq)]
-// struct ADepCallCounter(usize, BDepCallCounter);
-// impl<'a> NodeDepState<(&'a BDepCallCounter,)> for ADepCallCounter {
-//     type Ctx = ();
-//     const NODE_MASK: NodeMask = NodeMask::NONE;
-//     fn reduce(
-//         &mut self,
-//         _node: NodeView,
-//         (sibling,): (&'a BDepCallCounter,),
-//         _ctx: &Self::Ctx,
-//     ) -> bool {
-//         self.0 += 1;
-//         self.1 = sibling.clone();
-//         true
-//     }
-// }
-
-// #[derive(Debug, Clone, Default, PartialEq)]
-// struct BDepCallCounter(usize, CDepCallCounter);
-// impl<'a> NodeDepState<(&'a CDepCallCounter,)> for BDepCallCounter {
-//     type Ctx = ();
-//     const NODE_MASK: NodeMask = NodeMask::NONE;
-//     fn reduce(
-//         &mut self,
-//         _node: NodeView,
-//         (sibling,): (&'a CDepCallCounter,),
-//         _ctx: &Self::Ctx,
-//     ) -> bool {
-//         self.0 += 1;
-//         self.1 = sibling.clone();
-//         true
-//     }
-// }
-
-// #[derive(Debug, Clone, Default, PartialEq)]
-// struct CDepCallCounter(usize);
-// impl NodeDepState<()> for CDepCallCounter {
-//     type Ctx = ();
-//     const NODE_MASK: NodeMask = NodeMask::ALL;
-//     fn reduce(&mut self, _node: NodeView, _sibling: (), _ctx: &Self::Ctx) -> bool {
-//         self.0 += 1;
-//         true
-//     }
-// }
-
-// #[test]
-// fn dependancies_order_independant() {
-//     #[allow(non_snake_case)]
-//     fn Base(cx: Scope) -> Element {
-//         render!(div {
-//             width: "100%",
-//             p{
-//                 "hello"
-//             }
-//         })
-//     }
-
-//     let vdom = VirtualDom::new(Base);
-
-//     let mutations = vdom.create_vnodes(rsx! {
-//         div {
-//             width: "100%",
-//             p{
-//                 "hello"
-//             }
-//         }
-//     });
-
-//     let mut dom: RealDom<UnorderedDependanciesState> = RealDom::new();
-
-//     let nodes_updated = dom.apply_mutations(vec![mutations]);
-//     let _to_rerender = dom.update_state(nodes_updated, AnyMap::new());
-
-//     let c = CDepCallCounter(1);
-//     let b = BDepCallCounter(1, c.clone());
-//     let a = ADepCallCounter(1, b.clone());
-//     dom.traverse_depth_first(|n| {
-//         assert_eq!(&n.state.a, &a);
-//         assert_eq!(&n.state.b, &b);
-//         assert_eq!(&n.state.c, &c);
-//     });
-// }
-
-// #[derive(Clone, Default, State)]
-// struct DependanciesStateTest {
-//     #[node_dep_state(c)]
-//     b: BDepCallCounter,
-//     #[node_dep_state()]
-//     c: CDepCallCounter,
-//     #[node_dep_state(b)]
-//     a: ADepCallCounter,
-//     #[state]
-//     child: UnorderedDependanciesState,
-// }
+use dioxus::core::ElementId;
+use dioxus::core::{AttributeValue, Mutations};
+use dioxus::prelude::*;
+use dioxus_native_core::real_dom::*;
+use dioxus_native_core::state::{ChildDepState, NodeDepState, ParentDepState, State};
+use dioxus_native_core::tree::TreeView;
+use dioxus_native_core::{node_ref::*, NodeId, RealNodeId, SendAnyMap};
+use dioxus_native_core_macro::State;
+
+#[derive(Debug, Clone, Default, State)]
+struct CallCounterStatePart1 {
+    #[child_dep_state(child_counter)]
+    child_counter: ChildDepCallCounter,
+}
+
+#[derive(Debug, Clone, Default, State)]
+struct CallCounterStatePart2 {
+    #[parent_dep_state(parent_counter)]
+    parent_counter: ParentDepCallCounter,
+}
+
+#[derive(Debug, Clone, Default, State)]
+struct CallCounterStatePart3 {
+    #[node_dep_state()]
+    node_counter: NodeDepCallCounter,
+}
+
+#[derive(Debug, Clone, Default, State)]
+struct CallCounterState {
+    #[child_dep_state(child_counter)]
+    child_counter: ChildDepCallCounter,
+    #[state]
+    part2: CallCounterStatePart2,
+    #[parent_dep_state(parent_counter)]
+    parent_counter: ParentDepCallCounter,
+    #[state]
+    part1: CallCounterStatePart1,
+    #[state]
+    part3: CallCounterStatePart3,
+    #[node_dep_state()]
+    node_counter: NodeDepCallCounter,
+}
+
+#[derive(Debug, Clone, Default)]
+struct ChildDepCallCounter(u32);
+impl ChildDepState for ChildDepCallCounter {
+    type Ctx = ();
+    type DepState = (Self,);
+    const NODE_MASK: NodeMask = NodeMask::ALL;
+    fn reduce<'a>(
+        &mut self,
+        _: NodeView,
+        _: impl Iterator<Item = (&'a Self,)>,
+        _: &Self::Ctx,
+    ) -> bool
+    where
+        Self::DepState: 'a,
+    {
+        self.0 += 1;
+        true
+    }
+}
+
+#[derive(Debug, Clone, Default)]
+struct ParentDepCallCounter(u32);
+impl ParentDepState for ParentDepCallCounter {
+    type Ctx = ();
+    type DepState = (Self,);
+    const NODE_MASK: NodeMask = NodeMask::ALL;
+    fn reduce(&mut self, _node: NodeView, _parent: Option<(&Self,)>, _ctx: &Self::Ctx) -> bool {
+        self.0 += 1;
+        true
+    }
+}
+
+#[derive(Debug, Clone, Default)]
+struct NodeDepCallCounter(u32);
+impl NodeDepState for NodeDepCallCounter {
+    type Ctx = ();
+    type DepState = ();
+    const NODE_MASK: NodeMask = NodeMask::ALL;
+    fn reduce(&mut self, _node: NodeView, _sibling: (), _ctx: &Self::Ctx) -> bool {
+        self.0 += 1;
+        true
+    }
+}
+
+#[allow(clippy::vec_box)]
+#[derive(Debug, Clone, PartialEq, Default)]
+struct BubbledUpStateTester(Option<String>, Vec<Box<BubbledUpStateTester>>);
+impl ChildDepState for BubbledUpStateTester {
+    type Ctx = u32;
+    type DepState = (Self,);
+    const NODE_MASK: NodeMask = NodeMask::new().with_tag();
+    fn reduce<'a>(
+        &mut self,
+        node: NodeView,
+        children: impl Iterator<Item = (&'a Self,)>,
+        ctx: &Self::Ctx,
+    ) -> bool
+    where
+        Self::DepState: 'a,
+    {
+        assert_eq!(*ctx, 42);
+        *self = BubbledUpStateTester(
+            node.tag().map(|s| s.to_string()),
+            children
+                .into_iter()
+                .map(|(c,)| Box::new(c.clone()))
+                .collect(),
+        );
+        true
+    }
+}
+
+#[derive(Debug, Clone, PartialEq, Default)]
+struct PushedDownStateTester(Option<String>, Option<Box<PushedDownStateTester>>);
+impl ParentDepState for PushedDownStateTester {
+    type Ctx = u32;
+    type DepState = (Self,);
+    const NODE_MASK: NodeMask = NodeMask::new().with_tag();
+    fn reduce(&mut self, node: NodeView, parent: Option<(&Self,)>, ctx: &Self::Ctx) -> bool {
+        assert_eq!(*ctx, 42);
+        *self = PushedDownStateTester(
+            node.tag().map(|s| s.to_string()),
+            parent.map(|(c,)| Box::new(c.clone())),
+        );
+        true
+    }
+}
+
+#[derive(Debug, Clone, PartialEq, Default)]
+struct NodeStateTester(Option<String>, Vec<(String, String)>);
+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: (), ctx: &Self::Ctx) -> bool {
+        assert_eq!(*ctx, 42);
+        *self = NodeStateTester(
+            node.tag().map(|s| s.to_string()),
+            node.attributes()
+                .map(|iter| {
+                    iter.map(|a| {
+                        (
+                            a.attribute.name.to_string(),
+                            a.value.as_text().unwrap().to_string(),
+                        )
+                    })
+                    .collect()
+                })
+                .unwrap_or_default(),
+        );
+        true
+    }
+}
+
+#[derive(State, Clone, Default, Debug)]
+struct StateTester {
+    #[child_dep_state(bubbled, u32)]
+    bubbled: BubbledUpStateTester,
+    #[parent_dep_state(pushed, u32)]
+    pushed: PushedDownStateTester,
+    #[node_dep_state(NONE, u32)]
+    node: NodeStateTester,
+}
+
+#[test]
+fn state_initial() {
+    #[allow(non_snake_case)]
+    fn Base(cx: Scope) -> Element {
+        render! {
+            div{
+                p{}
+                h1{}
+                div {
+                    p{
+                        color: "red"
+                    }
+                    h1{}
+                }
+            }
+        }
+    }
+
+    let mut vdom = VirtualDom::new(Base);
+
+    let mutations = vdom.rebuild();
+
+    let mut dom: RealDom<StateTester> = RealDom::new();
+
+    let (nodes_updated, _) = dom.apply_mutations(mutations);
+    let mut ctx = SendAnyMap::new();
+    ctx.insert(42u32);
+    let _to_rerender = dom.update_state(nodes_updated, ctx);
+
+    let root_div_id = dom.children_ids(NodeId(0)).unwrap()[0];
+    let root_div = &dom.get(root_div_id).unwrap();
+    assert_eq!(root_div.state.bubbled.0, Some("div".to_string()));
+    assert_eq!(
+        root_div.state.bubbled.1,
+        vec![
+            Box::new(BubbledUpStateTester(Some("p".to_string()), Vec::new())),
+            Box::new(BubbledUpStateTester(Some("h1".to_string()), Vec::new()))
+        ]
+    );
+    assert_eq!(root_div.state.pushed.0, Some("div".to_string()));
+    assert_eq!(
+        root_div.state.pushed.1,
+        Some(Box::new(PushedDownStateTester(
+            Some("Root".to_string()),
+            None
+        )))
+    );
+    assert_eq!(root_div.state.node.0, Some("div".to_string()));
+    assert_eq!(root_div.state.node.1, vec![]);
+
+    let child_p_id = dom.children_ids(root_div_id).unwrap()[0];
+    let child_p = &dom[child_p_id];
+    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()));
+    assert_eq!(
+        child_p.state.pushed.1,
+        Some(Box::new(PushedDownStateTester(
+            Some("div".to_string()),
+            Some(Box::new(PushedDownStateTester(
+                Some("Root".to_string()),
+                None
+            )))
+        )))
+    );
+    assert_eq!(child_p.state.node.0, Some("p".to_string()));
+    assert_eq!(
+        child_p.state.node.1,
+        vec![("color".to_string(), "red".to_string())]
+    );
+
+    let child_h1_id = dom.children_ids(root_div_id).unwrap()[1];
+    let child_h1 = &dom[child_h1_id];
+    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()));
+    assert_eq!(
+        child_h1.state.pushed.1,
+        Some(Box::new(PushedDownStateTester(
+            Some("div".to_string()),
+            Some(Box::new(PushedDownStateTester(
+                Some("Root".to_string()),
+                None
+            )))
+        )))
+    );
+    assert_eq!(child_h1.state.node.0, Some("h1".to_string()));
+    assert_eq!(child_h1.state.node.1, vec![]);
+}
+
+#[test]
+fn state_reduce_parent_called_minimally_on_update() {
+    #[allow(non_snake_case)]
+    fn Base(cx: Scope) -> Element {
+        let width = if cx.generation() == 0 { "100%" } else { "99%" };
+        cx.render(rsx! {
+            div {
+                div{
+                    div{
+                        p{
+                            width: "{width}",
+                        }
+                    }
+                    p{
+                        "hello"
+                    }
+                    div{
+                        h1{}
+                    }
+                    p{
+                        "world"
+                    }
+                }
+            }
+        })
+    }
+
+    let mut vdom = VirtualDom::new(Base);
+
+    let mut dom: RealDom<CallCounterState> = RealDom::new();
+
+    let (nodes_updated, _) = dom.apply_mutations(vdom.rebuild());
+    let _to_rerender = dom.update_state(nodes_updated, SendAnyMap::new());
+    let (nodes_updated, _) = dom.apply_mutations(vdom.rebuild());
+    let _to_rerender = dom.update_state(nodes_updated, SendAnyMap::new());
+
+    dom.traverse_depth_first(|n| {
+        assert_eq!(n.state.part2.parent_counter.0, 2);
+        assert_eq!(n.state.parent_counter.0, 2);
+    });
+}
+
+#[test]
+fn state_reduce_child_called_minimally_on_update() {
+    #[allow(non_snake_case)]
+    fn Base(cx: Scope) -> Element {
+        let width = if cx.generation() == 0 { "100%" } else { "99%" };
+        cx.render(rsx! {
+            div {
+                div{
+                    div{
+                        p{
+                            width: "{width}",
+                        }
+                    }
+                    p{
+                        "hello"
+                    }
+                    div{
+                        h1{}
+                    }
+                    p{
+                        "world"
+                    }
+                }
+            }
+        })
+    }
+
+    let mut vdom = VirtualDom::new(Base);
+
+    let mut dom: RealDom<CallCounterState> = RealDom::new();
+
+    let (nodes_updated, _) = dom.apply_mutations(vdom.rebuild());
+    let _to_rerender = dom.update_state(nodes_updated, SendAnyMap::new());
+    let (nodes_updated, _) = dom.apply_mutations(vdom.rebuild());
+    let _to_rerender = dom.update_state(nodes_updated, SendAnyMap::new());
+
+    dom.traverse_depth_first(|n| {
+        assert_eq!(n.state.part1.child_counter.0, {
+            let id = n.node_data.node_id.0;
+            if id > 4 {
+                1
+            } else {
+                2
+            }
+        });
+        assert_eq!(n.state.child_counter.0, {
+            let id = n.node_data.node_id.0;
+            if id > 4 {
+                1
+            } else {
+                2
+            }
+        });
+    });
+}
+
+#[derive(Debug, Clone, Default, State)]
+struct UnorderedDependanciesState {
+    #[node_dep_state(c)]
+    b: BDepCallCounter,
+    #[node_dep_state()]
+    c: CDepCallCounter,
+    #[node_dep_state(b)]
+    a: ADepCallCounter,
+}
+
+#[derive(Debug, Clone, Default, PartialEq)]
+struct ADepCallCounter(usize, BDepCallCounter);
+impl NodeDepState for ADepCallCounter {
+    type Ctx = ();
+    type DepState = (BDepCallCounter,);
+    const NODE_MASK: NodeMask = NodeMask::NONE;
+    fn reduce(
+        &mut self,
+        _node: NodeView,
+        (sibling,): (&BDepCallCounter,),
+        _ctx: &Self::Ctx,
+    ) -> bool {
+        self.0 += 1;
+        self.1 = sibling.clone();
+        true
+    }
+}
+
+#[derive(Debug, Clone, Default, PartialEq)]
+struct BDepCallCounter(usize, CDepCallCounter);
+impl NodeDepState for BDepCallCounter {
+    type Ctx = ();
+    type DepState = (CDepCallCounter,);
+    const NODE_MASK: NodeMask = NodeMask::NONE;
+    fn reduce(
+        &mut self,
+        _node: NodeView,
+        (sibling,): (&CDepCallCounter,),
+        _ctx: &Self::Ctx,
+    ) -> bool {
+        self.0 += 1;
+        self.1 = sibling.clone();
+        true
+    }
+}
+
+#[derive(Debug, Clone, Default, PartialEq)]
+struct CDepCallCounter(usize);
+impl NodeDepState for CDepCallCounter {
+    type Ctx = ();
+    type DepState = ();
+    const NODE_MASK: NodeMask = NodeMask::ALL;
+    fn reduce(&mut self, _node: NodeView, _sibling: (), _ctx: &Self::Ctx) -> bool {
+        self.0 += 1;
+        true
+    }
+}
+
+#[test]
+fn dependancies_order_independant() {
+    #[allow(non_snake_case)]
+    fn Base(cx: Scope) -> Element {
+        render!(div {
+            width: "100%",
+            p{
+                "hello"
+            }
+        })
+    }
+
+    let mut vdom = VirtualDom::new(Base);
+
+    let mut dom: RealDom<UnorderedDependanciesState> = RealDom::new();
+
+    let mutations = vdom.rebuild();
+    let (nodes_updated, _) = dom.apply_mutations(mutations);
+    let _to_rerender = dom.update_state(nodes_updated, SendAnyMap::new());
+
+    let c = CDepCallCounter(1);
+    let b = BDepCallCounter(1, c.clone());
+    let a = ADepCallCounter(1, b.clone());
+    dom.traverse_depth_first(|n| {
+        assert_eq!(&n.state.a, &a);
+        assert_eq!(&n.state.b, &b);
+        assert_eq!(&n.state.c, &c);
+    });
+}
+
+#[derive(Clone, Default, State)]
+struct DependanciesStateTest {
+    #[node_dep_state(c)]
+    b: BDepCallCounter,
+    #[node_dep_state()]
+    c: CDepCallCounter,
+    #[node_dep_state(b)]
+    a: ADepCallCounter,
+    #[state]
+    child: UnorderedDependanciesState,
+}

+ 12 - 9
packages/native-core/src/utils.rs

@@ -2,6 +2,7 @@ use crate::{node::NodeType, real_dom::RealDom, state::State, tree::TreeView, Nod
 use dioxus_core::{Mutation, Mutations};
 use std::fmt::Debug;
 
+#[derive(Debug)]
 pub enum ElementProduced {
     /// The iterator produced an element by progressing to the next node in a depth first order.
     Progressed(RealNodeId),
@@ -124,20 +125,20 @@ impl PersistantElementIter {
 
     /// get the next element
     pub fn next<S: State>(&mut self, rdom: &RealDom<S>) -> ElementProduced {
-        if self.stack.is_empty() {
+        let r=if self.stack.is_empty() {
             let id = NodeId(0);
             let new = (id, NodePosition::AtNode);
             self.stack.push(new);
             ElementProduced::Looped(id)
         } else {
-            let (last, o_child_idx) = self.stack.last_mut().unwrap();
+            let (last, old_child_idx) = self.stack.last_mut().unwrap();
             let node = &rdom[*last];
             match &node.node_data.node_type {
                 NodeType::Element { .. } => {
                     let children = rdom.tree.children_ids(*last).unwrap();
-                    *o_child_idx = o_child_idx.map(|i| i + 1);
+                    *old_child_idx = old_child_idx.map(|i| i + 1);
                     // if we have children, go to the next child
-                    let child_idx = o_child_idx.get_or_insert(0);
+                    let child_idx = old_child_idx.get_or_insert(0);
                     if child_idx >= children.len() {
                         self.pop();
                         self.next(rdom)
@@ -155,7 +156,9 @@ impl PersistantElementIter {
                     ElementProduced::Progressed(self.pop())
                 }
             }
-        }
+        };
+        println!("next: {:?}", r);
+        r
     }
 
     /// get the previous element
@@ -183,17 +186,17 @@ impl PersistantElementIter {
             let new_node = NodeId(0);
             ElementProduced::Looped(push_back(&mut self.stack, new_node, rdom))
         } else {
-            let (last, o_child_idx) = self.stack.last_mut().unwrap();
+            let (last, old_child_idx) = self.stack.last_mut().unwrap();
             let node = &rdom[*last];
             match &node.node_data.node_type {
                 NodeType::Element { .. } => {
                     let children = rdom.tree.children_ids(*last).unwrap();
                     // if we have children, go to the next child
-                    if let NodePosition::InChild(0) = o_child_idx {
+                    if let NodePosition::InChild(0) = old_child_idx {
                         ElementProduced::Progressed(self.pop())
                     } else {
-                        *o_child_idx = o_child_idx.map(|i| i - 1);
-                        if let NodePosition::InChild(child_idx) = o_child_idx {
+                        *old_child_idx = old_child_idx.map(|i| i - 1);
+                        if let NodePosition::InChild(child_idx) = old_child_idx {
                             if *child_idx >= children.len() || children.is_empty() {
                                 self.pop();
                                 self.prev(rdom)