From 113b2c1529ca95908590359bff0f7226165bb76e Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Fri, 5 Jan 2024 12:07:29 -0600 Subject: [PATCH] port over more diffing + creation logic --- packages/core/src/create.rs | 10 ++--- packages/core/src/diff.rs | 67 ++++++++++++++------------------ packages/core/src/mutations.rs | 8 ++-- packages/core/src/nodes.rs | 16 ++++---- packages/core/src/scopes.rs | 6 +-- packages/core/src/virtual_dom.rs | 28 +++++++++---- packages/core/tests/fuzzing.rs | 2 +- 7 files changed, 69 insertions(+), 68 deletions(-) diff --git a/packages/core/src/create.rs b/packages/core/src/create.rs index 3da568634..06cb07603 100644 --- a/packages/core/src/create.rs +++ b/packages/core/src/create.rs @@ -408,11 +408,7 @@ impl VirtualDom { } /// Insert a new template into the VirtualDom's template registry - pub(crate) fn register_template_first_byte_index( - &mut self, - mut template: Template<'static>, - to: &mut impl WriteMutations, - ) { + pub(crate) fn register_template_first_byte_index(&mut self, mut template: Template) { // First, make sure we mark the template as seen, regardless if we process it let (path, _) = template.name.rsplit_once(':').unwrap(); if let Some((_, old_template)) = self @@ -435,7 +431,7 @@ impl VirtualDom { // If it's all dynamic nodes, then we don't need to register it if !template.is_completely_dynamic() { - to.register_template(template); + self.queued_templates.push(template); } } @@ -444,7 +440,7 @@ impl VirtualDom { #[allow(unused_mut)] pub(crate) fn register_template( &mut self, - mut template: Template<'static>, + mut template: Template, to: &mut impl WriteMutations, ) { let (path, byte_index) = template.name.rsplit_once(':').unwrap(); diff --git a/packages/core/src/diff.rs b/packages/core/src/diff.rs index 0b41f4916..61cb8e178 100644 --- a/packages/core/src/diff.rs +++ b/packages/core/src/diff.rs @@ -6,7 +6,6 @@ use crate::{ innerlude::{ DirtyScope, ElementPath, ElementRef, VComponent, VPlaceholder, VText, WriteMutations, }, - mutations::Mutation, nodes::RenderReturn, nodes::{DynamicNode, VNode}, scopes::ScopeId, @@ -63,15 +62,10 @@ impl VirtualDom { *p.parent.borrow_mut() = l.parent.borrow().clone(); to.create_placeholder(id); - self.remove_node(l, true, to); + to.insert_nodes_before(id, 1); - // We want to optimize the replace case to use one less mutation if possible - // Since mutations are done in reverse, the last node removed will be the first in the stack - // Instead of *just* removing it, we can use the replace mutation - match self.mutations.edits.pop().unwrap() { - Mutation::Remove { id } => self.mutations.push(Mutation::ReplaceWith { id, m: 1 }), - _ => panic!("Expected remove mutation from remove_node"), - }; + // TODO: Instead of *just* removing it, we can use the replace mutation + self.remove_node(l, true, to); } fn diff_node( @@ -250,17 +244,12 @@ impl VirtualDom { parent: Option, to: &mut impl WriteMutations, ) { - let m = self.create_component_node(parent, right); + let m = self.create_component_node(parent, right, to); + // TODO: Instead of *just* removing it, we can use the replace mutation self.remove_component_node(left, true, to); - // We want to optimize the replace case to use one less mutation if possible - // Since mutations are done in reverse, the last node removed will be the first in the stack - // Instead of *just* removing it, we can use the replace mutation - match self.mutations.edits.pop().unwrap() { - Mutation::Remove { id } => self.mutations.push(Mutation::ReplaceWith { id, m }), - at => panic!("Expected remove mutation from remove_node {:#?}", at), - }; + todo!() } /// Lightly diff the two templates, checking only their roots. @@ -656,7 +645,7 @@ impl VirtualDom { let new_idx = idx + last + 1; let old_index = new_index_to_old_index[new_idx]; if old_index == u32::MAX as usize { - nodes_created += self.create(new_node); + nodes_created += self.create(new_node, to); } else { self.diff_node(&old[old_index], new_node, to); nodes_created += self.push_all_real_nodes(new_node, to); @@ -679,7 +668,7 @@ impl VirtualDom { let new_idx = idx + next + 1; let old_index = new_index_to_old_index[new_idx]; if old_index == u32::MAX as usize { - nodes_created += self.create(new_node); + nodes_created += self.create(new_node, to); } else { self.diff_node(&old[old_index], new_node, to); nodes_created += self.push_all_real_nodes(new_node, to); @@ -702,7 +691,7 @@ impl VirtualDom { for (idx, new_node) in new[..first_lis].iter().enumerate() { let old_index = new_index_to_old_index[idx]; if old_index == u32::MAX as usize { - nodes_created += self.create(new_node); + nodes_created += self.create(new_node, to); } else { self.diff_node(&old[old_index], new_node, to); nodes_created += self.push_all_real_nodes(new_node, to); @@ -768,7 +757,7 @@ impl VirtualDom { .into_iter() .map(|child| { self.assign_boundary_ref(parent, child); - self.create(child) + self.create(child, to) }) .sum() } @@ -807,7 +796,7 @@ impl VirtualDom { ) { let m = self.create_children(r, Some(parent), to); let id = l.id.get().unwrap(); - to.replace_with(id, m); + to.replace_node_with(id, m); self.reclaim(id); } @@ -820,15 +809,10 @@ impl VirtualDom { ) { let m = self.create_children(right, parent, to); - self.remove_node(left, true, to); + // TODO: Instead of *just* removing it, we can use the replace mutation + to.insert_nodes_before(self.find_first_element(left), m); - // We want to optimize the replace case to use one less mutation if possible - // Since mutations are done in reverse, the last node removed will be the first in the stack - // Instead of *just* removing it, we can use the replace mutation - match self.mutations.edits.pop().unwrap() { - Mutation::Remove { id } => self.mutations.push(Mutation::ReplaceWith { id, m }), - _ => panic!("Expected remove mutation from remove_node"), - }; + self.remove_node(left, true, to); } fn node_to_placeholder( @@ -846,15 +830,22 @@ impl VirtualDom { to.create_placeholder(placeholder); - self.remove_nodes(l, to); + self.replace_nodes(l, 1, to); + } + /// Replace many nodes with a number of nodes on the stack + fn replace_nodes(&mut self, nodes: &[VNode], m: usize, to: &mut impl WriteMutations) { // We want to optimize the replace case to use one less mutation if possible // Since mutations are done in reverse, the last node removed will be the first in the stack - // Instead of *just* removing it, we can use the replace mutation - match self.mutations.edits.pop().unwrap() { - Mutation::Remove { id } => self.mutations.push(Mutation::ReplaceWith { id, m: 1 }), - _ => panic!("Expected remove mutation from remove_node"), - }; + // TODO: Instead of *just* removing it, we can use the replace mutation + to.insert_nodes_before(self.find_first_element(&nodes[0]), m); + + debug_assert!( + !nodes.is_empty(), + "replace_nodes must have at least one node" + ); + + self.remove_nodes(&nodes, to); } /// Remove these nodes from the dom @@ -869,7 +860,7 @@ impl VirtualDom { fn remove_node(&mut self, node: &VNode, gen_muts: bool, to: &mut impl WriteMutations) { // Clean up any attributes that have claimed a static node as dynamic for mount/unmounta // Will not generate mutations! - self.reclaim_attributes(node, to); + self.reclaim_attributes(node); // Remove the nested dynamic nodes // We don't generate mutations for these, as they will be removed by the parent (in the next line) @@ -895,7 +886,7 @@ impl VirtualDom { } } - fn reclaim_attributes(&mut self, node: &VNode, to: &mut impl WriteMutations) { + fn reclaim_attributes(&mut self, node: &VNode) { let mut id = None; for (idx, attr) in node.dynamic_attrs.iter().enumerate() { // We'll clean up the root nodes either way, so don't worry diff --git a/packages/core/src/mutations.rs b/packages/core/src/mutations.rs index 6ac45b690..0493194f2 100644 --- a/packages/core/src/mutations.rs +++ b/packages/core/src/mutations.rs @@ -15,7 +15,7 @@ use crate::{arena::ElementId, AttributeValue, ScopeId, Template}; /// Mutations are the only link between the RealDOM and the VirtualDOM. pub trait WriteMutations { /// Register a template with the renderer - fn register_template(&mut self, template: Template<'static>); + fn register_template(&mut self, template: Template); /// Add these m children to the target element /// @@ -333,7 +333,7 @@ pub struct MutationsVec { /// Any templates encountered while diffing the DOM. /// /// These must be loaded into a cache before applying the edits - pub templates: Vec>, + pub templates: Vec