浏览代码

wip: structure coming together and tests

Jonathan Kelley 3 年之前
父节点
当前提交
2d541eca64

+ 1 - 1
packages/core/.vscode/settings.json

@@ -1,3 +1,3 @@
 {
 {
-  "rust-analyzer.inlayHints.enable": true
+  "rust-analyzer.inlayHints.enable": false
 }
 }

+ 37 - 56
packages/core/src/diff.rs

@@ -167,8 +167,10 @@ impl<'bump> DiffMachine<'bump> {
                 DiffInstruction::PopScope => {
                 DiffInstruction::PopScope => {
                     self.stack.pop_scope();
                     self.stack.pop_scope();
                 }
                 }
+
                 DiffInstruction::PopElement => {
                 DiffInstruction::PopElement => {
-                    self.mutations.pop();
+                    todo!();
+                    // self.mutations.pop();
                 }
                 }
 
 
                 DiffInstruction::DiffNode { old, new, .. } => {
                 DiffInstruction::DiffNode { old, new, .. } => {
@@ -179,20 +181,16 @@ impl<'bump> DiffMachine<'bump> {
                     self.diff_children(old, new);
                     self.diff_children(old, new);
                 }
                 }
 
 
-                DiffInstruction::Create { node, and } => {
+                DiffInstruction::Create { node } => {
                     self.create_node(node);
                     self.create_node(node);
                 }
                 }
 
 
                 DiffInstruction::Remove { child } => {
                 DiffInstruction::Remove { child } => {
-                    for child in RealChildIterator::new(child, self.vdom) {
-                        self.mutations.remove(child.direct_id().as_u64());
-                    }
+                    self.remove_nodes(Some(child));
                 }
                 }
 
 
                 DiffInstruction::RemoveChildren { children } => {
                 DiffInstruction::RemoveChildren { children } => {
-                    for child in RealChildIterator::new_from_slice(children, self.vdom) {
-                        self.mutations.remove(child.direct_id().as_u64());
-                    }
+                    self.remove_nodes(children);
                 }
                 }
 
 
                 DiffInstruction::Mount { and } => {
                 DiffInstruction::Mount { and } => {
@@ -204,13 +202,13 @@ impl<'bump> DiffMachine<'bump> {
         Ok(())
         Ok(())
     }
     }
 
 
-    fn mount(&mut self, and: MountType) {
-        let nodes_created = self.stack.nodes_created_stack.pop().unwrap();
+    fn mount(&mut self, and: MountType<'bump>) {
+        let nodes_created = self.stack.pop_nodes_created();
         match and {
         match and {
             // add the nodes from this virtual list to the parent
             // add the nodes from this virtual list to the parent
             // used by fragments and components
             // used by fragments and components
             MountType::Absorb => {
             MountType::Absorb => {
-                *self.stack.nodes_created_stack.last_mut().unwrap() += nodes_created;
+                self.stack.add_child_count(nodes_created);
             }
             }
             MountType::Append => {
             MountType::Append => {
                 self.mutations.edits.push(AppendChildren {
                 self.mutations.edits.push(AppendChildren {
@@ -218,15 +216,21 @@ impl<'bump> DiffMachine<'bump> {
                 });
                 });
             }
             }
             MountType::Replace { old } => {
             MountType::Replace { old } => {
-                todo!()
-                // self.mutations.replace_with(with as u32, many as u32);
+                let root = todo!();
+                self.mutations.replace_with(root, nodes_created as u32);
+            }
+            MountType::ReplaceByElementId { old } => {
+                self.mutations.replace_with(old, nodes_created as u32);
             }
             }
+
             MountType::InsertAfter { other_node } => {
             MountType::InsertAfter { other_node } => {
-                self.mutations.insert_after(nodes_created as u32);
+                let root = self.find_last_element(other_node).direct_id();
+                self.mutations.insert_after(root, nodes_created as u32);
             }
             }
 
 
             MountType::InsertBefore { other_node } => {
             MountType::InsertBefore { other_node } => {
-                self.mutations.insert_before(nodes_created as u32);
+                let root = self.find_first_element(other_node).direct_id();
+                self.mutations.insert_before(root, nodes_created as u32);
             }
             }
         }
         }
     }
     }
@@ -373,17 +377,19 @@ impl<'bump> DiffMachine<'bump> {
         match (old_node, new_node) {
         match (old_node, new_node) {
             // Check the most common cases first
             // Check the most common cases first
             (Text(old), Text(new)) => self.diff_text_nodes(old, new),
             (Text(old), Text(new)) => self.diff_text_nodes(old, new),
-            (Element(old), Element(new)) => self.diff_element_nodes(old, new),
             (Component(old), Component(new)) => self.diff_component_nodes(old, new),
             (Component(old), Component(new)) => self.diff_component_nodes(old, new),
             (Fragment(old), Fragment(new)) => self.diff_fragment_nodes(old, new),
             (Fragment(old), Fragment(new)) => self.diff_fragment_nodes(old, new),
             (Anchor(old), Anchor(new)) => new.dom_id.set(old.dom_id.get()),
             (Anchor(old), Anchor(new)) => new.dom_id.set(old.dom_id.get()),
             (Suspended(old), Suspended(new)) => new.node.set(old.node.get()),
             (Suspended(old), Suspended(new)) => new.node.set(old.node.get()),
+            (Element(old), Element(new)) => self.diff_element_nodes(old, new),
 
 
             // Anything else is just a basic replace and create
             // Anything else is just a basic replace and create
             (
             (
                 Component(_) | Fragment(_) | Text(_) | Element(_) | Anchor(_) | Suspended(_),
                 Component(_) | Fragment(_) | Text(_) | Element(_) | Anchor(_) | Suspended(_),
                 Component(_) | Fragment(_) | Text(_) | Element(_) | Anchor(_) | Suspended(_),
                 Component(_) | Fragment(_) | Text(_) | Element(_) | Anchor(_) | Suspended(_),
-            ) => self.replace_and_create_one_with_one(old_node, new_node),
+            ) => self
+                .stack
+                .create_node(new_node, MountType::Replace { old: old_node }),
         }
         }
     }
     }
 
 
@@ -407,8 +413,8 @@ impl<'bump> DiffMachine<'bump> {
         //
         //
         // This case is rather rare (typically only in non-keyed lists)
         // This case is rather rare (typically only in non-keyed lists)
         if new.tag_name != old.tag_name || new.namespace != old.namespace {
         if new.tag_name != old.tag_name || new.namespace != old.namespace {
-            todo!();
-            // self.replace_node_with_node(root, old_node, new_node);
+            todo!("element changed");
+            // self.replace_node_with_node(old, new);
             return;
             return;
         }
         }
 
 
@@ -779,21 +785,6 @@ impl<'bump> DiffMachine<'bump> {
         KeyedPrefixResult::MoreWorkToDo(shared_prefix_count)
         KeyedPrefixResult::MoreWorkToDo(shared_prefix_count)
     }
     }
 
 
-    // Create the given children and append them to the parent node.
-    //
-    // The parent node must currently be on top of the change list stack:
-    //
-    //     [... parent]
-    //
-    // When this function returns, the change list stack is in the same state.
-    fn create_and_append_children(&mut self, new: &'bump [VNode<'bump>]) {
-        for child in new {
-            todo!();
-            // let meta = self.create_vnode(child);
-            // self.mutations.append_children(meta.added_to_stack);
-        }
-    }
-
     // The most-general, expensive code path for keyed children diffing.
     // The most-general, expensive code path for keyed children diffing.
     //
     //
     // We find the longest subsequence within `old` of children that are relatively
     // We find the longest subsequence within `old` of children that are relatively
@@ -957,12 +948,12 @@ impl<'bump> DiffMachine<'bump> {
                             self.mutations.insert_before(1);
                             self.mutations.insert_before(1);
                         }
                         }
                     } else {
                     } else {
-                        self.stack.push(DiffInstruction::Create {
-                            node: next_new,
-                            and: MountType::InsertBefore {
-                                other_node: Some(new_anchor),
+                        self.stack.create_node(
+                            next_new,
+                            MountType::InsertBefore {
+                                other_node: new_anchor,
                             },
                             },
-                        });
+                        );
                     }
                     }
                 }
                 }
             }
             }
@@ -1081,7 +1072,7 @@ impl<'bump> DiffMachine<'bump> {
                 self.stack.create_children(
                 self.stack.create_children(
                     &new[old.len()..],
                     &new[old.len()..],
                     MountType::InsertAfter {
                     MountType::InsertAfter {
-                        other_node: old.last(),
+                        other_node: old.last().unwrap(),
                     },
                     },
                 );
                 );
             }
             }
@@ -1098,6 +1089,10 @@ impl<'bump> DiffMachine<'bump> {
         }
         }
     }
     }
 
 
+    // =====================
+    //  Utilities
+    // =====================
+
     fn find_last_element(&mut self, vnode: &'bump VNode<'bump>) -> &'bump VNode<'bump> {
     fn find_last_element(&mut self, vnode: &'bump VNode<'bump>) -> &'bump VNode<'bump> {
         let mut search_node = Some(vnode);
         let mut search_node = Some(vnode);
 
 
@@ -1144,18 +1139,6 @@ impl<'bump> DiffMachine<'bump> {
         }
         }
     }
     }
 
 
-    // fn remove_child(&mut self, node: &'bump VNode<'bump>) {
-    //     self.replace_and_create_many_with_many(Some(node), None);
-    // }
-
-    fn replace_and_create_one_with_one(
-        &mut self,
-        old: &'bump VNode<'bump>,
-        new: &'bump VNode<'bump>,
-    ) {
-        self.stack.create_node(new, MountType::Replace { old });
-    }
-
     fn replace_many_with_many(&mut self, old: &'bump [VNode<'bump>], new: &'bump [VNode<'bump>]) {
     fn replace_many_with_many(&mut self, old: &'bump [VNode<'bump>], new: &'bump [VNode<'bump>]) {
         //
         //
     }
     }
