diff --git a/packages/native-core-macro/.gitignore b/packages/native-core-macro/.gitignore new file mode 100644 index 000000000..96ef6c0b9 --- /dev/null +++ b/packages/native-core-macro/.gitignore @@ -0,0 +1,2 @@ +/target +Cargo.lock diff --git a/packages/native-core-macro/tests/persistent_iterator.rs b/packages/native-core-macro/tests/persistent_iterator.rs deleted file mode 100644 index 0ad2e3ca2..000000000 --- a/packages/native-core-macro/tests/persistent_iterator.rs +++ /dev/null @@ -1,297 +0,0 @@ -use dioxus::prelude::*; -use dioxus_native_core::{ - node::NodeType, real_dom::RealDom, state::State, utils::PersistantElementIter, -}; -use dioxus_native_core_macro::State; - -#[derive(State, Default, Clone, Debug)] -struct Empty {} - -#[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 vdom = VirtualDom::new(Base); - let mutations = vdom.rebuild(); - - let mut rdom: RealDom = RealDom::new(); - - let _to_update = rdom.apply_mutations(mutations); - - 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, .. } - )); - - 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, .. } - )); -} - -#[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 mut rdom: RealDom = RealDom::new(); - - let build = vdom.rebuild(); - let _to_update = rdom.apply_mutations(build); - - // 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(); - - vdom.mark_dirty(ScopeId(0)); - let update = vdom.render_immediate(); - iter1.prune(&update, &rdom); - iter2.prune(&update, &rdom); - let _to_update = rdom.apply_mutations(update); - - 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, .. } - )); -} - -#[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 mut rdom: RealDom = RealDom::new(); - - 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(); - - vdom.mark_dirty(ScopeId(0)); - let update = vdom.render_immediate(); - iter.prune(&update, &rdom); - let _to_update = rdom.apply_mutations(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, .. } - )); -} - -#[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); - - let mut rdom: RealDom = RealDom::new(); - - 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(); - // "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); - - 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/.gitignore b/packages/native-core/.gitignore new file mode 100644 index 000000000..96ef6c0b9 --- /dev/null +++ b/packages/native-core/.gitignore @@ -0,0 +1,2 @@ +/target +Cargo.lock diff --git a/packages/native-core/Cargo.toml b/packages/native-core/Cargo.toml index f15a743f3..309fba781 100644 --- a/packages/native-core/Cargo.toml +++ b/packages/native-core/Cargo.toml @@ -25,4 +25,5 @@ crossbeam-deque = "0.8.2" dashmap = "5.4.0" [dev-dependencies] -rand = "0.8.5" \ No newline at end of file +rand = "0.8.5" +dioxus = { path = "../dioxus", version = "^0.2.1" } \ No newline at end of file diff --git a/packages/native-core/src/utils.rs b/packages/native-core/src/utils.rs index ac6d1f6d3..7a55ad6db 100644 --- a/packages/native-core/src/utils.rs +++ b/packages/native-core/src/utils.rs @@ -125,7 +125,7 @@ impl PersistantElementIter { /// get the next element pub fn next(&mut self, rdom: &RealDom) -> ElementProduced { - let r=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); @@ -227,3 +227,304 @@ impl PersistantElementIter { self.stack.pop().unwrap().0 } } + +#[derive(Default, Clone, Debug)] +struct Empty {} +impl State for Empty { + const PASSES: &'static [crate::AnyPass>] = &[]; + + const MASKS: &'static [crate::NodeMask] = &[]; +} + +#[test] +#[allow(unused_variables)] +fn traverse() { + use dioxus::prelude::*; + #[allow(non_snake_case)] + fn Base(cx: Scope) -> Element { + render!( + div{ + div{ + "hello" + p{ + "world" + } + "hello world" + } + } + ) + } + + let mut vdom = VirtualDom::new(Base); + let mutations = vdom.rebuild(); + + let mut rdom: RealDom = RealDom::new(); + + let _to_update = rdom.apply_mutations(mutations); + + 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, .. } + )); + + 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, .. } + )); +} + +#[test] +#[allow(unused_variables)] +fn persist_removes() { + use dioxus::prelude::*; + #[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 mut rdom: RealDom = RealDom::new(); + + let build = vdom.rebuild(); + let _to_update = rdom.apply_mutations(build); + + // 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(); + + vdom.mark_dirty(ScopeId(0)); + let update = vdom.render_immediate(); + iter1.prune(&update, &rdom); + iter2.prune(&update, &rdom); + let _to_update = rdom.apply_mutations(update); + + 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, .. } + )); +} + +#[test] +#[allow(unused_variables)] +fn persist_instertions_before() { + use dioxus::prelude::*; + #[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 mut rdom: RealDom = RealDom::new(); + + 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(); + + vdom.mark_dirty(ScopeId(0)); + let update = vdom.render_immediate(); + iter.prune(&update, &rdom); + let _to_update = rdom.apply_mutations(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, .. } + )); +} + +#[test] +#[allow(unused_variables)] +fn persist_instertions_after() { + use dioxus::prelude::*; + #[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 mut rdom: RealDom = RealDom::new(); + + 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(); + // "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); + + 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, .. } + )); +}