wip: use the new structure

This commit is contained in:
Jonathan Kelley committed 2021-07-12 18:19:27 -04:00
1 parent a85b8c4b6b
commit a05047d01e
12 files changed
+884 -1241

No files matched your search

+64 -62
View File
@@ -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