@@ -1316,10 +1299,8 @@ impl<'bump> DiffMachine<'bump> {
         old_node: &'bump VNode<'bump>,
         old_node: &'bump VNode<'bump>,
         new_node: &'bump VNode<'bump>,
         new_node: &'bump VNode<'bump>,
     ) {
     ) {
-        self.stack.instructions.push(DiffInstruction::Create {
-            and: MountType::Replace { old: old_node },
-            node: new_node,
-        });
+        self.stack
+            .create_node(new_node, MountType::Replace { old: old_node });
     }
     }
 
 
     fn fix_listener<'a>(&mut self, listener: &'a Listener<'a>) {
     fn fix_listener<'a>(&mut self, listener: &'a Listener<'a>) {

+ 13 - 15
packages/core/src/diff_stack.rs

@@ -16,7 +16,6 @@ pub enum DiffInstruction<'a> {
 
 
     Create {
     Create {
         node: &'a VNode<'a>,
         node: &'a VNode<'a>,
-        and: MountType<'a>,
     },
     },
 
 
     Remove {
     Remove {
@@ -41,13 +40,14 @@ pub enum MountType<'a> {
     Absorb,
     Absorb,
     Append,
     Append,
     Replace { old: &'a VNode<'a> },
     Replace { old: &'a VNode<'a> },
-    InsertAfter { other_node: Option<&'a VNode<'a>> },
-    InsertBefore { other_node: Option<&'a VNode<'a>> },
+    ReplaceByElementId { old: ElementId },
+    InsertAfter { other_node: &'a VNode<'a> },
+    InsertBefore { other_node: &'a VNode<'a> },
 }
 }
 
 
 pub struct DiffStack<'bump> {
 pub struct DiffStack<'bump> {
-    pub instructions: Vec<DiffInstruction<'bump>>,
-    pub nodes_created_stack: SmallVec<[usize; 10]>,
+    instructions: Vec<DiffInstruction<'bump>>,
+    nodes_created_stack: SmallVec<[usize; 10]>,
     pub scope_stack: SmallVec<[ScopeId; 5]>,
     pub scope_stack: SmallVec<[ScopeId; 5]>,
 }
 }
 
 
@@ -77,24 +77,25 @@ impl<'bump> DiffStack<'bump> {
         self.instructions.push(DiffInstruction::Mount { and });
         self.instructions.push(DiffInstruction::Mount { and });
 
 
         for child in children.into_iter().rev() {
         for child in children.into_iter().rev() {
-            self.instructions.push(DiffInstruction::Create {
-                and: MountType::Absorb,
-                node: child,
-            });
+            self.instructions
+                .push(DiffInstruction::Create { node: child });
         }
         }
     }
     }
 
 
     pub fn create_node(&mut self, node: &'bump VNode<'bump>, and: MountType<'bump>) {
     pub fn create_node(&mut self, node: &'bump VNode<'bump>, and: MountType<'bump>) {
         self.nodes_created_stack.push(0);
         self.nodes_created_stack.push(0);
         self.instructions.push(DiffInstruction::Mount { and });
         self.instructions.push(DiffInstruction::Mount { and });
-        self.instructions
-            .push(DiffInstruction::Create { and, node });
+        self.instructions.push(DiffInstruction::Create { node });
     }
     }
 
 
     pub fn add_child_count(&mut self, count: usize) {
     pub fn add_child_count(&mut self, count: usize) {
         *self.nodes_created_stack.last_mut().unwrap() += count;
         *self.nodes_created_stack.last_mut().unwrap() += count;
     }
     }
 
 
+    pub fn pop_nodes_created(&mut self) -> usize {
+        self.nodes_created_stack.pop().unwrap()
+    }
+
     pub fn current_scope(&self) -> Option<ScopeId> {
     pub fn current_scope(&self) -> Option<ScopeId> {
         self.scope_stack.last().map(|f| f.clone())
         self.scope_stack.last().map(|f| f.clone())
     }
     }
@@ -107,9 +108,6 @@ impl<'bump> DiffStack<'bump> {
 
 
         // Run the creation algorithm with this scope on the stack
         // Run the creation algorithm with this scope on the stack
         // ?? I think we treat components as framgnets??
         // ?? I think we treat components as framgnets??
-        self.instructions.push(DiffInstruction::Create {
-            node,
-            and: MountType::Absorb,
-        });
+        self.instructions.push(DiffInstruction::Create { node });
     }
     }
 }
 }

+ 8 - 1
packages/core/src/editor.rs → packages/core/src/dom_edits.rs

@@ -20,22 +20,29 @@ pub enum DomEdit<'bump> {
         id: u64,
         id: u64,
     },
     },
     PopRoot,
     PopRoot,
+
     AppendChildren {
     AppendChildren {
         many: u32,
         many: u32,
     },
     },
+
+    // "Root" refers to the item direclty
+    // it's a waste of an instruction to push the root directly
     ReplaceWith {
     ReplaceWith {
+        root: u64,
         m: u32,
         m: u32,
     },
     },
     InsertAfter {
     InsertAfter {
+        root: u64,
         n: u32,
         n: u32,
     },
     },
     InsertBefore {
     InsertBefore {
+        root: u64,
         n: u32,
         n: u32,
     },
     },
-    // remove roots directly
     Remove {
     Remove {
         root: u64,
         root: u64,
     },
     },
