diff --git a/packages/native-core-macro/src/lib.rs b/packages/native-core-macro/src/lib.rs index 6c0cdb2d0..dda96b512 100644 --- a/packages/native-core-macro/src/lib.rs +++ b/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 { + fn parse(parent: &Ident, field: &Field, id: u64) -> Option { 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(), diff --git a/packages/native-core-macro/tests/called_minimally_on_build.rs b/packages/native-core-macro/tests/called_minimally_on_build.rs index 978ad8f5f..84e4fb0e6 100644 --- a/packages/native-core-macro/tests/called_minimally_on_build.rs +++ b/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" - } - } - }) - } - - let vdom = VirtualDom::new(Base); - - let mutations = vdom.create_vnodes(rsx! { - div { - div{ - div{ - p{} - } - p{ - "hello" - } - div{ - h1{} - } - p{ - "world" + div{ + p{} + } + p{ + "hello" + } + div{ + h1{} + } + p{ + "world" + } } } } - }); + } + + let mut vdom = VirtualDom::new(Base); + + 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))); +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 Child(i32); + dep!(child(Child, (Child,))); -// #[derive(Debug, Clone, Default, PartialEq)] -// struct Parent(i32); -// dep!(parent(Parent, (Parent,))); + #[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, -// } + #[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)); -// } + 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,))); +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 Child(i32); + dep!(child(Child, (Node,))); -// #[derive(Debug, Clone, Default, PartialEq)] -// struct Parent(i32); -// dep!(parent(Parent, (Parent,))); + #[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, -// } + #[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)); -// } + 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,))); +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 Child(i32); + dep!(child(Child, (Child,))); -// #[derive(Debug, Clone, Default, PartialEq)] -// struct Parent(i32); -// dep!(parent(Parent, (Node,))); + #[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, -// } + #[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)); -// } + 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,))); +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, 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, -// } + #[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: ()); -// } + 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, ())); +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 Child(i32); + dep!(child(Child, (Child,))); -// #[derive(Debug, Clone, Default, PartialEq)] -// struct Parent(i32); -// dep!(parent(Parent, (Parent,))); + #[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, -// } + #[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)); -// } + test_state!(StateTester, child: (child), node: (node), parent: (parent)); +} diff --git a/packages/native-core-macro/tests/change_nodes.rs b/packages/native-core-macro/tests/change_nodes.rs deleted file mode 100644 index af3cbefb8..000000000 --- a/packages/native-core-macro/tests/change_nodes.rs +++ /dev/null @@ -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 = 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 = 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)); -// } diff --git a/packages/native-core-macro/tests/initial_build.rs b/packages/native-core-macro/tests/initial_build.rs deleted file mode 100644 index 86605aca9..000000000 --- a/packages/native-core-macro/tests/initial_build.rs +++ /dev/null @@ -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 = 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 = 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); -// } diff --git a/packages/native-core-macro/tests/persistent_iterator.rs b/packages/native-core-macro/tests/persistent_iterator.rs index b1de9392e..c35c6ab0a 100644 --- a/packages/native-core-macro/tests/persistent_iterator.rs +++ b/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 = RealDom::new(); + let mut vdom = VirtualDom::new(Base); + let mutations = vdom.rebuild(); -// let _to_update = rdom.apply_mutations(vec![mutations]); + let mut rdom: RealDom = 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 = 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 = 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 = 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 = 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 = RealDom::new(); -// let mut rdom: RealDom = 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, .. } + )); +} diff --git a/packages/native-core-macro/tests/update_state.rs b/packages/native-core-macro/tests/update_state.rs index 2e6a04dec..456ea5f5b 100644 --- a/packages/native-core-macro/tests/update_state.rs +++ b/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; +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 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 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 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, 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, -// _: &Self::Ctx, -// ) -> bool -// where -// Self::DepState: 'a, -// { -// self.0 += 1; -// true -// } -// } +#[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, + _: &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 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 = (); -// const NODE_MASK: NodeMask = NodeMask::ALL; -// fn reduce(&mut self, _node: NodeView, _sibling: (), _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, Vec>); -// 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, -// 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 -// } -// } +#[allow(clippy::vec_box)] +#[derive(Debug, Clone, PartialEq, Default)] +struct BubbledUpStateTester(Option, Vec>); +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, + 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, Option>); -// 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 PushedDownStateTester(Option, Option>); +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, 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(Debug, Clone, PartialEq, Default)] +struct NodeStateTester(Option, 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, -// } +#[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{} -// }) -// } +#[test] +fn state_initial() { + #[allow(non_snake_case)] + fn Base(cx: Scope) -> Element { + render! { + div{ + p{} + h1{} + div { + p{ + color: "red" + } + h1{} + } + } + } + } -// let vdom = VirtualDom::new(Base); + let mut vdom = VirtualDom::new(Base); -// let mutations = vdom.create_vnodes(rsx! { -// div { -// p{ -// color: "red" -// } -// h1{} -// } -// }); + let mutations = vdom.rebuild(); -// let mut dom: RealDom = RealDom::new(); + let mut dom: RealDom = 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 (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 = &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 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 = &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_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 = &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![]); -// } + 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 { -// render!(div { -// width: "100%", -// div{ -// div{ -// p{} -// } -// p{ -// "hello" -// } -// div{ -// h1{} -// } -// p{ -// "world" -// } -// } -// }) -// } +#[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 vdom = VirtualDom::new(Base); + let mut 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 = RealDom::new(); -// let mut dom: RealDom = 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()); -// 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); + }); +} -// 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" + } + } + } + }) + } -// #[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 mut vdom = VirtualDom::new(Base); -// let vdom = VirtualDom::new(Base); + let mut dom: RealDom = RealDom::new(); -// let mutations = vdom.create_vnodes(rsx_without_templates! { -// div { -// div{ -// div{ -// p{ -// width: "100%", -// } -// } -// p{ -// "hello" -// } -// div{ -// h1{} -// } -// p{ -// "world" -// } -// } -// } -// }); + 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()); -// let mut dom: RealDom = RealDom::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 + } + }); + }); +} -// 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()); +#[derive(Debug, Clone, Default, State)] +struct UnorderedDependanciesState { + #[node_dep_state(c)] + b: BDepCallCounter, + #[node_dep_state()] + c: CDepCallCounter, + #[node_dep_state(b)] + a: ADepCallCounter, +} -// 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, 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, 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 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 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 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 + } +} -// #[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 -// } -// } +#[test] +fn dependancies_order_independant() { + #[allow(non_snake_case)] + fn Base(cx: Scope) -> Element { + render!(div { + width: "100%", + p{ + "hello" + } + }) + } -// #[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 -// } -// } + let mut vdom = VirtualDom::new(Base); -// #[test] -// fn dependancies_order_independant() { -// #[allow(non_snake_case)] -// fn Base(cx: Scope) -> Element { -// render!(div { -// width: "100%", -// p{ -// "hello" -// } -// }) -// } + let mut dom: RealDom = RealDom::new(); -// let vdom = VirtualDom::new(Base); + let mutations = vdom.rebuild(); + let (nodes_updated, _) = dom.apply_mutations(mutations); + let _to_rerender = dom.update_state(nodes_updated, SendAnyMap::new()); -// let mutations = vdom.create_vnodes(rsx! { -// div { -// width: "100%", -// p{ -// "hello" -// } -// } -// }); + 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); + }); +} -// let mut dom: RealDom = 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, -// } +#[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, +} diff --git a/packages/native-core/src/utils.rs b/packages/native-core/src/utils.rs index bec658624..ac6d1f6d3 100644 --- a/packages/native-core/src/utils.rs +++ b/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(&mut self, rdom: &RealDom) -> 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)