diff --git a/packages/core/src/diff.rs b/packages/core/src/diff.rs index ad1cabf83..9760e758f 100644 --- a/packages/core/src/diff.rs +++ b/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::>(); 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(); diff --git a/packages/core/src/hooks.rs b/packages/core/src/hooks.rs index 29ecebe7d..3a0510ace 100644 --- a/packages/core/src/hooks.rs +++ b/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(), + })) } } }); diff --git a/packages/core/src/lib.rs b/packages/core/src/lib.rs index fa2de0c8c..d26d4c161 100644 --- a/packages/core/src/lib.rs +++ b/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 { diff --git a/packages/core/src/nodes.rs b/packages/core/src/nodes.rs index fae6c31d4..865284794 100644 --- a/packages/core/src/nodes.rs +++ b/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 { - 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 { + 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>, } @@ -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>, pub(crate) caller: Rc 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( @@ -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"), + 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"), - VNodeKind::Fragment(_) => write!(s, "fragment"), - VNodeKind::Suspended { .. } => write!(s, "suspended"), - VNodeKind::Component(_) => write!(s, "component"), + VNode::Fragment(_) => write!(s, "fragment"), + VNode::Suspended { .. } => write!(s, "suspended"), + VNode::Component(_) => write!(s, "component"), } } } diff --git a/packages/core/src/scheduler.rs b/packages/core/src/scheduler.rs index 85ad7a8b1..22e55a994 100644 --- a/packages/core/src/scheduler.rs +++ b/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(); diff --git a/packages/ssr/src/lib.rs b/packages/ssr/src/lib.rs index bd323e77d..80a4c17ef 100644 --- a/packages/ssr/src/lib.rs +++ b/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 } }