+
     RemoveAllChildren,
     RemoveAllChildren,
     CreateTextNode {
     CreateTextNode {
         text: &'bump str,
         text: &'bump str,

+ 5 - 5
packages/core/src/lib.rs

@@ -11,9 +11,9 @@
 //!
 //!
 
 
 pub use crate::innerlude::{
 pub use crate::innerlude::{
-    format_args_f, html, rsx, Context, DioxusElement, DomEdit, DomTree, ElementId, EventPriority,
-    EventTrigger, LazyNodes, Mutations, NodeFactory, Properties, ScopeId, SuspendedContext, VNode,
-    VirtualDom, VirtualEvent, FC,
+    format_args_f, html, rsx, Context, DiffInstruction, DioxusElement, DomEdit, DomTree, ElementId,
+    EventPriority, EventTrigger, LazyNodes, MountType, Mutations, NodeFactory, Properties, ScopeId,
+    SuspendedContext, VNode, VirtualDom, VirtualEvent, FC,
 };
 };
 
 
 pub mod prelude {
 pub mod prelude {
@@ -35,7 +35,7 @@ pub(crate) mod innerlude {
     pub use crate::context::*;
     pub use crate::context::*;
     pub use crate::diff::*;
     pub use crate::diff::*;
     pub use crate::diff_stack::*;
     pub use crate::diff_stack::*;
-    pub use crate::editor::*;
+    pub use crate::dom_edits::*;
     pub use crate::error::*;
     pub use crate::error::*;
     pub use crate::events::*;
     pub use crate::events::*;
     pub use crate::heuristics::*;
     pub use crate::heuristics::*;
@@ -67,7 +67,7 @@ pub mod component;
 pub mod context;
 pub mod context;
 pub mod diff;
 pub mod diff;
 pub mod diff_stack;
 pub mod diff_stack;
-pub mod editor;
+pub mod dom_edits;
 pub mod error;
 pub mod error;
 pub mod events;
 pub mod events;
 pub mod heuristics;
 pub mod heuristics;

+ 9 - 6
packages/core/src/mutations.rs

@@ -31,16 +31,19 @@ impl<'a> Mutations<'a> {
         self.edits.push(PopRoot {});
         self.edits.push(PopRoot {});
     }
     }
 
 
-    pub(crate) fn replace_with(&mut self, m: u32) {
-        self.edits.push(ReplaceWith { m });
+    pub(crate) fn replace_with(&mut self, root: ElementId, m: u32) {
+        let root = root.as_u64();
+        self.edits.push(ReplaceWith { m, root });
     }
     }
 
 
-    pub(crate) fn insert_after(&mut self, n: u32) {
-        self.edits.push(InsertAfter { n });
+    pub(crate) fn insert_after(&mut self, root: ElementId, n: u32) {
+        let root = root.as_u64();
+        self.edits.push(InsertAfter { n, root });
     }
     }
 
 
-    pub(crate) fn insert_before(&mut self, n: u32) {
-        self.edits.push(InsertBefore { n });
+    pub(crate) fn insert_before(&mut self, root: ElementId, n: u32) {
+        let root = root.as_u64();
+        self.edits.push(InsertBefore { n, root });
     }
     }
 
 
     // Remove Nodesfrom the dom
     // Remove Nodesfrom the dom

+ 3 - 4
packages/core/src/virtual_dom.rs

@@ -173,10 +173,9 @@ impl VirtualDom {
 
 
         // // We run the component. If it succeeds, then we can diff it and add the changes to the dom.
         // // We run the component. If it succeeds, then we can diff it and add the changes to the dom.
         if cur_component.run_scope().is_ok() {
         if cur_component.run_scope().is_ok() {
-            diff_machine.stack.push(DiffInstruction::Create {
-                node: cur_component.frames.fin_head(),
-                and: MountType::Append,
-            });
+            diff_machine
+                .stack
+                .create_node(cur_component.frames.fin_head(), MountType::Append);
             diff_machine.work().await.unwrap();
             diff_machine.work().await.unwrap();
         } else {
         } else {
             // todo: should this be a hard error?
             // todo: should this be a hard error?

+ 161 - 17
packages/core/tests/create_iterative.rs

@@ -1,16 +1,11 @@
 //! tests to prove that the iterative implementation works
 //! tests to prove that the iterative implementation works
 
 
 use anyhow::{Context, Result};
 use anyhow::{Context, Result};
-use dioxus::{
-    arena::SharedResources,
-    diff::{CreateMeta, DiffMachine},
-    prelude::*,
-    scheduler::Mutations,
-    DomEdit,
-};
+use dioxus::{arena::SharedResources, diff::DiffMachine, prelude::*, DomEdit, Mutations};
 mod test_logging;
 mod test_logging;
 use dioxus_core as dioxus;
 use dioxus_core as dioxus;
 use dioxus_html as dioxus_elements;
 use dioxus_html as dioxus_elements;
+use DomEdit::*;
 
 
 #[test]
 #[test]
 fn test_original_diff() {
 fn test_original_diff() {
@@ -26,11 +21,24 @@ fn test_original_diff() {
 
 
     let mut dom = VirtualDom::new(App);
     let mut dom = VirtualDom::new(App);
     let mutations = dom.rebuild().unwrap();
     let mutations = dom.rebuild().unwrap();
-    dbg!(mutations);
+    assert_eq!(
+        mutations.edits,
+        [
+            CreateElement { id: 0, tag: "div" },
+            CreateElement { id: 1, tag: "div" },
+            CreateTextNode {
+                id: 2,
+                text: "Hello, world!"
+            },
+            AppendChildren { many: 1 },
+            AppendChildren { many: 1 },
+            AppendChildren { many: 1 },
+        ]
+    );
 }
 }
 
 
 #[async_std::test]
 #[async_std::test]
-async fn test_iterative_create() {
+async fn create() {
     static App: FC<()> = |cx| {
     static App: FC<()> = |cx| {
         cx.render(rsx! {
         cx.render(rsx! {
             div {
             div {
@@ -50,14 +58,38 @@ async fn test_iterative_create() {
     };
     };
 
 
     test_logging::set_up_logging();
     test_logging::set_up_logging();
-
     let mut dom = VirtualDom::new(App);
     let mut dom = VirtualDom::new(App);
     let mutations = dom.rebuild_async().await.unwrap();
     let mutations = dom.rebuild_async().await.unwrap();
-    dbg!(mutations);
+    assert_eq!(
+        mutations.edits,
+        [
+            CreateElement { id: 0, tag: "div" },
+            CreateElement { id: 1, tag: "div" },
+            CreateTextNode {
+                id: 2,
+                text: "Hello, world!"
+            },
+            CreateElement { id: 3, tag: "div" },
+            CreateElement { id: 4, tag: "div" },
+            CreateTextNode {
+                id: 5,
+                text: "hello"
+            },
+            CreateTextNode {
+                id: 6,
+                text: "world"
+            },
+            AppendChildren { many: 2 },
+            AppendChildren { many: 1 },
+            AppendChildren { many: 2 },
+            AppendChildren { many: 1 },
+            AppendChildren { many: 1 },
+        ]
+    );
 }
 }
 
 
 #[async_std::test]
 #[async_std::test]
-async fn test_iterative_create_list() {
+async fn create_list() {
     static App: FC<()> = |cx| {
     static App: FC<()> = |cx| {
         cx.render(rsx! {
         cx.render(rsx! {
             {(0..3).map(|f| rsx!{ div {
             {(0..3).map(|f| rsx!{ div {
@@ -70,11 +102,36 @@ async fn test_iterative_create_list() {
 
 
     let mut dom = VirtualDom::new(App);
     let mut dom = VirtualDom::new(App);
     let mutations = dom.rebuild_async().await.unwrap();
     let mutations = dom.rebuild_async().await.unwrap();
-    dbg!(mutations);
+
+    // copilot wrote this test :P
+    assert_eq!(
+        mutations.edits,
+        [
+            CreateElement { id: 0, tag: "div" },
+            CreateTextNode {
+                id: 1,
+                text: "hello"
+            },
+            AppendChildren { many: 1 },
+            CreateElement { id: 2, tag: "div" },
+            CreateTextNode {
+                id: 3,
+                text: "hello"
+            },
+            AppendChildren { many: 1 },
+            CreateElement { id: 4, tag: "div" },
+            CreateTextNode {
+                id: 5,
+                text: "hello"
+            },
+            AppendChildren { many: 1 },
+            AppendChildren { many: 3 },
+        ]
+    );
 }
 }
 
 
 #[async_std::test]
 #[async_std::test]
-async fn test_iterative_create_simple() {
+async fn create_simple() {
     static App: FC<()> = |cx| {
     static App: FC<()> = |cx| {
         cx.render(rsx! {
         cx.render(rsx! {
             div {}
             div {}
@@ -88,11 +145,22 @@ async fn test_iterative_create_simple() {
 
 
     let mut dom = VirtualDom::new(App);
     let mut dom = VirtualDom::new(App);
     let mutations = dom.rebuild_async().await.unwrap();
     let mutations = dom.rebuild_async().await.unwrap();
-    dbg!(mutations);
+
+    // copilot wrote this test :P
+    assert_eq!(
+        mutations.edits,
+        [
+            CreateElement { id: 0, tag: "div" },
+            CreateElement { id: 1, tag: "div" },
+            CreateElement { id: 2, tag: "div" },
+            CreateElement { id: 3, tag: "div" },
+            AppendChildren { many: 4 },
+        ]
+    );
 }
 }
 
 
 #[async_std::test]
 #[async_std::test]
-async fn test_iterative_create_components() {
+async fn create_components() {
     static App: FC<()> = |cx| {
     static App: FC<()> = |cx| {
         cx.render(rsx! {
         cx.render(rsx! {
             Child { "abc1" }
             Child { "abc1" }
@@ -113,5 +181,81 @@ async fn test_iterative_create_components() {
 
 
     let mut dom = VirtualDom::new(App);
     let mut dom = VirtualDom::new(App);
     let mutations = dom.rebuild_async().await.unwrap();
     let mutations = dom.rebuild_async().await.unwrap();
-    dbg!(mutations);
+
+    assert_eq!(
+        mutations.edits,
+        [
+            CreateElement { id: 0, tag: "h1" },
+            CreateElement { id: 1, tag: "div" },
+            CreateTextNode {
+                id: 2,
+                text: "abc1"
+            },
+            AppendChildren { many: 1 },
+            CreateElement { id: 3, tag: "p" },
+            CreateElement { id: 4, tag: "h1" },
+            CreateElement { id: 5, tag: "div" },
+            CreateTextNode {
+                id: 6,
+                text: "abc2"
+            },
+            AppendChildren { many: 1 },
+            CreateElement { id: 7, tag: "p" },
+            CreateElement { id: 8, tag: "h1" },
+            CreateElement { id: 9, tag: "div" },
+            CreateTextNode {
+                id: 10,
+                text: "abc3"
+            },
+            AppendChildren { many: 1 },
+            CreateElement { id: 11, tag: "p" },
+            AppendChildren { many: 9 },
+        ]
+    );
+}
+
+#[async_std::test]
+async fn anchors() {
+    static App: FC<()> = |cx| {
+        cx.render(rsx! {
+            {true.then(|| rsx!{ div { "hello" } })}
+            {false.then(|| rsx!{ div { "goodbye" } })}
+        })
+    };
+
+    test_logging::set_up_logging();
+
+    let mut dom = VirtualDom::new(App);
+    let mutations = dom.rebuild_async().await.unwrap();
+    assert_eq!(
+        mutations.edits,
+        [
+            CreateElement { id: 0, tag: "div" },
+            CreateTextNode {
+                id: 1,
+                text: "hello"
+            },
+            AppendChildren { many: 1 },
+            CreatePlaceholder { id: 2 },
+            AppendChildren { many: 2 },
+        ]
+    );
+}
+
+#[async_std::test]
+async fn suspended() {
+    static App: FC<()> = |cx| {
+        let val = use_suspense(cx, || async {}, |cx, _| cx.render(rsx! { "hi "}));
+        cx.render(rsx! { {val} })
+    };
+
+    test_logging::set_up_logging();
+
+    let mut dom = VirtualDom::new(App);
+    let mutations = dom.rebuild_async().await.unwrap();
+
+    assert_eq!(
+        mutations.edits,
+        [CreatePlaceholder { id: 0 }, AppendChildren { many: 1 },]
+    );
 }
 }

+ 7 - 15
packages/core/tests/diffing.rs

@@ -8,10 +8,7 @@ use bumpalo::Bump;
 
 
 use anyhow::{Context, Result};
 use anyhow::{Context, Result};
 use dioxus::{
 use dioxus::{
-    arena::SharedResources,
-    diff::{DiffInstruction, DiffMachine},
-    prelude::*,
-    DomEdit,
+    arena::SharedResources, diff::DiffMachine, prelude::*, DiffInstruction, DomEdit, MountType,
 };
 };
 use dioxus_core as dioxus;
 use dioxus_core as dioxus;
 use dioxus_html as dioxus_elements;
 use dioxus_html as dioxus_elements;
@@ -43,9 +40,7 @@ impl TestDom {
         // let mut edits = Vec::new();
         // let mut edits = Vec::new();
         let mut machine = DiffMachine::new_headless(&self.resources);
         let mut machine = DiffMachine::new_headless(&self.resources);
 
 
-        machine
-            .stack
-            .push(dioxus::diff::DiffInstruction::DiffNode { new, old });
+        machine.stack.push(DiffInstruction::DiffNode { new, old });
 
 
         machine.mutations
         machine.mutations
     }
     }
@@ -58,10 +53,8 @@ impl TestDom {
 
 
         let mut machine = DiffMachine::new_headless(&self.resources);
         let mut machine = DiffMachine::new_headless(&self.resources);
 
 
-        machine.stack.push(dioxus::diff::DiffInstruction::Create {
-            node: old,
-            and: dioxus::diff::MountType::Append,
-        });
+        machine.stack.create_node(old, MountType::Append);
+
         work_sync(&mut machine);
         work_sync(&mut machine);
 
 
         machine.mutations
         machine.mutations
@@ -83,10 +76,9 @@ impl TestDom {
         // let mut create_edits = Vec::new();
         // let mut create_edits = Vec::new();
 
 
         let mut machine = DiffMachine::new_headless(&self.resources);
         let mut machine = DiffMachine::new_headless(&self.resources);
-        machine.stack.push(dioxus::diff::DiffInstruction::Create {
-            and: dioxus::diff::MountType::Append,
-            node: old,
-        });
+
+        machine.stack.create_node(old, MountType::Append);
+
         work_sync(&mut machine);
         work_sync(&mut machine);
         let create_edits = machine.mutations;
         let create_edits = machine.mutations;
 
 

+ 1 - 6
packages/core/tests/eventsystem.rs

@@ -1,12 +1,7 @@
 use bumpalo::Bump;
 use bumpalo::Bump;
 
 
 use anyhow::{Context, Result};
 use anyhow::{Context, Result};
-use dioxus::{
-    arena::SharedResources,
-    diff::{CreateMeta, DiffMachine},
-    prelude::*,
-    DomEdit,
-};
+use dioxus::{arena::SharedResources, diff::DiffMachine, prelude::*, DomEdit};
 use dioxus_core as dioxus;
 use dioxus_core as dioxus;
 use dioxus_html as dioxus_elements;
 use dioxus_html as dioxus_elements;
 
 

+ 1 - 6
packages/core/tests/hooks.rs

@@ -1,10 +1,5 @@
 use anyhow::{Context, Result};
 use anyhow::{Context, Result};
-use dioxus::{
-    arena::SharedResources,
-    diff::{CreateMeta, DiffMachine},
-    prelude::*,
-    DomEdit,
-};
+use dioxus::{arena::SharedResources, diff::DiffMachine, prelude::*, DomEdit};
 use dioxus_core as dioxus;
 use dioxus_core as dioxus;
 use dioxus_html as dioxus_elements;
 use dioxus_html as dioxus_elements;
 
 

+ 4 - 3
packages/core/tests/test_logging.rs

@@ -17,7 +17,9 @@ pub fn set_up_logging() {
     // just clone `colors_line` and overwrite our changes
     // just clone `colors_line` and overwrite our changes
     let colors_level = colors_line.clone().info(Color::Green);
     let colors_level = colors_line.clone().info(Color::Green);
     // here we set up our fern Dispatch
     // here we set up our fern Dispatch
-    fern::Dispatch::new()
+
+    // when running tests in batch, the logger is re-used, so ignore the logger error
+    let _ = fern::Dispatch::new()
         .format(move |out, message, record| {
         .format(move |out, message, record| {
             out.finish(format_args!(
             out.finish(format_args!(
                 "{color_line}[{level}{color_line}] {message}\x1B[0m",
                 "{color_line}[{level}{color_line}] {message}\x1B[0m",
@@ -42,6 +44,5 @@ pub fn set_up_logging() {
         // .level_for("pretty_colored", log::LevelFilter::Trace)
         // .level_for("pretty_colored", log::LevelFilter::Trace)
         // output to stdout
         // output to stdout
         .chain(std::io::stdout())
         .chain(std::io::stdout())
-        .apply()
-        .unwrap();
+        .apply();
 }
 }

+ 1 - 6
packages/core/tests/work_sync.rs

@@ -3,12 +3,7 @@
 //! This means you can actually call it synchronously if you want.
 //! This means you can actually call it synchronously if you want.
 
 
 use anyhow::{Context, Result};
 use anyhow::{Context, Result};
-use dioxus::{
-    arena::SharedResources,
-    diff::{CreateMeta, DiffInstruction, DiffMachine},
-    prelude::*,
-    scope::Scope,
-};
+use dioxus::{arena::SharedResources, diff::DiffMachine, prelude::*, scope::Scope};
 use dioxus_core as dioxus;
 use dioxus_core as dioxus;
 use dioxus_html as dioxus_elements;
 use dioxus_html as dioxus_elements;
 use futures_util::FutureExt;
 use futures_util::FutureExt;