wip: use the new structure
This commit is contained in:
1 parent
a85b8c4b6b
commit
a05047d01e
12 files changed
+884
-1241
No files matched your search
+64
-62
@@ -158,50 +158,46 @@ where
|
||||
//
|
||||
// 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, new_node) {
|
||||
match (&old_node.kind, &new_node.kind) {
|
||||
// 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.
|
||||
(VNode::Text(old), VNode::Text(new)) => {
|
||||
if old.is_static {
|
||||
log::debug!("encountered static text node: {:?}", old.text);
|
||||
}
|
||||
|
||||
(VNodeKind::Text(old), VNodeKind::Text(new)) => {
|
||||
let root = old_node.dom_id.get();
|
||||
if old.text != new.text {
|
||||
self.dom.push(old.dom_id.get());
|
||||
self.dom.push(root);
|
||||
log::debug!("Text has changed {}, {}", old.text, new.text);
|
||||
self.dom.set_text(new.text);
|
||||
self.dom.pop();
|
||||
}
|
||||
|
||||
new.dom_id.set(old.dom_id.get());
|
||||
new_node.dom_id.set(root);
|
||||
}
|
||||
|
||||
(VNode::Element(old), VNode::Element(new)) => {
|
||||
(VNodeKind::Element(old), VNodeKind::Element(new)) => {
|
||||
// If the element type is completely different, the element needs to be re-rendered completely
|
||||
// This is an optimization React makes due to how users structure their code
|
||||
//
|
||||
// In Dioxus, this is less likely to occur unless through a fragment
|
||||
let root = old_node.dom_id.get();
|
||||
if new.tag_name != old.tag_name || new.namespace != old.namespace {
|
||||
self.dom.push(old.dom_id.get());
|
||||
self.dom.push(root);
|
||||
let meta = self.create(new_node);
|
||||
self.dom.replace_with(meta.added_to_stack);
|
||||
self.dom.pop();
|
||||
return;
|
||||
}
|
||||
|
||||
let oldid = old.dom_id.get();
|
||||
new.dom_id.set(oldid);
|
||||
new_node.dom_id.set(root);
|
||||
|
||||
// push it just in case
|
||||
self.dom.push(oldid);
|
||||
self.dom.push(root);
|
||||
self.diff_listeners(old.listeners, new.listeners);
|
||||
self.diff_attr(old.attributes, new.attributes, new.namespace);
|
||||
self.diff_children(old.children, new.children);
|
||||
self.dom.pop();
|
||||
}
|
||||
|
||||
(VNode::Component(old), VNode::Component(new)) => {
|
||||
(VNodeKind::Component(old), VNodeKind::Component(new)) => {
|
||||
log::warn!("diffing components? {:#?}", new.user_fc);
|
||||
if old.user_fc == new.user_fc {
|
||||
// Make sure we're dealing with the same component (by function pointer)
|
||||
@@ -257,7 +253,7 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
(VNode::Fragment(old), VNode::Fragment(new)) => {
|
||||
(VNodeKind::Fragment(old), VNodeKind::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 {
|
||||
@@ -278,15 +274,19 @@ where
|
||||
// We also walk the "real node" list to make sure all latent roots are claened up
|
||||
// This covers the case any time a fragment or component shows up with pretty much anything else
|
||||
(
|
||||
VNode::Component(_) | VNode::Fragment(_) | VNode::Text(_) | VNode::Element(_),
|
||||
VNode::Component(_) | VNode::Fragment(_) | VNode::Text(_) | VNode::Element(_),
|
||||
VNodeKind::Component(_)
|
||||
| VNodeKind::Fragment(_)
|
||||
| VNodeKind::Text(_)
|
||||
| VNodeKind::Element(_),
|
||||
VNodeKind::Component(_)
|
||||
| VNodeKind::Fragment(_)
|
||||
| VNodeKind::Text(_)
|
||||
| VNodeKind::Element(_),
|
||||
) => {
|
||||
// Choose the node to use as the placeholder for replacewith
|
||||
let back_node = match old_node {
|
||||
let back_node = match old_node.kind {
|
||||
// We special case these two types to avoid allocating the small-vecs
|
||||
VNode::Element(_) | VNode::Text(_) => old_node
|
||||
.get_mounted_id(&self.components)
|
||||
.expect("Element and text always have a real node"),
|
||||
VNodeKind::Element(_) | VNodeKind::Text(_) => old_node.dom_id.get(),
|
||||
|
||||
_ => {
|
||||
let mut old_iter = RealChildIterator::new(old_node, &self.components);
|
||||
@@ -314,8 +314,8 @@ where
|
||||
}
|
||||
|
||||
// TODO
|
||||
(VNode::Suspended { .. }, _) => todo!(),
|
||||
(_, VNode::Suspended { .. }) => todo!(),
|
||||
(VNodeKind::Suspended { .. }, _) => todo!(),
|
||||
(_, VNodeKind::Suspended { .. }) => todo!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -351,13 +351,14 @@ where
|
||||
// [... node]
|
||||
fn create(&mut self, node: &'bump VNode<'bump>) -> CreateMeta {
|
||||
log::warn!("Creating node! ... {:#?}", node);
|
||||
match node {
|
||||
VNode::Text(text) => {
|
||||
match &node.kind {
|
||||
VNodeKind::Text(text) => {
|
||||
let real_id = self.dom.create_text_node(text.text);
|
||||
text.dom_id.set(real_id);
|
||||
CreateMeta::new(text.is_static, 1)
|
||||
todo!()
|
||||
// text.dom_id.set(real_id);
|
||||
// CreateMeta::new(text.is_static, 1)
|
||||
}
|
||||
VNode::Element(el) => {
|
||||
VNodeKind::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
|
||||
@@ -366,14 +367,14 @@ where
|
||||
let mut is_static: bool = true;
|
||||
|
||||
let VElement {
|
||||
key,
|
||||
tag_name,
|
||||
listeners,
|
||||
attributes,
|
||||
children,
|
||||
namespace,
|
||||
dom_id,
|
||||
is_static: el_is_static,
|
||||
static_attrs,
|
||||
static_children,
|
||||
static_listeners,
|
||||
} = el;
|
||||
|
||||
let real_id = if let Some(namespace) = namespace {
|
||||
@@ -381,7 +382,7 @@ where
|
||||
} else {
|
||||
self.dom.create_element(tag_name, None)
|
||||
};
|
||||
dom_id.set(real_id);
|
||||
// dom_id.set(real_id);
|
||||
|
||||
listeners.iter().enumerate().for_each(|(idx, listener)| {
|
||||
listener.mounted_node.set(real_id);
|
||||
@@ -408,7 +409,7 @@ where
|
||||
//
|
||||
// TODO move over
|
||||
// if children.len() == 1 {
|
||||
// if let VNode::Text(text) = &children[0] {
|
||||
// if let VNodeKind::Text(text) = &children[0] {
|
||||
// self.dom.set_text(text.text);
|
||||
// return;
|
||||
// }
|
||||
@@ -428,11 +429,11 @@ where
|
||||
log::debug!("created a dynamic node {:#?}", node);
|
||||
}
|
||||
|
||||
el_is_static.set(is_static);
|
||||
// el_is_static.set(is_static);
|
||||
CreateMeta::new(is_static, 1)
|
||||
}
|
||||
|
||||
VNode::Component(vcomponent) => {
|
||||
VNodeKind::Component(vcomponent) => {
|
||||
log::debug!("Mounting a new component");
|
||||
let caller = vcomponent.caller.clone();
|
||||
|
||||
@@ -493,7 +494,7 @@ where
|
||||
// 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
|
||||
VNode::Fragment(frag) => {
|
||||
VNodeKind::Fragment(frag) => {
|
||||
let mut nodes_added = 0;
|
||||
for child in frag.children.iter().rev() {
|
||||
// different types of nodes will generate different amounts on the stack
|
||||
@@ -508,9 +509,10 @@ where
|
||||
CreateMeta::new(false, nodes_added)
|
||||
}
|
||||
|
||||
VNode::Suspended { real } => {
|
||||
let id = self.dom.create_placeholder();
|
||||
real.set(id);
|
||||
VNodeKind::Suspended => {
|
||||
todo!();
|
||||
// let id = self.dom.create_placeholder();
|
||||
// real.set(id);
|
||||
CreateMeta::new(false, 1)
|
||||
}
|
||||
}
|
||||
@@ -620,7 +622,7 @@ impl<'a, 'bump, Dom: RealDom<'bump>> DiffMachine<'a, 'bump, Dom> {
|
||||
// The "fast" path is when the list of attributes name is identical and in the same order
|
||||
// With the Rsx and Html macros, this will almost always be the case
|
||||
'outer: for new_attr in new {
|
||||
if new_attr.is_volatile() {
|
||||
if new_attr.is_volatile {
|
||||
// self.dom.commit_traversal();
|
||||
self.dom
|
||||
.set_attribute(new_attr.name, new_attr.value, namespace);
|
||||
@@ -675,13 +677,13 @@ impl<'a, 'bump, Dom: RealDom<'bump>> DiffMachine<'a, 'bump, Dom> {
|
||||
|
||||
if new.len() == 1 {
|
||||
match (&old.first(), &new[0]) {
|
||||
(Some(VNode::Text(old_vtext)), VNode::Text(new_vtext))
|
||||
if old_vtext.text == new_vtext.text =>
|
||||
{
|
||||
// Don't take this fast path...
|
||||
}
|
||||
// (Some(VNodeKind::Text(old_vtext)), VNodeKind::Text(new_vtext))
|
||||
// if old_vtext.text == new_vtext.text =>
|
||||
// {
|
||||
// // Don't take this fast path...
|
||||
// }
|
||||
|
||||
// (_, VNode::Text(text)) => {
|
||||
// (_, VNodeKind::Text(text)) => {
|
||||
// // self.dom.commit_traversal();
|
||||
// log::debug!("using optimized text set");
|
||||
// self.dom.set_text(text.text);
|
||||
@@ -701,15 +703,15 @@ impl<'a, 'bump, Dom: RealDom<'bump>> DiffMachine<'a, 'bump, Dom> {
|
||||
return;
|
||||
}
|
||||
|
||||
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"
|
||||
);
|
||||
|
||||
@@ -754,7 +756,7 @@ impl<'a, 'bump, Dom: RealDom<'bump>> DiffMachine<'a, 'bump, Dom> {
|
||||
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"
|
||||
@@ -797,7 +799,7 @@ impl<'a, 'bump, Dom: RealDom<'bump>> DiffMachine<'a, 'bump, Dom> {
|
||||
.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;
|
||||
@@ -1259,7 +1261,7 @@ impl<'a, 'bump, Dom: RealDom<'bump>> DiffMachine<'a, 'bump, Dom> {
|
||||
pub fn remove_self_and_next_siblings(&self, old: &[VNode<'bump>]) {
|
||||
// debug_assert!(self.dom.traversal_is_committed());
|
||||
for child in old {
|
||||
if let VNode::Component(vcomp) = child {
|
||||
if let VNodeKind::Component(vcomp) = child.kind {
|
||||
// dom
|
||||
// .create_text_node("placeholder for vcomponent");
|
||||
|
||||
@@ -1328,23 +1330,23 @@ impl<'a> Iterator for RealChildIterator<'a> {
|
||||
|
||||
while returned_node.is_none() {
|
||||
if let Some((count, node)) = self.stack.last_mut() {
|
||||
match node {
|
||||
match &node.kind {
|
||||
// We can only exit our looping when we get "real" nodes
|
||||
// This includes fragments and components when they're empty (have a single root)
|
||||
VNode::Element(_) | VNode::Text(_) => {
|
||||
VNodeKind::Element(_) | VNodeKind::Text(_) => {
|
||||
// We've recursed INTO an element/text
|
||||
// We need to recurse *out* of it and move forward to the next
|
||||
should_pop = true;
|
||||
returned_node = node.get_mounted_id(&self.scopes);
|
||||
returned_node = Some(node.dom_id.get());
|
||||
}
|
||||
|
||||
// If we get a fragment we push the next child
|
||||
VNode::Fragment(frag) => {
|
||||
VNodeKind::Fragment(frag) => {
|
||||
let subcount = *count as usize;
|
||||
|
||||
if frag.children.len() == 0 {
|
||||
should_pop = true;
|
||||
returned_node = node.get_mounted_id(&self.scopes);
|
||||
returned_node = Some(node.dom_id.get());
|
||||
}
|
||||
|
||||
if subcount >= frag.children.len() {
|
||||
@@ -1355,11 +1357,11 @@ impl<'a> Iterator for RealChildIterator<'a> {
|
||||
}
|
||||
|
||||
// Immediately abort suspended nodes - can't do anything with them yet
|
||||
// VNode::Suspended => should_pop = true,
|
||||
VNode::Suspended { real } => todo!(),
|
||||
// VNodeKind::Suspended => should_pop = true,
|
||||
VNodeKind::Suspended => todo!(),
|
||||
|
||||
// For components, we load their root and push them onto the stack
|
||||
VNode::Component(sc) => {
|
||||
VNodeKind::Component(sc) => {
|
||||
let scope = self.scopes.try_get(sc.ass_scope.get().unwrap()).unwrap();
|
||||
|
||||
// Simply swap the current node on the stack with the root of the component
|
||||
|
||||
Reference in new issue
Block a user