mirror of
https://github.com/DioxusLabs/dioxus
synced 2025-02-17 06:08:26 +00:00
wip: refactor non_keyed diff
This commit is contained in:
parent
e6f56563bc
commit
082765f687
3 changed files with 62 additions and 136 deletions
2
packages/core/.vscode/settings.json
vendored
2
packages/core/.vscode/settings.json
vendored
|
@ -1,3 +1,3 @@
|
||||||
{
|
{
|
||||||
"rust-analyzer.inlayHints.enable": true
|
"rust-analyzer.inlayHints.enable": false
|
||||||
}
|
}
|
||||||
|
|
|
@ -185,14 +185,6 @@ impl<'bump> DiffMachine<'bump> {
|
||||||
self.create_node(node);
|
self.create_node(node);
|
||||||
}
|
}
|
||||||
|
|
||||||
DiffInstruction::Remove { child } => {
|
|
||||||
self.remove_nodes(Some(child));
|
|
||||||
}
|
|
||||||
|
|
||||||
DiffInstruction::RemoveChildren { children } => {
|
|
||||||
self.remove_nodes(children);
|
|
||||||
}
|
|
||||||
|
|
||||||
DiffInstruction::Mount { and } => {
|
DiffInstruction::Mount { and } => {
|
||||||
self.mount(and);
|
self.mount(and);
|
||||||
}
|
}
|
||||||
|
@ -219,7 +211,7 @@ impl<'bump> DiffMachine<'bump> {
|
||||||
let root = todo!();
|
let root = todo!();
|
||||||
self.mutations.replace_with(root, nodes_created as u32);
|
self.mutations.replace_with(root, nodes_created as u32);
|
||||||
}
|
}
|
||||||
MountType::ReplaceByElementId { old } => {
|
MountType::ReplaceByElementId { el: old } => {
|
||||||
self.mutations.replace_with(old, nodes_created as u32);
|
self.mutations.replace_with(old, nodes_created as u32);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -584,49 +576,28 @@ impl<'bump> DiffMachine<'bump> {
|
||||||
// Frament nodes cannot generate empty children lists, so we can assume that when a list is empty, it belongs only
|
// Frament nodes cannot generate empty children lists, so we can assume that when a list is empty, it belongs only
|
||||||
// to an element, and appending makes sense.
|
// to an element, and appending makes sense.
|
||||||
fn diff_children(&mut self, old: &'bump [VNode<'bump>], new: &'bump [VNode<'bump>]) {
|
fn diff_children(&mut self, old: &'bump [VNode<'bump>], new: &'bump [VNode<'bump>]) {
|
||||||
const IS_EMPTY: bool = true;
|
|
||||||
const IS_NOT_EMPTY: bool = false;
|
|
||||||
|
|
||||||
// Remember, fragments can never be empty (they always have a single child)
|
// Remember, fragments can never be empty (they always have a single child)
|
||||||
match (old.is_empty(), new.is_empty()) {
|
match (old, new) {
|
||||||
(IS_EMPTY, IS_EMPTY) => {}
|
([], []) => {}
|
||||||
|
([], _) => {
|
||||||
// Completely adding new nodes, removing any placeholder if it exists
|
|
||||||
(IS_EMPTY, IS_NOT_EMPTY) => {
|
|
||||||
self.stack.create_children(new, MountType::Append);
|
self.stack.create_children(new, MountType::Append);
|
||||||
}
|
}
|
||||||
|
(_, []) => {
|
||||||
// Completely removing old nodes and putting an anchor in its place
|
|
||||||
// no anchor (old has nodes) and the new is empty
|
|
||||||
// remove all the old nodes
|
|
||||||
(IS_NOT_EMPTY, IS_EMPTY) => {
|
|
||||||
for node in old {
|
for node in old {
|
||||||
self.remove_nodes(Some(node));
|
self.remove_nodes(Some(node));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
([VNode::Anchor(old_anchor)], [VNode::Anchor(new_anchor)]) => {
|
||||||
(IS_NOT_EMPTY, IS_NOT_EMPTY) => {
|
|
||||||
let first_old = &old[0];
|
|
||||||
let first_new = &new[0];
|
|
||||||
|
|
||||||
match (&first_old, &first_new) {
|
|
||||||
// Anchors can only appear in empty fragments
|
|
||||||
(VNode::Anchor(old_anchor), VNode::Anchor(new_anchor)) => {
|
|
||||||
old_anchor.dom_id.set(new_anchor.dom_id.get());
|
old_anchor.dom_id.set(new_anchor.dom_id.get());
|
||||||
}
|
}
|
||||||
|
([VNode::Anchor(anchor)], _) => {
|
||||||
// Replace the anchor with whatever new nodes are coming down the pipe
|
let el = anchor.dom_id.get().unwrap();
|
||||||
(VNode::Anchor(anchor), _) => {
|
|
||||||
self.stack
|
self.stack
|
||||||
.create_children(new, MountType::Replace { old: first_old });
|
.create_children(new, MountType::ReplaceByElementId { el });
|
||||||
}
|
}
|
||||||
|
(_, [VNode::Anchor(_)]) => {
|
||||||
// Replace whatever nodes are sitting there with the anchor
|
self.replace_and_create_many_with_one(old, &new[0]);
|
||||||
(_, VNode::Anchor(anchor)) => {
|
|
||||||
self.replace_and_create_many_with_one(old, first_new);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Use the complex diff algorithm to diff the nodes
|
|
||||||
_ => {
|
_ => {
|
||||||
let new_is_keyed = new[0].key().is_some();
|
let new_is_keyed = new[0].key().is_some();
|
||||||
let old_is_keyed = old[0].key().is_some();
|
let old_is_keyed = old[0].key().is_some();
|
||||||
|
@ -648,6 +619,33 @@ impl<'bump> DiffMachine<'bump> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Diff children that are not keyed.
|
||||||
|
//
|
||||||
|
// The parent must be on the top of the change list stack when entering this
|
||||||
|
// function:
|
||||||
|
//
|
||||||
|
// [... parent]
|
||||||
|
//
|
||||||
|
// the change list stack is in the same state when this function returns.
|
||||||
|
fn diff_non_keyed_children(&mut self, old: &'bump [VNode<'bump>], new: &'bump [VNode<'bump>]) {
|
||||||
|
// Handled these cases in `diff_children` before calling this function.
|
||||||
|
debug_assert!(!new.is_empty());
|
||||||
|
debug_assert!(!old.is_empty());
|
||||||
|
|
||||||
|
for (new, old) in new.iter().zip(old.iter()).rev() {
|
||||||
|
self.stack.push(DiffInstruction::DiffNode { new, old });
|
||||||
|
}
|
||||||
|
|
||||||
|
if old.len() > new.len() {
|
||||||
|
self.remove_nodes(&old[new.len()..]);
|
||||||
|
} else {
|
||||||
|
self.stack.create_children(
|
||||||
|
&new[old.len()..],
|
||||||
|
MountType::InsertAfter {
|
||||||
|
other_node: old.last().unwrap(),
|
||||||
|
},
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1027,70 +1025,6 @@ impl<'bump> DiffMachine<'bump> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Diff children that are not keyed.
|
|
||||||
//
|
|
||||||
// The parent must be on the top of the change list stack when entering this
|
|
||||||
// function:
|
|
||||||
//
|
|
||||||
// [... parent]
|
|
||||||
//
|
|
||||||
// the change list stack is in the same state when this function returns.
|
|
||||||
fn diff_non_keyed_children(&mut self, old: &'bump [VNode<'bump>], new: &'bump [VNode<'bump>]) {
|
|
||||||
// Handled these cases in `diff_children` before calling this function.
|
|
||||||
//
|
|
||||||
debug_assert!(!new.is_empty());
|
|
||||||
debug_assert!(!old.is_empty());
|
|
||||||
|
|
||||||
match old.len().cmp(&new.len()) {
|
|
||||||
// old.len > new.len -> removing some nodes
|
|
||||||
Ordering::Greater => {
|
|
||||||
// Generate instructions to diff the existing elements
|
|
||||||
for (new_child, old_child) in new.iter().zip(old.iter()).rev() {
|
|
||||||
self.stack.push(DiffInstruction::DiffNode {
|
|
||||||
new: new_child,
|
|
||||||
old: old_child,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
self.stack.push(DiffInstruction::RemoveChildren {
|
|
||||||
children: &old[new.len()..],
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// old.len < new.len -> adding some nodes
|
|
||||||
// this is wrong in the case where we're diffing fragments
|
|
||||||
//
|
|
||||||
// we need to save the last old element and then replace it with all the new ones
|
|
||||||
Ordering::Less => {
|
|
||||||
// Generate instructions to diff the existing elements
|
|
||||||
for (new_child, old_child) in new.iter().zip(old.iter()).rev() {
|
|
||||||
self.stack.push(DiffInstruction::DiffNode {
|
|
||||||
new: new_child,
|
|
||||||
old: old_child,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Generate instructions to add in the new elements
|
|
||||||
self.stack.create_children(
|
|
||||||
&new[old.len()..],
|
|
||||||
MountType::InsertAfter {
|
|
||||||
other_node: old.last().unwrap(),
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// old.len == new.len -> no nodes added/removed, but perhaps changed
|
|
||||||
Ordering::Equal => {
|
|
||||||
for (new_child, old_child) in new.iter().zip(old.iter()).rev() {
|
|
||||||
self.stack.push(DiffInstruction::DiffNode {
|
|
||||||
new: new_child,
|
|
||||||
old: old_child,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// =====================
|
// =====================
|
||||||
// Utilities
|
// Utilities
|
||||||
// =====================
|
// =====================
|
||||||
|
|
|
@ -18,14 +18,6 @@ pub enum DiffInstruction<'a> {
|
||||||
node: &'a VNode<'a>,
|
node: &'a VNode<'a>,
|
||||||
},
|
},
|
||||||
|
|
||||||
Remove {
|
|
||||||
child: &'a VNode<'a>,
|
|
||||||
},
|
|
||||||
|
|
||||||
RemoveChildren {
|
|
||||||
children: &'a [VNode<'a>],
|
|
||||||
},
|
|
||||||
|
|
||||||
Mount {
|
Mount {
|
||||||
and: MountType<'a>,
|
and: MountType<'a>,
|
||||||
},
|
},
|
||||||
|
@ -40,7 +32,7 @@ pub enum MountType<'a> {
|
||||||
Absorb,
|
Absorb,
|
||||||
Append,
|
Append,
|
||||||
Replace { old: &'a VNode<'a> },
|
Replace { old: &'a VNode<'a> },
|
||||||
ReplaceByElementId { old: ElementId },
|
ReplaceByElementId { el: ElementId },
|
||||||
InsertAfter { other_node: &'a VNode<'a> },
|
InsertAfter { other_node: &'a VNode<'a> },
|
||||||
InsertBefore { other_node: &'a VNode<'a> },
|
InsertBefore { other_node: &'a VNode<'a> },
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue