port over more diffing + creation logic
This commit is contained in:
1 parent
717f38a5ec
commit
113b2c1529
7 files changed
+69
-68
No files matched your search
@@ -408,11 +408,7 @@ impl VirtualDom {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Insert a new template into the VirtualDom's template registry
|
/// Insert a new template into the VirtualDom's template registry
|
||||||
pub(crate) fn register_template_first_byte_index(
|
pub(crate) fn register_template_first_byte_index(&mut self, mut template: Template) {
|
||||||
&mut self,
|
|
||||||
mut template: Template<'static>,
|
|
||||||
to: &mut impl WriteMutations,
|
|
||||||
) {
|
|
||||||
// First, make sure we mark the template as seen, regardless if we process it
|
// First, make sure we mark the template as seen, regardless if we process it
|
||||||
let (path, _) = template.name.rsplit_once(':').unwrap();
|
let (path, _) = template.name.rsplit_once(':').unwrap();
|
||||||
if let Some((_, old_template)) = self
|
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 it's all dynamic nodes, then we don't need to register it
|
||||||
if !template.is_completely_dynamic() {
|
if !template.is_completely_dynamic() {
|
||||||
to.register_template(template);
|
self.queued_templates.push(template);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -444,7 +440,7 @@ impl VirtualDom {
|
|||||||
#[allow(unused_mut)]
|
#[allow(unused_mut)]
|
||||||
pub(crate) fn register_template(
|
pub(crate) fn register_template(
|
||||||
&mut self,
|
&mut self,
|
||||||
mut template: Template<'static>,
|
mut template: Template,
|
||||||
to: &mut impl WriteMutations,
|
to: &mut impl WriteMutations,
|
||||||
) {
|
) {
|
||||||
let (path, byte_index) = template.name.rsplit_once(':').unwrap();
|
let (path, byte_index) = template.name.rsplit_once(':').unwrap();
|
||||||
|
|||||||
+29
-38
@@ -6,7 +6,6 @@ use crate::{
|
|||||||
innerlude::{
|
innerlude::{
|
||||||
DirtyScope, ElementPath, ElementRef, VComponent, VPlaceholder, VText, WriteMutations,
|
DirtyScope, ElementPath, ElementRef, VComponent, VPlaceholder, VText, WriteMutations,
|
||||||
},
|
},
|
||||||
mutations::Mutation,
|
|
||||||
nodes::RenderReturn,
|
nodes::RenderReturn,
|
||||||
nodes::{DynamicNode, VNode},
|
nodes::{DynamicNode, VNode},
|
||||||
scopes::ScopeId,
|
scopes::ScopeId,
|
||||||
@@ -63,15 +62,10 @@ impl VirtualDom {
|
|||||||
*p.parent.borrow_mut() = l.parent.borrow().clone();
|
*p.parent.borrow_mut() = l.parent.borrow().clone();
|
||||||
to.create_placeholder(id);
|
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
|
// TODO: Instead of *just* removing it, we can use the replace mutation
|
||||||
// Since mutations are done in reverse, the last node removed will be the first in the stack
|
self.remove_node(l, true, to);
|
||||||
// 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"),
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn diff_node(
|
fn diff_node(
|
||||||
@@ -250,17 +244,12 @@ impl VirtualDom {
|
|||||||
parent: Option<ElementRef>,
|
parent: Option<ElementRef>,
|
||||||
to: &mut impl WriteMutations,
|
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);
|
self.remove_component_node(left, true, to);
|
||||||
|
|
||||||
// We want to optimize the replace case to use one less mutation if possible
|
todo!()
|
||||||
// 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),
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Lightly diff the two templates, checking only their roots.
|
/// Lightly diff the two templates, checking only their roots.
|
||||||
@@ -656,7 +645,7 @@ impl VirtualDom {
|
|||||||
let new_idx = idx + last + 1;
|
let new_idx = idx + last + 1;
|
||||||
let old_index = new_index_to_old_index[new_idx];
|
let old_index = new_index_to_old_index[new_idx];
|
||||||
if old_index == u32::MAX as usize {
|
if old_index == u32::MAX as usize {
|
||||||
nodes_created += self.create(new_node);
|
nodes_created += self.create(new_node, to);
|
||||||
} else {
|
} else {
|
||||||
self.diff_node(&old[old_index], new_node, to);
|
self.diff_node(&old[old_index], new_node, to);
|
||||||
nodes_created += self.push_all_real_nodes(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 new_idx = idx + next + 1;
|
||||||
let old_index = new_index_to_old_index[new_idx];
|
let old_index = new_index_to_old_index[new_idx];
|
||||||
if old_index == u32::MAX as usize {
|
if old_index == u32::MAX as usize {
|
||||||
nodes_created += self.create(new_node);
|
nodes_created += self.create(new_node, to);
|
||||||
} else {
|
} else {
|
||||||
self.diff_node(&old[old_index], new_node, to);
|
self.diff_node(&old[old_index], new_node, to);
|
||||||
nodes_created += self.push_all_real_nodes(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() {
|
for (idx, new_node) in new[..first_lis].iter().enumerate() {
|
||||||
let old_index = new_index_to_old_index[idx];
|
let old_index = new_index_to_old_index[idx];
|
||||||
if old_index == u32::MAX as usize {
|
if old_index == u32::MAX as usize {
|
||||||
nodes_created += self.create(new_node);
|
nodes_created += self.create(new_node, to);
|
||||||
} else {
|
} else {
|
||||||
self.diff_node(&old[old_index], new_node, to);
|
self.diff_node(&old[old_index], new_node, to);
|
||||||
nodes_created += self.push_all_real_nodes(new_node, to);
|
nodes_created += self.push_all_real_nodes(new_node, to);
|
||||||
@@ -768,7 +757,7 @@ impl VirtualDom {
|
|||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|child| {
|
.map(|child| {
|
||||||
self.assign_boundary_ref(parent, child);
|
self.assign_boundary_ref(parent, child);
|
||||||
self.create(child)
|
self.create(child, to)
|
||||||
})
|
})
|
||||||
.sum()
|
.sum()
|
||||||
}
|
}
|
||||||
@@ -807,7 +796,7 @@ impl VirtualDom {
|
|||||||
) {
|
) {
|
||||||
let m = self.create_children(r, Some(parent), to);
|
let m = self.create_children(r, Some(parent), to);
|
||||||
let id = l.id.get().unwrap();
|
let id = l.id.get().unwrap();
|
||||||
to.replace_with(id, m);
|
to.replace_node_with(id, m);
|
||||||
self.reclaim(id);
|
self.reclaim(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -820,15 +809,10 @@ impl VirtualDom {
|
|||||||
) {
|
) {
|
||||||
let m = self.create_children(right, parent, to);
|
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
|
self.remove_node(left, true, to);
|
||||||
// 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"),
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn node_to_placeholder(
|
fn node_to_placeholder(
|
||||||
@@ -846,15 +830,22 @@ impl VirtualDom {
|
|||||||
|
|
||||||
to.create_placeholder(placeholder);
|
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
|
// 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
|
// 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
|
// TODO: Instead of *just* removing it, we can use the replace mutation
|
||||||
match self.mutations.edits.pop().unwrap() {
|
to.insert_nodes_before(self.find_first_element(&nodes[0]), m);
|
||||||
Mutation::Remove { id } => self.mutations.push(Mutation::ReplaceWith { id, m: 1 }),
|
|
||||||
_ => panic!("Expected remove mutation from remove_node"),
|
debug_assert!(
|
||||||
};
|
!nodes.is_empty(),
|
||||||
|
"replace_nodes must have at least one node"
|
||||||
|
);
|
||||||
|
|
||||||
|
self.remove_nodes(&nodes, to);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Remove these nodes from the dom
|
/// 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) {
|
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
|
// Clean up any attributes that have claimed a static node as dynamic for mount/unmounta
|
||||||
// Will not generate mutations!
|
// Will not generate mutations!
|
||||||
self.reclaim_attributes(node, to);
|
self.reclaim_attributes(node);
|
||||||
|
|
||||||
// Remove the nested dynamic nodes
|
// Remove the nested dynamic nodes
|
||||||
// We don't generate mutations for these, as they will be removed by the parent (in the next line)
|
// 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;
|
let mut id = None;
|
||||||
for (idx, attr) in node.dynamic_attrs.iter().enumerate() {
|
for (idx, attr) in node.dynamic_attrs.iter().enumerate() {
|
||||||
// We'll clean up the root nodes either way, so don't worry
|
// We'll clean up the root nodes either way, so don't worry
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ use crate::{arena::ElementId, AttributeValue, ScopeId, Template};
|
|||||||
/// Mutations are the only link between the RealDOM and the VirtualDOM.
|
/// Mutations are the only link between the RealDOM and the VirtualDOM.
|
||||||
pub trait WriteMutations {
|
pub trait WriteMutations {
|
||||||
/// Register a template with the renderer
|
/// 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
|
/// Add these m children to the target element
|
||||||
///
|
///
|
||||||
@@ -333,7 +333,7 @@ pub struct MutationsVec {
|
|||||||
/// Any templates encountered while diffing the DOM.
|
/// Any templates encountered while diffing the DOM.
|
||||||
///
|
///
|
||||||
/// These must be loaded into a cache before applying the edits
|
/// These must be loaded into a cache before applying the edits
|
||||||
pub templates: Vec<Template<'static>>,
|
pub templates: Vec<Template>,
|
||||||
|
|
||||||
/// Any mutations required to patch the renderer to match the layout of the VirtualDom
|
/// Any mutations required to patch the renderer to match the layout of the VirtualDom
|
||||||
pub edits: Vec<Mutation>,
|
pub edits: Vec<Mutation>,
|
||||||
@@ -355,7 +355,7 @@ impl MutationsVec {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl WriteMutations for MutationsVec {
|
impl WriteMutations for MutationsVec {
|
||||||
fn register_template(&mut self, template: Template<'static>) {
|
fn register_template(&mut self, template: Template) {
|
||||||
self.templates.push(template)
|
self.templates.push(template)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -468,7 +468,7 @@ impl WriteMutations for MutationsVec {
|
|||||||
pub struct NoOpMutations;
|
pub struct NoOpMutations;
|
||||||
|
|
||||||
impl WriteMutations for NoOpMutations {
|
impl WriteMutations for NoOpMutations {
|
||||||
fn register_template(&mut self, template: Template<'static>) {}
|
fn register_template(&mut self, template: Template) {}
|
||||||
|
|
||||||
fn append_children(&mut self, id: ElementId, m: usize) {}
|
fn append_children(&mut self, id: ElementId, m: usize) {}
|
||||||
|
|
||||||
|
|||||||
@@ -55,7 +55,7 @@ pub struct VNodeInner {
|
|||||||
pub root_ids: RefCell<Vec<ElementId>>,
|
pub root_ids: RefCell<Vec<ElementId>>,
|
||||||
|
|
||||||
/// The static nodes and static descriptor of the template
|
/// The static nodes and static descriptor of the template
|
||||||
pub template: Cell<Template<'static>>,
|
pub template: Cell<Template>,
|
||||||
|
|
||||||
/// The dynamic parts of the template
|
/// The dynamic parts of the template
|
||||||
pub dynamic_nodes: Vec<DynamicNode>,
|
pub dynamic_nodes: Vec<DynamicNode>,
|
||||||
@@ -106,7 +106,7 @@ impl VNode {
|
|||||||
/// Create a new VNode
|
/// Create a new VNode
|
||||||
pub fn new(
|
pub fn new(
|
||||||
key: Option<String>,
|
key: Option<String>,
|
||||||
template: Template<'static>,
|
template: Template,
|
||||||
root_ids: Vec<ElementId>,
|
root_ids: Vec<ElementId>,
|
||||||
dynamic_nodes: Vec<DynamicNode>,
|
dynamic_nodes: Vec<DynamicNode>,
|
||||||
dynamic_attrs: Vec<Attribute>,
|
dynamic_attrs: Vec<Attribute>,
|
||||||
@@ -144,7 +144,7 @@ impl VNode {
|
|||||||
/// ways, with the suggested approach being the unique code location (file, line, col, etc).
|
/// ways, with the suggested approach being the unique code location (file, line, col, etc).
|
||||||
#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
|
#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Hash, Eq, PartialOrd, Ord)]
|
#[derive(Debug, Clone, Copy, PartialEq, Hash, Eq, PartialOrd, Ord)]
|
||||||
pub struct Template<'a> {
|
pub struct Template {
|
||||||
/// The name of the template. This must be unique across your entire program for template diffing to work properly
|
/// The name of the template. This must be unique across your entire program for template diffing to work properly
|
||||||
///
|
///
|
||||||
/// If two templates have the same name, it's likely that Dioxus will panic when diffing.
|
/// If two templates have the same name, it's likely that Dioxus will panic when diffing.
|
||||||
@@ -152,13 +152,13 @@ pub struct Template<'a> {
|
|||||||
feature = "serialize",
|
feature = "serialize",
|
||||||
serde(deserialize_with = "deserialize_string_leaky")
|
serde(deserialize_with = "deserialize_string_leaky")
|
||||||
)]
|
)]
|
||||||
pub name: &'a str,
|
pub name: &'static str,
|
||||||
|
|
||||||
/// The list of template nodes that make up the template
|
/// The list of template nodes that make up the template
|
||||||
///
|
///
|
||||||
/// Unlike react, calls to `rsx!` can have multiple roots. This list supports that paradigm.
|
/// Unlike react, calls to `rsx!` can have multiple roots. This list supports that paradigm.
|
||||||
#[cfg_attr(feature = "serialize", serde(deserialize_with = "deserialize_leaky"))]
|
#[cfg_attr(feature = "serialize", serde(deserialize_with = "deserialize_leaky"))]
|
||||||
pub roots: &'a [TemplateNode],
|
pub roots: &'static [TemplateNode],
|
||||||
|
|
||||||
/// The paths of each node relative to the root of the template.
|
/// The paths of each node relative to the root of the template.
|
||||||
///
|
///
|
||||||
@@ -168,7 +168,7 @@ pub struct Template<'a> {
|
|||||||
feature = "serialize",
|
feature = "serialize",
|
||||||
serde(deserialize_with = "deserialize_bytes_leaky")
|
serde(deserialize_with = "deserialize_bytes_leaky")
|
||||||
)]
|
)]
|
||||||
pub node_paths: &'a [&'a [u8]],
|
pub node_paths: &'static [&'static [u8]],
|
||||||
|
|
||||||
/// The paths of each dynamic attribute relative to the root of the template
|
/// The paths of each dynamic attribute relative to the root of the template
|
||||||
///
|
///
|
||||||
@@ -178,7 +178,7 @@ pub struct Template<'a> {
|
|||||||
feature = "serialize",
|
feature = "serialize",
|
||||||
serde(deserialize_with = "deserialize_bytes_leaky")
|
serde(deserialize_with = "deserialize_bytes_leaky")
|
||||||
)]
|
)]
|
||||||
pub attr_paths: &'a [&'a [u8]],
|
pub attr_paths: &'static [&'static [u8]],
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "serialize")]
|
#[cfg(feature = "serialize")]
|
||||||
@@ -232,7 +232,7 @@ where
|
|||||||
Ok(deserialized.map(|deserialized| &*Box::leak(deserialized.into_boxed_str())))
|
Ok(deserialized.map(|deserialized| &*Box::leak(deserialized.into_boxed_str())))
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Template<'a> {
|
impl Template {
|
||||||
/// Is this template worth caching at all, since it's completely runtime?
|
/// Is this template worth caching at all, since it's completely runtime?
|
||||||
///
|
///
|
||||||
/// There's no point in saving templates that are completely dynamic, since they'll be recreated every time anyway.
|
/// There's no point in saving templates that are completely dynamic, since they'll be recreated every time anyway.
|
||||||
|
|||||||
@@ -310,7 +310,7 @@ impl<'src> ScopeState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Create a new [`EventHandler`] from an [`FnMut`]
|
/// Create a new [`EventHandler`] from an [`FnMut`]
|
||||||
pub fn event_handler<T>(&self, f: impl FnMut(T)) -> EventHandler<T> {
|
pub fn event_handler<T>(&self, f: impl FnMut(T) + 'static) -> EventHandler<T> {
|
||||||
let callback = RefCell::new(Some(Box::new(move |event: T| {
|
let callback = RefCell::new(Some(Box::new(move |event: T| {
|
||||||
f(event);
|
f(event);
|
||||||
}) as Box<dyn FnMut(T)>));
|
}) as Box<dyn FnMut(T)>));
|
||||||
@@ -324,8 +324,8 @@ impl<'src> ScopeState {
|
|||||||
///
|
///
|
||||||
/// The callback must be confined to the lifetime of the ScopeState
|
/// The callback must be confined to the lifetime of the ScopeState
|
||||||
pub fn listener<T: 'static>(
|
pub fn listener<T: 'static>(
|
||||||
&'src self,
|
&self,
|
||||||
mut callback: impl FnMut(Event<T>) + 'src,
|
mut callback: impl FnMut(Event<T>) + 'static,
|
||||||
) -> AttributeValue {
|
) -> AttributeValue {
|
||||||
AttributeValue::Listener(RefCell::new(Box::new(move |event: Event<dyn Any>| {
|
AttributeValue::Listener(RefCell::new(Box::new(move |event: Event<dyn Any>| {
|
||||||
if let Ok(data) = event.data.downcast::<T>() {
|
if let Ok(data) = event.data.downcast::<T>() {
|
||||||
|
|||||||
@@ -6,10 +6,9 @@ use crate::{
|
|||||||
any_props::{BoxedAnyProps, VProps},
|
any_props::{BoxedAnyProps, VProps},
|
||||||
arena::ElementId,
|
arena::ElementId,
|
||||||
innerlude::{
|
innerlude::{
|
||||||
DirtyScope, ElementRef, ErrorBoundary, Mutations, NoOpMutations, Scheduler, SchedulerMsg,
|
DirtyScope, ElementRef, ErrorBoundary, NoOpMutations, Scheduler, SchedulerMsg,
|
||||||
WriteMutations,
|
WriteMutations,
|
||||||
},
|
},
|
||||||
mutations::Mutation,
|
|
||||||
nodes::RenderReturn,
|
nodes::RenderReturn,
|
||||||
nodes::{Template, TemplateId},
|
nodes::{Template, TemplateId},
|
||||||
runtime::{Runtime, RuntimeGuard},
|
runtime::{Runtime, RuntimeGuard},
|
||||||
@@ -186,7 +185,10 @@ pub struct VirtualDom {
|
|||||||
pub(crate) dirty_scopes: BTreeSet<DirtyScope>,
|
pub(crate) dirty_scopes: BTreeSet<DirtyScope>,
|
||||||
|
|
||||||
// Maps a template path to a map of byteindexes to templates
|
// Maps a template path to a map of byteindexes to templates
|
||||||
pub(crate) templates: FxHashMap<TemplateId, FxHashMap<usize, Template<'static>>>,
|
pub(crate) templates: FxHashMap<TemplateId, FxHashMap<usize, Template>>,
|
||||||
|
|
||||||
|
// Templates changes that are queued for the next render
|
||||||
|
pub(crate) queued_templates: Vec<Template>,
|
||||||
|
|
||||||
// The element ids that are used in the renderer
|
// The element ids that are used in the renderer
|
||||||
pub(crate) elements: Slab<Option<ElementRef>>,
|
pub(crate) elements: Slab<Option<ElementRef>>,
|
||||||
@@ -263,6 +265,7 @@ impl VirtualDom {
|
|||||||
scopes: Default::default(),
|
scopes: Default::default(),
|
||||||
dirty_scopes: Default::default(),
|
dirty_scopes: Default::default(),
|
||||||
templates: Default::default(),
|
templates: Default::default(),
|
||||||
|
queued_templates: Default::default(),
|
||||||
elements: Default::default(),
|
elements: Default::default(),
|
||||||
suspended_scopes: Default::default(),
|
suspended_scopes: Default::default(),
|
||||||
};
|
};
|
||||||
@@ -361,7 +364,6 @@ impl VirtualDom {
|
|||||||
_ => return,
|
_ => return,
|
||||||
};
|
};
|
||||||
let mut parent_node = Some(parent_path);
|
let mut parent_node = Some(parent_path);
|
||||||
let mut listeners = vec![];
|
|
||||||
|
|
||||||
// We will clone this later. The data itself is wrapped in RC to be used in callbacks if required
|
// We will clone this later. The data itself is wrapped in RC to be used in callbacks if required
|
||||||
let uievent = Event {
|
let uievent = Event {
|
||||||
@@ -373,6 +375,8 @@ impl VirtualDom {
|
|||||||
if bubbles {
|
if bubbles {
|
||||||
// Loop through each dynamic attribute (in a depth first order) in this template before moving up to the template's parent.
|
// Loop through each dynamic attribute (in a depth first order) in this template before moving up to the template's parent.
|
||||||
while let Some(path) = parent_node {
|
while let Some(path) = parent_node {
|
||||||
|
let mut listeners = vec![];
|
||||||
|
|
||||||
let el_ref = &path.element;
|
let el_ref = &path.element;
|
||||||
let node_template = el_ref.template.get();
|
let node_template = el_ref.template.get();
|
||||||
let target_path = path.path;
|
let target_path = path.path;
|
||||||
@@ -397,7 +401,7 @@ impl VirtualDom {
|
|||||||
|
|
||||||
// Now that we've accumulated all the parent attributes for the target element, call them in reverse order
|
// Now that we've accumulated all the parent attributes for the target element, call them in reverse order
|
||||||
// We check the bubble state between each call to see if the event has been stopped from bubbling
|
// We check the bubble state between each call to see if the event has been stopped from bubbling
|
||||||
for listener in listeners.drain(..).rev() {
|
for listener in listeners.into_iter().rev() {
|
||||||
if let AttributeValue::Listener(listener) = listener {
|
if let AttributeValue::Listener(listener) = listener {
|
||||||
let origin = path.scope;
|
let origin = path.scope;
|
||||||
self.runtime.scope_stack.borrow_mut().push(origin);
|
self.runtime.scope_stack.borrow_mut().push(origin);
|
||||||
@@ -505,7 +509,7 @@ impl VirtualDom {
|
|||||||
/// The caller must ensure that the template refrences the same dynamic attributes and nodes as the original template.
|
/// The caller must ensure that the template refrences the same dynamic attributes and nodes as the original template.
|
||||||
///
|
///
|
||||||
/// This will only replace the the parent template, not any nested templates.
|
/// This will only replace the the parent template, not any nested templates.
|
||||||
pub fn replace_template(&mut self, template: Template<'static>) {
|
pub fn replace_template(&mut self, template: Template) {
|
||||||
self.register_template_first_byte_index(template);
|
self.register_template_first_byte_index(template);
|
||||||
// iterating a slab is very inefficient, but this is a rare operation that will only happen during development so it's fine
|
// iterating a slab is very inefficient, but this is a rare operation that will only happen during development so it's fine
|
||||||
for (_, scope) in self.scopes.iter() {
|
for (_, scope) in self.scopes.iter() {
|
||||||
@@ -545,8 +549,9 @@ impl VirtualDom {
|
|||||||
/// apply_edits(edits);
|
/// apply_edits(edits);
|
||||||
/// ```
|
/// ```
|
||||||
pub fn rebuild(&mut self, to: &mut impl WriteMutations) {
|
pub fn rebuild(&mut self, to: &mut impl WriteMutations) {
|
||||||
|
self.flush_templates(to);
|
||||||
let _runtime = RuntimeGuard::new(self.runtime.clone());
|
let _runtime = RuntimeGuard::new(self.runtime.clone());
|
||||||
match unsafe { self.run_scope(ScopeId::ROOT) } {
|
match self.run_scope(ScopeId::ROOT) {
|
||||||
// Rebuilding implies we append the created elements to the root
|
// Rebuilding implies we append the created elements to the root
|
||||||
RenderReturn::Ready(node) => {
|
RenderReturn::Ready(node) => {
|
||||||
let m = self.create_scope(ScopeId::ROOT, &node, to);
|
let m = self.create_scope(ScopeId::ROOT, &node, to);
|
||||||
@@ -565,6 +570,7 @@ impl VirtualDom {
|
|||||||
/// Render whatever the VirtualDom has ready as fast as possible without requiring an executor to progress
|
/// Render whatever the VirtualDom has ready as fast as possible without requiring an executor to progress
|
||||||
/// suspended subtrees.
|
/// suspended subtrees.
|
||||||
pub fn render_immediate(&mut self, to: &mut impl WriteMutations) {
|
pub fn render_immediate(&mut self, to: &mut impl WriteMutations) {
|
||||||
|
self.flush_templates(to);
|
||||||
// Build a waker that won't wake up since our deadline is already expired when it's polled
|
// Build a waker that won't wake up since our deadline is already expired when it's polled
|
||||||
let waker = futures_util::task::noop_waker();
|
let waker = futures_util::task::noop_waker();
|
||||||
let mut cx = std::task::Context::from_waker(&waker);
|
let mut cx = std::task::Context::from_waker(&waker);
|
||||||
@@ -605,6 +611,7 @@ impl VirtualDom {
|
|||||||
deadline: impl Future<Output = ()>,
|
deadline: impl Future<Output = ()>,
|
||||||
to: &mut impl WriteMutations,
|
to: &mut impl WriteMutations,
|
||||||
) {
|
) {
|
||||||
|
self.flush_templates(to);
|
||||||
pin_mut!(deadline);
|
pin_mut!(deadline);
|
||||||
|
|
||||||
self.process_events();
|
self.process_events();
|
||||||
@@ -653,6 +660,13 @@ impl VirtualDom {
|
|||||||
pub fn runtime(&self) -> Rc<Runtime> {
|
pub fn runtime(&self) -> Rc<Runtime> {
|
||||||
self.runtime.clone()
|
self.runtime.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Flush any queued template changes
|
||||||
|
pub fn flush_templates(&mut self, to: &mut impl WriteMutations) {
|
||||||
|
for template in self.queued_templates.drain(..) {
|
||||||
|
to.register_template(template);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Drop for VirtualDom {
|
impl Drop for VirtualDom {
|
||||||
|
|||||||
@@ -130,7 +130,7 @@ enum DynamicNodeType {
|
|||||||
Other,
|
Other,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn create_random_template(name: &'static str) -> (Template<'static>, Vec<DynamicNodeType>) {
|
fn create_random_template(name: &'static str) -> (Template, Vec<DynamicNodeType>) {
|
||||||
let mut dynamic_node_type = Vec::new();
|
let mut dynamic_node_type = Vec::new();
|
||||||
let mut template_idx = 0;
|
let mut template_idx = 0;
|
||||||
let mut attr_idx = 0;
|
let mut attr_idx = 0;
|
||||||
|
|||||||
Reference in new issue
Block a user