diff --git a/packages/cli/src/assets.rs b/packages/cli/src/assets.rs index 5848e6989..d08d9eb6f 100644 --- a/packages/cli/src/assets.rs +++ b/packages/cli/src/assets.rs @@ -102,7 +102,7 @@ impl AssetConfigDropGuard { None => "/".to_string(), }; manganis_cli_support::Config::default() - .with_assets_serve_location(&base) + .with_assets_serve_location(base) .save(); Self {} } diff --git a/packages/core/src/arena.rs b/packages/core/src/arena.rs index 432ffe604..79accf881 100644 --- a/packages/core/src/arena.rs +++ b/packages/core/src/arena.rs @@ -27,10 +27,10 @@ impl MountId { pub(crate) const PLACEHOLDER: Self = Self(usize::MAX); pub(crate) fn as_usize(self) -> Option { - if self == Self::PLACEHOLDER { - None - } else { + if self.mounted() { Some(self.0) + } else { + None } } diff --git a/packages/core/src/diff/mod.rs b/packages/core/src/diff/mod.rs index 4ed5e70ab..023796539 100644 --- a/packages/core/src/diff/mod.rs +++ b/packages/core/src/diff/mod.rs @@ -10,11 +10,10 @@ #![allow(clippy::too_many_arguments)] use crate::{ - arena::ElementId, - innerlude::{ElementRef, MountId, WriteMutations}, + innerlude::{ElementRef, WriteMutations}, nodes::VNode, virtual_dom::VirtualDom, - Template, TemplateNode, + TemplateNode, }; mod component; @@ -34,62 +33,6 @@ impl VirtualDom { .sum() } - /// Simply replace a placeholder with a list of nodes - fn replace_placeholder( - &mut self, - mut to: Option<&mut impl WriteMutations>, - placeholder_id: ElementId, - r: &[VNode], - parent: Option, - ) { - let m = self.create_children(to.as_deref_mut(), r, parent); - if let Some(to) = to { - self.replace_placeholder_with_nodes_on_stack(to, placeholder_id, m) - } - } - - fn replace_placeholder_with_nodes_on_stack( - &mut self, - to: &mut impl WriteMutations, - placeholder_id: ElementId, - m: usize, - ) { - to.replace_node_with(placeholder_id, m); - self.reclaim(placeholder_id); - } - - fn nodes_to_placeholder( - &mut self, - mut to: Option<&mut impl WriteMutations>, - mount: MountId, - dyn_node_idx: usize, - old_nodes: &[VNode], - ) { - // Create the placeholder first, ensuring we get a dedicated ID for the placeholder - let placeholder = self.next_element(); - - // Set the id of the placeholder - self.mounts[mount.0].mounted_dynamic_nodes[dyn_node_idx] = placeholder.0; - - if let Some(to) = to.as_deref_mut() { - to.create_placeholder(placeholder); - } - - self.replace_nodes(to, old_nodes, 1); - } - - /// Replace many nodes with a number of nodes on the stack - fn replace_nodes(&mut self, to: Option<&mut impl WriteMutations>, nodes: &[VNode], m: usize) { - debug_assert!( - !nodes.is_empty(), - "replace_nodes must have at least one node" - ); - - // We want to optimize the replace case to use one less mutation if possible - // Instead of *just* removing it, we can use the replace mutation - self.remove_nodes(to, nodes, Some(m)); - } - /// Remove these nodes from the dom /// Wont generate mutations for the inner nodes fn remove_nodes( @@ -103,26 +46,6 @@ impl VirtualDom { node.remove_node(self, to.as_deref_mut(), replace_with.filter(|_| last_node)); } } - - /// Insert a new template into the VirtualDom's template registry - // used in conditional compilation - #[allow(unused_mut)] - pub(crate) fn register_template( - &mut self, - to: &mut impl WriteMutations, - mut template: Template, - ) { - if self.templates.contains(&template.name) { - return; - } - - _ = self.templates.insert(template.name); - - // If it's all dynamic nodes, then we don't need to register it - if !template.is_completely_dynamic() { - to.register_template(template) - } - } } /// We can apply various optimizations to dynamic nodes that are the single child of their parent. diff --git a/packages/core/src/diff/node.rs b/packages/core/src/diff/node.rs index 06925f5a8..d2ad6f278 100644 --- a/packages/core/src/diff/node.rs +++ b/packages/core/src/diff/node.rs @@ -5,7 +5,7 @@ use core::iter::Peekable; use crate::{ arena::ElementId, - innerlude::{ElementPath, ElementRef, VComponent, VNodeMount, VText}, + innerlude::{ElementPath, ElementRef, VNodeMount, VText}, nodes::DynamicNode, scopes::ScopeId, TemplateNode, @@ -21,9 +21,12 @@ impl VNode { // The node we are diffing from should always be mounted debug_assert!(dom.mounts.get(self.mount.get().0).is_some() || to.is_none()); - // If the templates are different by name, we need to replace the entire template - if self.templates_are_different(new) { - return self.light_diff_templates(new, dom, to); + // If the templates are different, we need to replace the entire template + if self.template != new.template { + let mount_id = self.mount.get(); + let mount = &dom.mounts[mount_id.0]; + let parent = mount.parent; + return self.replace(std::slice::from_ref(new), parent, dom, to); } let mount_id = self.mount.get(); @@ -73,75 +76,62 @@ impl VNode { old_node: &DynamicNode, new_node: &DynamicNode, dom: &mut VirtualDom, - to: Option<&mut impl WriteMutations>, + mut to: Option<&mut impl WriteMutations>, ) { tracing::trace!("diffing dynamic node from {old_node:?} to {new_node:?}"); match (old_node, new_node) { (Text(old), Text(new)) => { // Diffing text is just a side effect, if we are diffing suspended nodes and are not outputting mutations, we can skip it - if let Some(to) = to{ + if let Some(to) = to { let mount = &dom.mounts[mount.0]; self.diff_vtext(to, mount, idx, old, new) } - }, - (Text(_), Placeholder(_)) => { - self.replace_text_with_placeholder(to, mount, idx, dom) - }, - (Placeholder(_), Text(new)) => { - self.replace_placeholder_with_text(to, mount, idx, new, dom) - }, - (Placeholder(_), Placeholder(_)) => {}, - (Fragment(old), Fragment(new)) => dom.diff_non_empty_fragment(to, old, new, Some(self.reference_to_dynamic_node(mount, idx))), + } + (Placeholder(_), Placeholder(_)) => {} + (Fragment(old), Fragment(new)) => dom.diff_non_empty_fragment( + to, + old, + new, + Some(self.reference_to_dynamic_node(mount, idx)), + ), (Component(old), Component(new)) => { - let scope_id = ScopeId(dom.mounts[mount.0].mounted_dynamic_nodes[idx]); - self.diff_vcomponent(mount, idx, new, old, scope_id, Some(self.reference_to_dynamic_node(mount, idx)), dom, to) - }, - (Placeholder(_), Fragment(right)) => { - let placeholder_id = ElementId(dom.mounts[mount.0].mounted_dynamic_nodes[idx]); - dom.replace_placeholder(to, placeholder_id, right, Some(self.reference_to_dynamic_node(mount, idx)))}, - (Fragment(left), Placeholder(_)) => { - dom.nodes_to_placeholder(to, mount, idx, left,) - }, - _ => todo!("This is an usual custom case for dynamic nodes. We don't know how to handle it yet."), + let scope_id = ScopeId(dom.mounts[mount.0].mounted_dynamic_nodes[idx]); + self.diff_vcomponent( + mount, + idx, + new, + old, + scope_id, + Some(self.reference_to_dynamic_node(mount, idx)), + dom, + to, + ) + } + (old, new) => { + // TODO: we should pass around the mount instead of the mount id + // that would make moving the mount around here much easier + + // Mark the mount as unused. When a scope is created, it reads the mount and + // if it is the placeholder value, it will create the scope, otherwise it will + // reuse the scope + let old_mount = dom.mounts[mount.0].mounted_dynamic_nodes[idx]; + dom.mounts[mount.0].mounted_dynamic_nodes[idx] = usize::MAX; + + let new_nodes_on_stack = + self.create_dynamic_node(new, mount, idx, dom, to.as_deref_mut()); + + // Restore the mount for the scope we are removing + let new_mount = dom.mounts[mount.0].mounted_dynamic_nodes[idx]; + dom.mounts[mount.0].mounted_dynamic_nodes[idx] = old_mount; + + self.remove_dynamic_node(mount, dom, to, true, idx, old, Some(new_nodes_on_stack)); + + // Restore the mount for the node we created + dom.mounts[mount.0].mounted_dynamic_nodes[idx] = new_mount; + } }; } - /// Replace a text node with a placeholder node - pub(crate) fn replace_text_with_placeholder( - &self, - to: Option<&mut impl WriteMutations>, - mount: MountId, - idx: usize, - dom: &mut VirtualDom, - ) { - if let Some(to) = to { - // Grab the text element id from the mount and replace it with a new placeholder - let text_id = ElementId(dom.mounts[mount.0].mounted_dynamic_nodes[idx]); - let (id, _) = self.create_dynamic_node_with_path(mount, idx, dom); - to.create_placeholder(id); - to.replace_node_with(text_id, 1); - dom.reclaim(text_id); - } - } - - /// Replace a placeholder node with a text node - pub(crate) fn replace_placeholder_with_text( - &self, - to: Option<&mut impl WriteMutations>, - mount: MountId, - idx: usize, - new: &VText, - dom: &mut VirtualDom, - ) { - if let Some(to) = to { - // Grab the placeholder id from the mount and replace it with a new text node - let placeholder_id = ElementId(dom.mounts[mount.0].mounted_dynamic_nodes[idx]); - let (new_id, _) = self.create_dynamic_node_with_path(mount, idx, dom); - to.create_text_node(&new.value, new_id); - dom.replace_placeholder_with_nodes_on_stack(to, placeholder_id, 1); - } - } - /// Try to get the dynamic node and its index for a root node pub(crate) fn get_dynamic_root_node_and_id( &self, @@ -401,12 +391,6 @@ impl VNode { }; } - fn templates_are_different(&self, other: &VNode) -> bool { - let self_node_name = self.template.id(); - let other_node_name = other.template.id(); - self_node_name != other_node_name - } - pub(super) fn reclaim_attributes(&self, mount: MountId, dom: &mut VirtualDom) { let mut next_id = None; for (idx, path) in self.template.attr_paths.iter().enumerate() { @@ -530,83 +514,6 @@ impl VNode { } } - /// Lightly diff the two templates, checking only their roots. - /// - /// The goal here is to preserve any existing component state that might exist. This is to preserve some React-like - /// behavior where the component state is preserved when the component is re-rendered. - /// - /// This is implemented by iterating each root, checking if the component is the same, if it is, then diff it. - /// - /// We then pass the new template through "create" which should be smart enough to skip roots. - /// - /// Currently, we only handle the case where the roots are the same component list. If there's any sort of deviation, - /// IE more nodes, less nodes, different nodes, or expressions, then we just replace the whole thing. - /// - /// This is mostly implemented to help solve the issue where the same component is rendered under two different - /// conditions: - /// - /// ```rust, no_run - /// # use dioxus::prelude::*; - /// # let enabled = true; - /// # #[component] - /// # fn Component(enabled_sign: String) -> Element { unimplemented!() } - /// if enabled { - /// rsx!{ Component { enabled_sign: "abc" } } - /// } else { - /// rsx!{ Component { enabled_sign: "xyz" } } - /// }; - /// ``` - /// - /// However, we should not that it's explicit in the docs that this is not a guarantee. If you need to preserve state, - /// then you should be passing in separate props instead. - /// - /// ```rust, no_run - /// # use dioxus::prelude::*; - /// # #[component] - /// # fn Component(enabled_sign: String) -> Element { unimplemented!() } - /// # let enabled = true; - /// let props = if enabled { - /// ComponentProps { enabled_sign: "abc".to_string() } - /// } else { - /// ComponentProps { enabled_sign: "xyz".to_string() } - /// }; - /// - /// rsx! { - /// Component { ..props } - /// }; - /// ``` - pub(crate) fn light_diff_templates( - &self, - new: &VNode, - dom: &mut VirtualDom, - mut to: Option<&mut impl WriteMutations>, - ) { - let mount_id = self.mount.get(); - let mount = &dom.mounts[mount_id.0]; - let parent = mount.parent; - match matching_components(self, new) { - None => self.replace(std::slice::from_ref(new), parent, dom, to), - Some(components) => { - self.move_mount_to(new, dom); - - for (idx, (old_component, new_component)) in components.into_iter().enumerate() { - let mount = &dom.mounts[mount_id.0]; - let scope_id = ScopeId(mount.mounted_dynamic_nodes[idx]); - self.diff_vcomponent( - mount_id, - idx, - new_component, - old_component, - scope_id, - parent, - dom, - to.as_deref_mut(), - ) - } - } - } - } - /// Create this rsx block. This will create scopes from components that this rsx block contains, but it will not write anything to the DOM. pub(crate) fn create( &self, @@ -634,13 +541,6 @@ impl VNode { }); } - // If we are outputting mutations, mount the node as well - if let Some(to) = to.as_deref_mut() { - // The best renderers will have templates pre-hydrated and registered - // Just in case, let's create the template using instructions anyways - dom.register_template(to, template); - } - // Walk the roots, creating nodes and assigning IDs // nodes in an iterator of (dynamic_node_index, path) and attrs in an iterator of (attr_index, path) let mut nodes = template.node_paths.iter().copied().enumerate().peekable(); @@ -671,7 +571,13 @@ impl VNode { // Take a dynamic node off the depth first iterator nodes.next().unwrap(); // Then mount the node - self.create_dynamic_node(mount, *id, dom, to.as_deref_mut()) + self.create_dynamic_node( + &self.dynamic_nodes[*id], + mount, + *id, + dom, + to.as_deref_mut(), + ) } // For static text and element nodes, just load the template root. This may be a placeholder or just a static node. We now know that each root node has a unique id TemplateNode::Text { .. } | TemplateNode::Element { .. } => { @@ -720,13 +626,13 @@ impl VNode { pub(crate) fn create_dynamic_node( &self, + node: &DynamicNode, mount: MountId, dynamic_node_id: usize, dom: &mut VirtualDom, to: Option<&mut impl WriteMutations>, ) -> usize { use DynamicNode::*; - let node = &self.dynamic_nodes[dynamic_node_id]; match node { Component(component) => { let parent = Some(self.reference_to_dynamic_node(mount, dynamic_node_id)); @@ -786,7 +692,13 @@ impl VNode { // Only take nodes that are under this root node let from_root_node = |(_, path): &(usize, &[u8])| path.first() == Some(&root_idx); while let Some((dynamic_node_id, path)) = dynamic_nodes_iter.next_if(from_root_node) { - let m = self.create_dynamic_node(mount, dynamic_node_id, dom, to.as_deref_mut()); + let m = self.create_dynamic_node( + &self.dynamic_nodes[dynamic_node_id], + mount, + dynamic_node_id, + dom, + to.as_deref_mut(), + ); if let Some(to) = to.as_deref_mut() { // If we actually created real new nodes, we need to replace the placeholder for this dynamic node with the new dynamic nodes if m > 0 { @@ -856,7 +768,7 @@ impl VNode { let this_id = dom.next_element(); dom.mounts[mount.0].root_ids[root_idx] = this_id; - to.load_template(self.template.name, root_idx, this_id); + to.load_template(self.template, root_idx, this_id); this_id } @@ -888,22 +800,6 @@ impl VNode { id } - /// Mount a root node and return its ID and the path to the node - fn create_dynamic_node_with_path( - &self, - mount: MountId, - idx: usize, - dom: &mut VirtualDom, - ) -> (ElementId, &'static [u8]) { - // Add the mutation to the list - let path = self.template.node_paths[idx]; - - // Allocate a dynamic element reference for this text node - let new_id = mount.mount_node(idx, dom); - - (new_id, &path[1..]) - } - fn create_dynamic_text( &self, mount: MountId, @@ -912,19 +808,12 @@ impl VNode { dom: &mut VirtualDom, to: &mut impl WriteMutations, ) -> usize { - let (new_id, path) = self.create_dynamic_node_with_path(mount, idx, dom); + let new_id = mount.mount_node(idx, dom); // If this is a root node, the path is empty and we need to create a new text node - if path.is_empty() { - to.create_text_node(&text.value, new_id); - // We create one node on the stack - 1 - } else { - // Dynamic text nodes always exist as a placeholder text node in the template, we can just hydrate that text node instead of creating a new one - to.hydrate_text_node(path, &text.value, new_id); - // Since we're hydrating an existing node, we don't create any new nodes - 0 - } + to.create_text_node(&text.value, new_id); + // We create one node on the stack + 1 } pub(crate) fn create_placeholder( @@ -934,19 +823,12 @@ impl VNode { dom: &mut VirtualDom, to: &mut impl WriteMutations, ) -> usize { - let (id, path) = self.create_dynamic_node_with_path(mount, idx, dom); + let new_id = mount.mount_node(idx, dom); // If this is a root node, the path is empty and we need to create a new placeholder node - if path.is_empty() { - to.create_placeholder(id); - // We create one node on the stack - 1 - } else { - // Assign the ID to the existing node in the template - to.assign_node_id(path, id); - // Since the placeholder is already in the DOM, we don't create any new nodes - 0 - } + to.create_placeholder(new_id); + // We create one node on the stack + 1 } } @@ -957,34 +839,3 @@ impl MountId { id } } - -fn matching_components<'a>( - left: &'a VNode, - right: &'a VNode, -) -> Option> { - let left_node = left.template; - let right_node = right.template; - if left_node.roots.len() != right_node.roots.len() { - return None; - } - - // run through the components, ensuring they're the same - left_node - .roots - .iter() - .zip(right_node.roots.iter()) - .map(|(l, r)| { - let (l, r) = match (l, r) { - (TemplateNode::Dynamic { id: l }, TemplateNode::Dynamic { id: r }) => (l, r), - _ => return None, - }; - - let (l, r) = match (&left.dynamic_nodes[*l], &right.dynamic_nodes[*r]) { - (Component(l), Component(r)) => (l, r), - _ => return None, - }; - - Some((l, r)) - }) - .collect() -} diff --git a/packages/core/src/error_boundary.rs b/packages/core/src/error_boundary.rs index 7c8ea6057..2de89ab49 100644 --- a/packages/core/src/error_boundary.rs +++ b/packages/core/src/error_boundary.rs @@ -527,7 +527,6 @@ impl Element + 'static> From for ErrorHandler { fn default_handler(errors: ErrorContext) -> Element { static TEMPLATE: Template = Template { - name: "error_handle.rs:42:5:884", roots: &[TemplateNode::Element { tag: "div", namespace: None, @@ -549,7 +548,6 @@ fn default_handler(errors: ErrorContext) -> Element { .iter() .map(|e| { static TEMPLATE: Template = Template { - name: "error_handle.rs:43:5:884", roots: &[TemplateNode::Element { tag: "pre", namespace: None, @@ -753,7 +751,6 @@ pub fn ErrorBoundary(props: ErrorBoundaryProps) -> Element { if errors.is_empty() { std::result::Result::Ok({ static TEMPLATE: Template = Template { - name: "examples/error_handle.rs:81:17:2342", roots: &[TemplateNode::Dynamic { id: 0usize }], node_paths: &[&[0u8]], attr_paths: &[], diff --git a/packages/core/src/hotreload_utils.rs b/packages/core/src/hotreload_utils.rs index 0fdab6413..7d8380ffd 100644 --- a/packages/core/src/hotreload_utils.rs +++ b/packages/core/src/hotreload_utils.rs @@ -235,15 +235,6 @@ impl DynamicValuePool { pub fn render_with(&mut self, hot_reload: &HotReloadedTemplate) -> VNode { // Get the node_paths from a depth first traversal of the template - let node_paths = hot_reload.node_paths(); - let attr_paths = hot_reload.attr_paths(); - - let template = Template { - name: hot_reload.name, - roots: hot_reload.roots, - node_paths, - attr_paths, - }; let key = hot_reload .key .as_ref() @@ -259,7 +250,7 @@ impl DynamicValuePool { .map(|attr| self.render_attribute(attr)) .collect(); - VNode::new(key, template, dynamic_nodes, dynamic_attrs) + VNode::new(key, hot_reload.template, dynamic_nodes, dynamic_attrs) } fn render_dynamic_node(&mut self, node: &HotReloadDynamicNode) -> DynamicNode { @@ -318,8 +309,8 @@ pub struct HotReloadTemplateWithLocation { #[doc(hidden)] #[derive(Debug, PartialEq, Clone)] #[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serialize", serde(bound(deserialize = "'de: 'static")))] pub struct HotReloadedTemplate { - pub name: &'static str, pub key: Option, pub dynamic_nodes: Vec, pub dynamic_attributes: Vec, @@ -329,28 +320,37 @@ pub struct HotReloadedTemplate { serde(deserialize_with = "crate::nodes::deserialize_leaky") )] pub roots: &'static [TemplateNode], + /// The template that is computed from the hot reload roots + template: Template, } impl HotReloadedTemplate { pub fn new( - name: &'static str, key: Option, dynamic_nodes: Vec, dynamic_attributes: Vec, component_values: Vec, roots: &'static [TemplateNode], ) -> Self { + let node_paths = Self::node_paths(roots); + let attr_paths = Self::attr_paths(roots); + + let template = Template { + roots, + node_paths, + attr_paths, + }; Self { - name, key, dynamic_nodes, dynamic_attributes, component_values, roots, + template, } } - fn node_paths(&self) -> &'static [&'static [u8]] { + fn node_paths(roots: &'static [TemplateNode]) -> &'static [&'static [u8]] { fn add_node_paths( roots: &[TemplateNode], node_paths: &mut Vec<&'static [u8]>, @@ -373,12 +373,12 @@ impl HotReloadedTemplate { } let mut node_paths = Vec::new(); - add_node_paths(self.roots, &mut node_paths, Vec::new()); + add_node_paths(roots, &mut node_paths, Vec::new()); let leaked: &'static [&'static [u8]] = Box::leak(node_paths.into_boxed_slice()); leaked } - fn attr_paths(&self) -> &'static [&'static [u8]] { + fn attr_paths(roots: &'static [TemplateNode]) -> &'static [&'static [u8]] { fn add_attr_paths( roots: &[TemplateNode], attr_paths: &mut Vec<&'static [u8]>, @@ -403,7 +403,7 @@ impl HotReloadedTemplate { } let mut attr_paths = Vec::new(); - add_attr_paths(self.roots, &mut attr_paths, Vec::new()); + add_attr_paths(roots, &mut attr_paths, Vec::new()); let leaked: &'static [&'static [u8]] = Box::leak(attr_paths.into_boxed_slice()); leaked } diff --git a/packages/core/src/mutations.rs b/packages/core/src/mutations.rs index 0fa2a1ce7..2d1ce81b3 100644 --- a/packages/core/src/mutations.rs +++ b/packages/core/src/mutations.rs @@ -1,6 +1,4 @@ -use rustc_hash::FxHashSet; - -use crate::{arena::ElementId, AttributeValue, ScopeId, Template}; +use crate::{arena::ElementId, AttributeValue, Template}; /// Something that can handle the mutations that are generated by the diffing process and apply them to the Real DOM /// @@ -14,9 +12,6 @@ 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); - /// Add these m children to the target element /// /// Id: The ID of the element being mounted to @@ -45,15 +40,6 @@ pub trait WriteMutations { /// Id: The ID we're assigning to this specific text nodes. This will be used later to modify the element or replace it with another element. fn create_text_node(&mut self, value: &str, id: ElementId); - /// Hydrate an existing text node at the given path with the given text. - /// - /// Assign this text node the given ID since we will likely need to modify this text at a later point - /// - /// Path: The path of the child of the topmost node on the stack. A path of `[]` represents the topmost node. A path of `[0]` represents the first child. `[0,1,2]` represents 1st child's 2nd child's 3rd child. - /// Value: The value of the textnode that we want to set the placeholder with - /// Id: The ID we're assigning to this specific text nodes. This will be used later to modify the element or replace it with another element. - fn hydrate_text_node(&mut self, path: &'static [u8], value: &str, id: ElementId); - /// Load and clone an existing node from a template saved under that specific name /// /// Dioxus guarantees that the renderer will have already been provided the template. @@ -62,7 +48,7 @@ pub trait WriteMutations { /// Name: The unique "name" of the template based on the template location. When paired with `rsx!`, this is autogenerated /// Index: The index root we loading from the template. The template is stored as a list of nodes. This index represents the position of that root /// Id: The ID we're assigning to this element being loaded from the template (This will be used later to move the element around in lists) - fn load_template(&mut self, name: &'static str, index: usize, id: ElementId); + fn load_template(&mut self, template: Template, index: usize, id: ElementId); /// Replace the target element (given by its ID) with the topmost m nodes on the stack /// @@ -129,12 +115,6 @@ pub trait WriteMutations { /// /// Id: The ID of the root node to push. fn push_root(&mut self, id: ElementId); - - /// Swap to a new subtree - fn swap_subtree(&mut self, _subtree_index: usize) {} - - /// Mark a scope as dirty - fn mark_scope_dirty(&mut self, _scope_id: ScopeId) {} } /// A `Mutation` represents a single instruction for the renderer to use to modify the UI tree to match the state @@ -156,8 +136,6 @@ pub enum Mutation { /// /// The path is in the form of a list of indices based on children. Templates cannot have more than 255 children per /// element, hence the use of a single byte. - /// - /// AssignId { /// The path of the child of the topmost node on the stack /// @@ -192,33 +170,11 @@ pub enum Mutation { id: ElementId, }, - /// Hydrate an existing text node at the given path with the given text. - /// - /// Assign this text node the given ID since we will likely need to modify this text at a later point - HydrateText { - /// The path of the child of the topmost node on the stack - /// - /// A path of `[]` represents the topmost node. A path of `[0]` represents the first child. - /// `[0,1,2]` represents 1st child's 2nd child's 3rd child. - path: &'static [u8], - - /// The value of the textnode that we want to set the placeholder with - value: String, - - /// The ID we're assigning to this specific text nodes - /// - /// This will be used later to modify the element or replace it with another element. - id: ElementId, - }, - - /// Load and clone an existing node from a template saved under that specific name + /// Load and clone an existing node from a template with a given ID /// /// Dioxus guarantees that the renderer will have already been provided the template. /// When the template is picked up in the template list, it should be saved under its "name" - here, the name LoadTemplate { - /// The "name" of the template. When paired with `rsx!`, this is autogenerated - name: &'static str, - /// Which root are we loading from the template? /// /// The template is stored as a list of nodes. This index represents the position of that root @@ -328,38 +284,11 @@ pub enum Mutation { /// A static list of mutations that can be applied to the DOM. Note: this list does not contain any `Any` attribute values #[derive(Debug, PartialEq, Default)] pub struct Mutations { - /// The list of Scopes that were diffed, created, and removed during the Diff process. - pub dirty_scopes: FxHashSet, - - /// Any templates encountered while diffing the DOM. - /// - /// These must be loaded into a cache before applying the edits - pub templates: Vec