Jonathan Kelley 3 лет назад
Родитель
Сommit
64f289a

+ 107 - 103
packages/core/src/diff.rs

@@ -85,7 +85,9 @@ use DomEdit::*;
 /// was origially implemented using recursive techniques, but Rust lacks the abilty to call async functions recursively,
 /// meaning we could not "pause" the diffing algorithm.
 ///
-/// Instead, we use a traditional stack machine approach to diff and create new nodes.
+/// Instead, we use a traditional stack machine approach to diff and create new nodes. The diff algorithm periodically
+/// calls "yield_now" which allows the machine to pause and return control to the caller. The caller can then wait for
+/// the next period of idle time, preventing our diff algorithm from blocking the maint thread.
 pub struct DiffMachine<'bump> {
     vdom: &'bump SharedResources,
 
@@ -187,27 +189,27 @@ impl<'bump> DiffMachine<'bump> {
                 }
 
                 DiffInstruction::Create { node, .. } => {
-                    match &node.kind {
-                        VNodeKind::Text(text) => {
+                    match &node {
+                        VNode::Text(text) => {
                             let real_id = self.vdom.reserve_node();
                             self.edit_create_text_node(text.text, real_id);
                             text.dom_id.set(Some(real_id));
                             *self.nodes_created_stack.last_mut().unwrap() += 1;
                         }
-                        VNodeKind::Suspended(suspended) => {
+                        VNode::Suspended(suspended) => {
                             let real_id = self.vdom.reserve_node();
                             self.edit_create_placeholder(real_id);
                             suspended.node.set(Some(real_id));
                             *self.nodes_created_stack.last_mut().unwrap() += 1;
                         }
-                        VNodeKind::Anchor(anchor) => {
+                        VNode::Anchor(anchor) => {
                             let real_id = self.vdom.reserve_node();
                             self.edit_create_placeholder(real_id);
                             anchor.dom_id.set(Some(real_id));
                             *self.nodes_created_stack.last_mut().unwrap() += 1;
                         }
 
-                        VNodeKind::Element(el) => {
+                        VNode::Element(el) => {
                             let VElement {
                                 tag_name,
                                 listeners,
@@ -218,6 +220,7 @@ impl<'bump> DiffMachine<'bump> {
                                 static_children: _,
                                 static_listeners: _,
                                 dom_id,
+                                key,
                             } = el;
 
                             let real_id = self.vdom.reserve_node();
@@ -250,13 +253,13 @@ impl<'bump> DiffMachine<'bump> {
                             }
                         }
 
-                        VNodeKind::Fragment(frag) => {
+                        VNode::Fragment(frag) => {
                             for node in frag.children {
                                 self.node_stack.push(DiffInstruction::Create { node })
                             }
                         }
 
-                        VNodeKind::Component(_) => {
+                        VNode::Component(_) => {
                             //
                         }
                     }
@@ -267,50 +270,52 @@ impl<'bump> DiffMachine<'bump> {
         Ok(())
     }
 
+    fn create_text_node(&mut self) {}
+
     /// Create the new node, pushing instructions on our instruction stack to create any further children
     ///
     ///
     pub fn create_iterative(&mut self, node: &'bump VNode<'bump>) {
-        match &node.kind {
+        match &node {
             // singles
             // update the parent
-            VNodeKind::Text(text) => {
+            VNode::Text(text) => {
                 let real_id = self.vdom.reserve_node();
                 self.edit_create_text_node(text.text, real_id);
                 text.dom_id.set(Some(real_id));
                 *self.nodes_created_stack.last_mut().unwrap() += 1;
             }
-            VNodeKind::Suspended(suspended) => {
+            VNode::Suspended(suspended) => {
                 let real_id = self.vdom.reserve_node();
                 self.edit_create_placeholder(real_id);
                 suspended.node.set(Some(real_id));
                 *self.nodes_created_stack.last_mut().unwrap() += 1;
             }
-            VNodeKind::Anchor(anchor) => {
+            VNode::Anchor(anchor) => {
                 let real_id = self.vdom.reserve_node();
                 self.edit_create_placeholder(real_id);
                 anchor.dom_id.set(Some(real_id));
                 *self.nodes_created_stack.last_mut().unwrap() += 1;
             }
 
-            VNodeKind::Element(el) => {
+            VNode::Element(el) => {
                 //
             }
-            VNodeKind::Fragment(frag) => {
+            VNode::Fragment(frag) => {
                 //
             }
-            VNodeKind::Component(comp) => {
+            VNode::Component(comp) => {
                 //
             }
         }
     }
 
     pub fn diff_iterative(&mut self, old_node: &'bump VNode<'bump>, new_node: &'bump VNode<'bump>) {
-        match (&old_node.kind, &new_node.kind) {
+        match (&old_node, &new_node) {
             // Handle the "sane" cases first.
             // The rsx and html macros strongly discourage dynamic lists not encapsulated by a "Fragment".
             // So the sane (and fast!) cases are where the virtual structure stays the same and is easily diffable.
-            (VNodeKind::Text(old), VNodeKind::Text(new)) => {
+            (VNode::Text(old), VNode::Text(new)) => {
                 let root = old_node.direct_id();
 
                 if old.text != new.text {
@@ -322,7 +327,7 @@ impl<'bump> DiffMachine<'bump> {
                 new.dom_id.set(Some(root));
             }
 
-            (VNodeKind::Element(old), VNodeKind::Element(new)) => {
+            (VNode::Element(old), VNode::Element(new)) => {
                 let root = old_node.direct_id();
 
                 // If the element type is completely different, the element needs to be re-rendered completely
@@ -409,7 +414,7 @@ impl<'bump> DiffMachine<'bump> {
                 self.diff_children(old.children, new.children);
             }
 
-            (VNodeKind::Component(old), VNodeKind::Component(new)) => {
+            (VNode::Component(old), VNode::Component(new)) => {
                 let scope_addr = old.ass_scope.get().unwrap();
 
                 // Make sure we're dealing with the same component (by function pointer)
@@ -464,7 +469,7 @@ impl<'bump> DiffMachine<'bump> {
                 }
             }
 
-            (VNodeKind::Fragment(old), VNodeKind::Fragment(new)) => {
+            (VNode::Fragment(old), VNode::Fragment(new)) => {
                 // This is the case where options or direct vnodes might be used.
                 // In this case, it's faster to just skip ahead to their diff
                 if old.children.len() == 1 && new.children.len() == 1 {
@@ -475,7 +480,7 @@ impl<'bump> DiffMachine<'bump> {
                 self.diff_children(old.children, new.children);
             }
 
-            (VNodeKind::Anchor(old), VNodeKind::Anchor(new)) => {
+            (VNode::Anchor(old), VNode::Anchor(new)) => {
                 new.dom_id.set(old.dom_id.get());
             }
 
@@ -487,27 +492,27 @@ impl<'bump> DiffMachine<'bump> {
             // This likely isn't the fastest way to go about replacing one node with a virtual node, but the "insane" cases
             // are pretty rare.  IE replacing a list (component or fragment) with a single node.
             (
-                VNodeKind::Component(_)
-                | VNodeKind::Fragment(_)
-                | VNodeKind::Text(_)
-                | VNodeKind::Element(_)
-                | VNodeKind::Anchor(_),
-                VNodeKind::Component(_)
-                | VNodeKind::Fragment(_)
-                | VNodeKind::Text(_)
-                | VNodeKind::Element(_)
-                | VNodeKind::Anchor(_),
+                VNode::Component(_)
+                | VNode::Fragment(_)
+                | VNode::Text(_)
+                | VNode::Element(_)
+                | VNode::Anchor(_),
+                VNode::Component(_)
+                | VNode::Fragment(_)
+                | VNode::Text(_)
+                | VNode::Element(_)
+                | VNode::Anchor(_),
             ) => {
                 self.replace_and_create_many_with_many([old_node], [new_node]);
             }
 
             // TODO
-            (VNodeKind::Suspended(old), new) => {
+            (VNode::Suspended(old), new) => {
                 //
                 self.replace_and_create_many_with_many([old_node], [new_node]);
             }
             // a node that was once real is now suspended
-            (old, VNodeKind::Suspended(_)) => {
+            (old, VNode::Suspended(_)) => {
                 //
                 self.replace_and_create_many_with_many([old_node], [new_node]);
             }
@@ -521,11 +526,11 @@ impl<'bump> DiffMachine<'bump> {
     //
     // each function call assumes the stack is fresh (empty).
     pub fn diff_node(&mut self, old_node: &'bump VNode<'bump>, new_node: &'bump VNode<'bump>) {
-        match (&old_node.kind, &new_node.kind) {
+        match (&old_node, &new_node) {
             // Handle the "sane" cases first.
             // The rsx and html macros strongly discourage dynamic lists not encapsulated by a "Fragment".
             // So the sane (and fast!) cases are where the virtual structure stays the same and is easily diffable.
-            (VNodeKind::Text(old), VNodeKind::Text(new)) => {
+            (VNode::Text(old), VNode::Text(new)) => {
                 let root = old_node.direct_id();
 
                 if old.text != new.text {
@@ -537,7 +542,7 @@ impl<'bump> DiffMachine<'bump> {
                 new.dom_id.set(Some(root));
             }
 
-            (VNodeKind::Element(old), VNodeKind::Element(new)) => {
+            (VNode::Element(old), VNode::Element(new)) => {
                 let root = old_node.direct_id();
 
                 // If the element type is completely different, the element needs to be re-rendered completely
@@ -624,7 +629,7 @@ impl<'bump> DiffMachine<'bump> {
                 self.diff_children(old.children, new.children);
             }
 
-            (VNodeKind::Component(old), VNodeKind::Component(new)) => {
+            (VNode::Component(old), VNode::Component(new)) => {
                 let scope_addr = old.ass_scope.get().unwrap();
 
                 // Make sure we're dealing with the same component (by function pointer)
@@ -679,7 +684,7 @@ impl<'bump> DiffMachine<'bump> {
                 }
             }
 
-            (VNodeKind::Fragment(old), VNodeKind::Fragment(new)) => {
+            (VNode::Fragment(old), VNode::Fragment(new)) => {
                 // This is the case where options or direct vnodes might be used.
                 // In this case, it's faster to just skip ahead to their diff
                 if old.children.len() == 1 && new.children.len() == 1 {
@@ -690,7 +695,7 @@ impl<'bump> DiffMachine<'bump> {
                 self.diff_children(old.children, new.children);
             }
 
-            (VNodeKind::Anchor(old), VNodeKind::Anchor(new)) => {
+            (VNode::Anchor(old), VNode::Anchor(new)) => {
                 new.dom_id.set(old.dom_id.get());
             }
 
@@ -702,27 +707,27 @@ impl<'bump> DiffMachine<'bump> {
             // This likely isn't the fastest way to go about replacing one node with a virtual node, but the "insane" cases
             // are pretty rare.  IE replacing a list (component or fragment) with a single node.
             (
-                VNodeKind::Component(_)
-                | VNodeKind::Fragment(_)
-                | VNodeKind::Text(_)
-                | VNodeKind::Element(_)
-                | VNodeKind::Anchor(_),
-                VNodeKind::Component(_)
-                | VNodeKind::Fragment(_)
-                | VNodeKind::Text(_)
-                | VNodeKind::Element(_)
-                | VNodeKind::Anchor(_),
+                VNode::Component(_)
+                | VNode::Fragment(_)
+                | VNode::Text(_)
+                | VNode::Element(_)
+                | VNode::Anchor(_),
+                VNode::Component(_)
+                | VNode::Fragment(_)
+                | VNode::Text(_)
+                | VNode::Element(_)
+                | VNode::Anchor(_),
             ) => {
                 self.replace_and_create_many_with_many([old_node], [new_node]);
             }
 
             // TODO
-            (VNodeKind::Suspended(old), new) => {
+            (VNode::Suspended(old), new) => {
                 //
                 self.replace_and_create_many_with_many([old_node], [new_node]);
             }
             // a node that was once real is now suspended
-            (old, VNodeKind::Suspended(_)) => {
+            (old, VNode::Suspended(_)) => {
                 //
                 self.replace_and_create_many_with_many([old_node], [new_node]);
             }
@@ -739,22 +744,22 @@ impl<'bump> DiffMachine<'bump> {
     //
     //     [... node]
     pub fn create_vnode(&mut self, node: &'bump VNode<'bump>) -> CreateMeta {
-        match &node.kind {
-            VNodeKind::Text(text) => {
+        match &node {
+            VNode::Text(text) => {
                 let real_id = self.vdom.reserve_node();
                 self.edit_create_text_node(text.text, real_id);
                 text.dom_id.set(Some(real_id));
                 CreateMeta::new(text.is_static, 1)
             }
 
-            VNodeKind::Anchor(anchor) => {
+            VNode::Anchor(anchor) => {
                 let real_id = self.vdom.reserve_node();
                 self.edit_create_placeholder(real_id);
                 anchor.dom_id.set(Some(real_id));
                 CreateMeta::new(false, 1)
             }
 
-            VNodeKind::Element(el) => {
+            VNode::Element(el) => {
                 // we have the potential to completely eliminate working on this node in the future(!)
                 //
                 // This can only be done if all of the elements properties (attrs, children, listeners, etc) are static
@@ -772,6 +777,7 @@ impl<'bump> DiffMachine<'bump> {
                     static_children: _,
                     static_listeners: _,
                     dom_id,
+                    key,
                 } = el;
 
                 let real_id = self.vdom.reserve_node();
@@ -805,7 +811,7 @@ impl<'bump> DiffMachine<'bump> {
                 //
                 // TODO move over
                 // if children.len() == 1 {
-                //     if let VNodeKind::Text(text) = &children[0].kind {
+                //     if let VNodeKind::Text(text) = &children[0] {
                 //         self.set_text(text.text);
                 //         return CreateMeta::new(is_static, 1);
                 //     }
@@ -822,7 +828,7 @@ impl<'bump> DiffMachine<'bump> {
                 CreateMeta::new(is_static, 1)
             }
 
-            VNodeKind::Component(vcomponent) => {
+            VNode::Component(vcomponent) => {
                 let caller = vcomponent.caller.clone();
 
                 let parent_idx = self.scope_stack.last().unwrap().clone();
@@ -895,9 +901,9 @@ impl<'bump> DiffMachine<'bump> {
             // Fragments are the only nodes that can contain dynamic content (IE through curlies or iterators).
             // We can never ignore their contents, so the prescence of a fragment indicates that we need always diff them.
             // Fragments will just put all their nodes onto the stack after creation
-            VNodeKind::Fragment(frag) => self.create_children(frag.children),
+            VNode::Fragment(frag) => self.create_children(frag.children),
 
-            VNodeKind::Suspended(VSuspended { node: real_node }) => {
+            VNode::Suspended(VSuspended { node: real_node }) => {
                 let id = self.vdom.reserve_node();
                 self.edit_create_placeholder(id);
                 real_node.set(Some(id));
@@ -993,14 +999,14 @@ impl<'bump> DiffMachine<'bump> {
                 let first_old = &old[0];
                 let first_new = &new[0];
 
-                match (&first_old.kind, &first_new.kind) {
+                match (&first_old, &first_new) {
                     // Anchors can only appear in empty fragments
-                    (VNodeKind::Anchor(old_anchor), VNodeKind::Anchor(new_anchor)) => {
+                    (VNode::Anchor(old_anchor), VNode::Anchor(new_anchor)) => {
                         old_anchor.dom_id.set(new_anchor.dom_id.get());
                     }
 
                     // Replace the anchor with whatever new nodes are coming down the pipe
-                    (VNodeKind::Anchor(anchor), _) => {
+                    (VNode::Anchor(anchor), _) => {
                         self.edit_push_root(anchor.dom_id.get().unwrap());
                         let mut added = 0;
                         for el in new {
@@ -1011,21 +1017,21 @@ impl<'bump> DiffMachine<'bump> {
                     }
 
                     // Replace whatever nodes are sitting there with the anchor
-                    (_, VNodeKind::Anchor(anchor)) => {
+                    (_, VNode::Anchor(anchor)) => {
                         self.replace_and_create_many_with_many(old, [first_new]);
                     }
 
                     // Use the complex diff algorithm to diff the nodes
                     _ => {
-                        let new_is_keyed = new[0].key.is_some();
-                        let old_is_keyed = old[0].key.is_some();
+                        let new_is_keyed = new[0].key().is_some();
+                        let old_is_keyed = old[0].key().is_some();
 
                         debug_assert!(
-                            new.iter().all(|n| n.key.is_some() == new_is_keyed),
+                            new.iter().all(|n| n.key().is_some() == new_is_keyed),
                             "all siblings must be keyed or all siblings must be non-keyed"
                         );
                         debug_assert!(
-                            old.iter().all(|o| o.key.is_some() == old_is_keyed),
+                            old.iter().all(|o| o.key().is_some() == old_is_keyed),
                             "all siblings must be keyed or all siblings must be non-keyed"
                         );
 
@@ -1062,7 +1068,7 @@ impl<'bump> DiffMachine<'bump> {
             let mut assert_unique_keys = |children: &'bump [VNode<'bump>]| {
                 keys.clear();
                 for child in children {
-                    let key = child.key;
+                    let key = child.key();
                     debug_assert!(
                         key.is_some(),
                         "if any sibling is keyed, all siblings must be keyed"
@@ -1102,7 +1108,7 @@ impl<'bump> DiffMachine<'bump> {
             .iter()
             .rev()
             .zip(new[shared_prefix_count..].iter().rev())
-            .take_while(|&(old, new)| old.key == new.key)
+            .take_while(|&(old, new)| old.key() == new.key())
             .count();
 
         let old_shared_suffix_start = old.len() - shared_suffix_count;
@@ -1543,17 +1549,16 @@ impl<'bump> DiffMachine<'bump> {
 
         loop {
             let node = search_node.take().unwrap();
-            match &node.kind {
+            match &node {
                 // the ones that have a direct id
-                VNodeKind::Text(_)
-                | VNodeKind::Element(_)
-                | VNodeKind::Anchor(_)
-                | VNodeKind::Suspended(_) => break node,
+                VNode::Text(_) | VNode::Element(_) | VNode::Anchor(_) | VNode::Suspended(_) => {
+                    break node
+                }
 
-                VNodeKind::Fragment(frag) => {
+                VNode::Fragment(frag) => {
                     search_node = frag.children.last();
                 }
-                VNodeKind::Component(el) => {
+                VNode::Component(el) => {
                     let scope_id = el.ass_scope.get().unwrap();
                     let scope = self.get_scope(&scope_id).unwrap();
                     search_node = Some(scope.root());
@@ -1567,17 +1572,16 @@ impl<'bump> DiffMachine<'bump> {
 
         loop {
             let node = search_node.take().unwrap();
-            match &node.kind {
+            match &node {
                 // the ones that have a direct id
-                VNodeKind::Text(_)
-                | VNodeKind::Element(_)
-                | VNodeKind::Anchor(_)
-                | VNodeKind::Suspended(_) => break node,
+                VNode::Text(_) | VNode::Element(_) | VNode::Anchor(_) | VNode::Suspended(_) => {
+                    break node
+                }
 
-                VNodeKind::Fragment(frag) => {
+                VNode::Fragment(frag) => {
                     search_node = Some(&frag.children[0]);
                 }
-                VNodeKind::Component(el) => {
+                VNode::Component(el) => {
                     let scope_id = el.ass_scope.get().unwrap();
                     let scope = self.get_scope(&scope_id).unwrap();
                     search_node = Some(scope.root());
@@ -1602,15 +1606,15 @@ impl<'bump> DiffMachine<'bump> {
         let mut nodes_to_search = old_nodes.into_iter().collect::<Vec<_>>();
         let mut scopes_obliterated = Vec::new();
         while let Some(node) = nodes_to_search.pop() {
-            match &node.kind {
+            match &node {
                 // the ones that have a direct id return immediately
-                VNodeKind::Text(el) => nodes_to_replace.push(el.dom_id.get().unwrap()),
-                VNodeKind::Element(el) => nodes_to_replace.push(el.dom_id.get().unwrap()),
-                VNodeKind::Anchor(el) => nodes_to_replace.push(el.dom_id.get().unwrap()),
-                VNodeKind::Suspended(el) => nodes_to_replace.push(el.node.get().unwrap()),
+                VNode::Text(el) => nodes_to_replace.push(el.dom_id.get().unwrap()),
+                VNode::Element(el) => nodes_to_replace.push(el.dom_id.get().unwrap()),
+                VNode::Anchor(el) => nodes_to_replace.push(el.dom_id.get().unwrap()),
+                VNode::Suspended(el) => nodes_to_replace.push(el.node.get().unwrap()),
 
                 // Fragments will either have a single anchor or a list of children
-                VNodeKind::Fragment(frag) => {
+                VNode::Fragment(frag) => {
                     for child in frag.children {
                         nodes_to_search.push(child);
                     }
@@ -1618,7 +1622,7 @@ impl<'bump> DiffMachine<'bump> {
 
                 // Components can be any of the nodes above
                 // However, we do need to track which components need to be removed
-                VNodeKind::Component(el) => {
+                VNode::Component(el) => {
                     let scope_id = el.ass_scope.get().unwrap();
                     let scope = self.get_scope(&scope_id).unwrap();
                     let root = scope.root();
@@ -1680,27 +1684,27 @@ impl<'bump> DiffMachine<'bump> {
     }
 
     fn remove_vnode(&mut self, node: &'bump VNode<'bump>) {
-        match &node.kind {
-            VNodeKind::Text(el) => self.immediately_dispose_garabage(node.direct_id()),
-            VNodeKind::Element(el) => {
+        match &node {
+            VNode::Text(el) => self.immediately_dispose_garabage(node.direct_id()),
+            VNode::Element(el) => {
                 self.immediately_dispose_garabage(node.direct_id());
                 for child in el.children {
                     self.remove_vnode(&child);
                 }
             }
-            VNodeKind::Anchor(a) => {
+            VNode::Anchor(a) => {
                 //
             }
-            VNodeKind::Fragment(frag) => {
+            VNode::Fragment(frag) => {
                 for child in frag.children {
                     self.remove_vnode(&child);
                 }
             }
-            VNodeKind::Component(el) => {
+            VNode::Component(el) => {
                 //
                 // self.destroy_scopes(old_scope)
             }
-            VNodeKind::Suspended(_) => todo!(),
+            VNode::Suspended(_) => todo!(),
         }
     }
 
@@ -1941,10 +1945,10 @@ impl<'a> Iterator for RealChildIterator<'a> {
 
         while returned_node.is_none() {
             if let Some((count, node)) = self.stack.last_mut() {
-                match &node.kind {
+                match &node {
                     // We can only exit our looping when we get "real" nodes
                     // This includes fragments and components when they're empty (have a single root)
-                    VNodeKind::Element(_) | VNodeKind::Text(_) => {
+                    VNode::Element(_) | VNode::Text(_) => {
                         // We've recursed INTO an element/text
                         // We need to recurse *out* of it and move forward to the next
                         should_pop = true;
@@ -1952,7 +1956,7 @@ impl<'a> Iterator for RealChildIterator<'a> {
                     }
 
                     // If we get a fragment we push the next child
-                    VNodeKind::Fragment(frag) => {
+                    VNode::Fragment(frag) => {
                         let subcount = *count as usize;
 
                         if frag.children.len() == 0 {
@@ -1983,17 +1987,17 @@ impl<'a> Iterator for RealChildIterator<'a> {
                     // }
 
                     // Immediately abort suspended nodes - can't do anything with them yet
-                    VNodeKind::Suspended(node) => {
+                    VNode::Suspended(node) => {
                         // VNodeKind::Suspended => should_pop = true,
                         todo!()
                     }
 
-                    VNodeKind::Anchor(a) => {
+                    VNode::Anchor(a) => {
                         todo!()
                     }
 
                     // For components, we load their root and push them onto the stack
-                    VNodeKind::Component(sc) => {
+                    VNode::Component(sc) => {
                         let scope =
                             unsafe { self.scopes.get_scope(sc.ass_scope.get().unwrap()) }.unwrap();
                         // let scope = self.scopes.get(sc.ass_scope.get().unwrap()).unwrap();

+ 3 - 6
packages/core/src/hooks.rs

@@ -191,12 +191,9 @@ where
                     }
                     None => {
                         //
-                        Some(VNode {
-                            key: None,
-                            kind: VNodeKind::Suspended(VSuspended {
-                                node: domnode.clone(),
-                            }),
-                        })
+                        Some(VNode::Suspended(VSuspended {
+                            node: domnode.clone(),
+                        }))
                     }
                 }
             });

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

@@ -12,8 +12,8 @@
 
 pub use crate::innerlude::{
     format_args_f, html, rsx, Context, DioxusElement, DomEdit, DomTree, ElementId, EventPriority,
-    EventTrigger, LazyNodes, NodeFactory, Properties, ScopeId, SuspendedContext, VNode, VNodeKind,
-    VirtualDom, VirtualEvent, FC,
+    EventTrigger, LazyNodes, NodeFactory, Properties, ScopeId, SuspendedContext, VNode, VirtualDom,
+    VirtualEvent, FC,
 };
 
 pub mod prelude {

+ 89 - 103
packages/core/src/nodes.rs

@@ -16,37 +16,12 @@ use std::{
     rc::Rc,
 };
 
-pub struct VNode<'src> {
-    pub kind: VNodeKind<'src>,
-
-    pub(crate) key: Option<&'src str>,
-}
-
-impl<'src> VNode<'src> {
-    pub fn key(&self) -> Option<&'src str> {
-        self.key
-    }
-    pub fn direct_id(&self) -> ElementId {
-        self.try_direct_id().unwrap()
-    }
-    pub fn try_direct_id(&self) -> Option<ElementId> {
-        match &self.kind {
-            VNodeKind::Text(el) => el.dom_id.get(),
-            VNodeKind::Element(el) => el.dom_id.get(),
-            VNodeKind::Anchor(el) => el.dom_id.get(),
-            VNodeKind::Fragment(_) => None,
-            VNodeKind::Component(_) => None,
-            VNodeKind::Suspended(_) => None,
-        }
-    }
-}
-
 /// Tools for the base unit of the virtual dom - the VNode
 /// VNodes are intended to be quickly-allocated, lightweight enum values.
 ///
 /// Components will be generating a lot of these very quickly, so we want to
 /// limit the amount of heap allocations / overly large enum sizes.
-pub enum VNodeKind<'src> {
+pub enum VNode<'src> {
     Text(VText<'src>),
 
     Element(&'src VElement<'src>),
@@ -60,6 +35,32 @@ pub enum VNodeKind<'src> {
     Anchor(VAnchor),
 }
 
+impl<'src> VNode<'src> {
+    pub fn key(&self) -> Option<&'src str> {
+        match &self {
+            VNode::Text(_) => todo!(),
+            VNode::Element(_) => todo!(),
+            VNode::Fragment(_) => todo!(),
+            VNode::Component(_) => todo!(),
+            VNode::Suspended(_) => todo!(),
+            VNode::Anchor(_) => todo!(),
+        }
+    }
+    pub fn direct_id(&self) -> ElementId {
+        self.try_direct_id().unwrap()
+    }
+    pub fn try_direct_id(&self) -> Option<ElementId> {
+        match &self {
+            VNode::Text(el) => el.dom_id.get(),
+            VNode::Element(el) => el.dom_id.get(),
+            VNode::Anchor(el) => el.dom_id.get(),
+            VNode::Fragment(_) => None,
+            VNode::Component(_) => None,
+            VNode::Suspended(_) => None,
+        }
+    }
+}
+
 pub struct VAnchor {
     pub dom_id: Cell<Option<ElementId>>,
 }
@@ -72,6 +73,7 @@ pub struct VText<'src> {
 
 pub struct VFragment<'src> {
     pub children: &'src [VNode<'src>],
+    pub key: Option<&'src str>,
     pub is_static: bool,
 }
 
@@ -89,6 +91,8 @@ pub trait DioxusElement {
 }
 
 pub struct VElement<'a> {
+    pub key: Option<&'a str>,
+
     // tag is always static
     pub tag_name: &'static str,
     pub namespace: Option<&'static str>,
@@ -144,6 +148,8 @@ impl Listener<'_> {
 /// Virtual Components for custom user-defined components
 /// Only supports the functional syntax
 pub struct VComponent<'src> {
+    pub key: Option<&'src str>,
+
     pub ass_scope: Cell<Option<ScopeId>>,
 
     pub(crate) caller: Rc<dyn Fn(&Scope) -> DomTree>,
@@ -196,26 +202,20 @@ impl<'a> NodeFactory<'a> {
     }
 
     pub fn unstable_place_holder() -> VNode<'static> {
-        VNode {
-            key: None,
-            kind: VNodeKind::Text(VText {
-                text: "",
-                dom_id: empty_cell(),
-                is_static: true,
-            }),
-        }
+        VNode::Text(VText {
+            text: "",
+            dom_id: empty_cell(),
+            is_static: true,
+        })
     }
 
     /// Used in a place or two to make it easier to build vnodes from dummy text
     pub fn static_text(&self, text: &'static str) -> VNode<'a> {
-        VNode {
-            key: None,
-            kind: VNodeKind::Text(VText {
-                dom_id: empty_cell(),
-                text,
-                is_static: true,
-            }),
-        }
+        VNode::Text(VText {
+            dom_id: empty_cell(),
+            text,
+            is_static: true,
+        })
     }
 
     /// Parses a lazy text Arguments and returns a string and a flag indicating if the text is 'static
@@ -237,14 +237,12 @@ impl<'a> NodeFactory<'a> {
     ///
     pub fn text(&self, args: Arguments) -> VNode<'a> {
         let (text, is_static) = self.raw_text(args);
-        VNode {
-            key: None,
-            kind: VNodeKind::Text(VText {
-                text,
-                is_static,
-                dom_id: empty_cell(),
-            }),
-        }
+
+        VNode::Text(VText {
+            text,
+            is_static,
+            dom_id: empty_cell(),
+        })
     }
 
     pub fn element<L, A, V>(
@@ -295,31 +293,26 @@ impl<'a> NodeFactory<'a> {
 
         let key = key.map(|f| self.raw_text(f).0);
 
-        VNode {
+        VNode::Element(self.bump().alloc(VElement {
+            tag_name: tag,
             key,
-            kind: VNodeKind::Element(self.bump().alloc(VElement {
-                tag_name: tag,
-                namespace,
-                listeners,
-                attributes,
-                children,
-                dom_id: empty_cell(),
+            namespace,
+            listeners,
+            attributes,
+            children,
+            dom_id: empty_cell(),
 
-                // todo: wire up more constization
-                static_listeners: false,
-                static_attrs: false,
-                static_children: false,
-            })),
-        }
+            // todo: wire up more constization
+            static_listeners: false,
+            static_attrs: false,
+            static_children: false,
+        }))
     }
 
     pub fn suspended() -> VNode<'static> {
-        VNode {
-            key: None,
-            kind: VNodeKind::Suspended(VSuspended {
-                node: Rc::new(empty_cell()),
-            }),
-        }
+        VNode::Suspended(VSuspended {
+            node: Rc::new(empty_cell()),
+        })
     }
 
     pub fn attr(
@@ -422,20 +415,18 @@ impl<'a> NodeFactory<'a> {
 
         let key = key.map(|f| self.raw_text(f).0);
 
-        VNode {
+        VNode::Component(bump.alloc_with(|| VComponent {
+            user_fc,
+            comparator,
+            raw_props,
+            children,
+            caller: NodeFactory::create_component_caller(component, raw_props),
+            is_static,
+            drop_props: RefCell::new(Some(drop_props)),
+            can_memoize: P::IS_STATIC,
+            ass_scope: Cell::new(None),
             key,
-            kind: VNodeKind::Component(bump.alloc_with(|| VComponent {
-                user_fc,
-                comparator,
-                raw_props,
-                children,
-                caller: NodeFactory::create_component_caller(component, raw_props),
-                is_static,
-                drop_props: RefCell::new(Some(drop_props)),
-                can_memoize: P::IS_STATIC,
-                ass_scope: Cell::new(None),
-            })),
-        }
+        }))
     }
 
     pub fn create_component_caller<'g, P: 'g>(
@@ -463,13 +454,11 @@ impl<'a> NodeFactory<'a> {
     pub fn fragment_from_iter(self, node_iter: impl IntoVNodeList<'a>) -> VNode<'a> {
         let children = node_iter.into_vnode_list(self);
 
-        VNode {
+        VNode::Fragment(VFragment {
+            children,
             key: None,
-            kind: VNodeKind::Fragment(VFragment {
-                children,
-                is_static: false,
-            }),
-        }
+            is_static: false,
+        })
     }
 }
 
@@ -525,12 +514,9 @@ where
         }
 
         if nodes.len() == 0 {
-            nodes.push(VNode {
-                kind: VNodeKind::Anchor(VAnchor {
-                    dom_id: empty_cell(),
-                }),
-                key: None,
-            });
+            nodes.push(VNode::Anchor(VAnchor {
+                dom_id: empty_cell(),
+            }));
         }
 
         nodes.into_bump_slice()
@@ -666,14 +652,14 @@ impl Debug for NodeFactory<'_> {
 
 impl Debug for VNode<'_> {
     fn fmt(&self, s: &mut Formatter<'_>) -> std::result::Result<(), std::fmt::Error> {
-        match &self.kind {
-            VNodeKind::Element(el) => write!(s, "VElement {{ name: {} }}", el.tag_name),
-            VNodeKind::Text(t) => write!(s, "VText {{ text: {} }}", t.text),
-            VNodeKind::Anchor(a) => write!(s, "VAnchor"),
-
-            VNodeKind::Fragment(_) => write!(s, "fragment"),
-            VNodeKind::Suspended { .. } => write!(s, "suspended"),
-            VNodeKind::Component(_) => write!(s, "component"),
+        match &self {
+            VNode::Element(el) => write!(s, "VElement {{ name: {} }}", el.tag_name),
+            VNode::Text(t) => write!(s, "VText {{ text: {} }}", t.text),
+            VNode::Anchor(a) => write!(s, "VAnchor"),
+
+            VNode::Fragment(_) => write!(s, "fragment"),
+            VNode::Suspended { .. } => write!(s, "suspended"),
+            VNode::Component(_) => write!(s, "component"),
         }
     }
 }

+ 7 - 7
packages/core/src/scheduler.rs

@@ -354,31 +354,31 @@ impl Scheduler {
             }
 
             while let Some(node) = garbage_list.pop() {
-                match &node.kind {
-                    VNodeKind::Text(_) => {
+                match &node {
+                    VNode::Text(_) => {
                         self.shared.collect_garbage(node.direct_id());
                     }
-                    VNodeKind::Anchor(_) => {
+                    VNode::Anchor(_) => {
                         self.shared.collect_garbage(node.direct_id());
                     }
-                    VNodeKind::Suspended(_) => {
+                    VNode::Suspended(_) => {
                         self.shared.collect_garbage(node.direct_id());
                     }
 
-                    VNodeKind::Element(el) => {
+                    VNode::Element(el) => {
                         self.shared.collect_garbage(node.direct_id());
                         for child in el.children {
                             garbage_list.push(child);
                         }
                     }
 
-                    VNodeKind::Fragment(frag) => {
+                    VNode::Fragment(frag) => {
                         for child in frag.children {
                             garbage_list.push(child);
                         }
                     }
 
-                    VNodeKind::Component(comp) => {
+                    VNode::Component(comp) => {
                         // TODO: run the hook destructors and then even delete the scope
 
                         let scope_id = comp.ass_scope.get().unwrap();

+ 6 - 6
packages/ssr/src/lib.rs

@@ -75,7 +75,7 @@ impl<'a> TextRenderer<'a> {
 
     fn html_render(&self, node: &VNode, f: &mut std::fmt::Formatter, il: u16) -> std::fmt::Result {
         match &node.kind {
-            VNodeKind::Text(text) => {
+            VNode::Text(text) => {
                 if self.cfg.indent {
                     for _ in 0..il {
                         write!(f, "    ")?;
@@ -83,7 +83,7 @@ impl<'a> TextRenderer<'a> {
                 }
                 write!(f, "{}", text.text)?
             }
-            VNodeKind::Anchor(anchor) => {
+            VNode::Anchor(anchor) => {
                 //
                 if self.cfg.indent {
                     for _ in 0..il {
@@ -92,7 +92,7 @@ impl<'a> TextRenderer<'a> {
                 }
                 write!(f, "<!-- -->")?;
             }
-            VNodeKind::Element(el) => {
+            VNode::Element(el) => {
                 if self.cfg.indent {
                     for _ in 0..il {
                         write!(f, "    ")?;
@@ -163,12 +163,12 @@ impl<'a> TextRenderer<'a> {
                     write!(f, "\n")?;
                 }
             }
-            VNodeKind::Fragment(frag) => {
+            VNode::Fragment(frag) => {
                 for child in frag.children {
                     self.html_render(child, f, il + 1)?;
                 }
             }
-            VNodeKind::Component(vcomp) => {
+            VNode::Component(vcomp) => {
                 let idx = vcomp.ass_scope.get().unwrap();
                 match (self.vdom, self.cfg.skip_components) {
                     (Some(vdom), false) => {
@@ -180,7 +180,7 @@ impl<'a> TextRenderer<'a> {
                     }
                 }
             }
-            VNodeKind::Suspended { .. } => {
+            VNode::Suspended { .. } => {
                 // we can't do anything with suspended nodes
             }
         }