diff --git a/packages/native-core/src/node.rs b/packages/native-core/src/node.rs index 09dd03e71..f73e0dc07 100644 --- a/packages/native-core/src/node.rs +++ b/packages/native-core/src/node.rs @@ -21,7 +21,6 @@ pub struct NodeData { pub node_type: NodeType, /// The number of parents before the root node. The root node has height 1. pub height: u16, - height_dirty: bool, } /// A type of node with data specific to the node type. The types are a subset of the [VNode] types. @@ -48,7 +47,6 @@ impl Node { node_type, height: 0, node_id: NodeId(0), - height_dirty: true, }, } } diff --git a/packages/native-core/src/real_dom.rs b/packages/native-core/src/real_dom.rs index cbeb80f2b..164fcd3e1 100644 --- a/packages/native-core/src/real_dom.rs +++ b/packages/native-core/src/real_dom.rs @@ -1,7 +1,7 @@ use anymap::AnyMap; use dioxus_core::{ElementId, Mutations}; use rustc_hash::{FxHashMap, FxHashSet}; -use std::ops::{Deref, DerefMut, Index, IndexMut}; +use std::ops::{Index, IndexMut}; use crate::node::{Node, NodeData, NodeType, OwnedAttributeDiscription}; use crate::node_ref::{AttributeMask, NodeMask}; @@ -9,6 +9,18 @@ use crate::state::State; use crate::tree::{NodeId, Tree, TreeLike, TreeView}; use crate::RealNodeId; +fn mark_dirty( + node_id: NodeId, + mask: NodeMask, + nodes_updated: &mut FxHashMap, +) { + if let Some(node) = nodes_updated.get_mut(&node_id) { + *node = node.union(&mask); + } else { + nodes_updated.insert(node_id, mask); + } +} + /// A Dom that can sync with the VirtualDom mutations intended for use in lazy renderers. /// The render state passes from parent to children and or accumulates state from children to parents. /// To get started implement [crate::state::ParentDepState], [crate::state::NodeDepState], or [crate::state::ChildDepState] and call [RealDom::apply_mutations] to update the dom and [RealDom::update_state] to update the state of the nodes. @@ -79,12 +91,31 @@ impl RealDom { node_id } + fn add_child(&mut self, node_id: RealNodeId, child_id: RealNodeId) { + self.tree.add_child(node_id, child_id); + self.resolve_height(child_id); + } + + fn resolve_height(&mut self, node_id: RealNodeId) { + if let Some((node, parent)) = self.tree.node_parent_mut(node_id) { + let height = parent.node_data.height; + node.node_data.height = height + 1; + unsafe { + let self_mut = self as *mut Self; + // Safety: No node will have itself as a child + for child in self.tree.children_ids(node_id).unwrap() { + (*self_mut).resolve_height(*child); + } + } + } + } + /// Updates the dom with some mutations and return a set of nodes that were updated. Pass the dirty nodes to update_state. - pub fn apply_mutations<'a>( + pub fn apply_mutations( &mut self, - mutations_vec: Vec>, - ) -> Vec<(RealNodeId, NodeMask)> { - let mut nodes_updated: Vec<(RealNodeId, NodeMask)> = Vec::new(); + mutations_vec: Vec, + ) -> FxHashMap { + let mut nodes_updated: FxHashMap = FxHashMap::default(); for mutations in mutations_vec { for e in mutations.edits { use dioxus_core::Mutation::*; @@ -93,12 +124,12 @@ impl RealDom { let data = self.stack.split_off(m); let (parent, children) = data.split_first().unwrap(); for child in children { - self.tree.add_child(*parent, *child); - nodes_updated.push((*parent, NodeMask::ALL)); + self.add_child(*parent, *child); + mark_dirty(*parent, NodeMask::ALL, &mut nodes_updated); } } AssignId { path, id } => { - self.set_element_id(self.load_child(&path), id); + self.set_element_id(self.load_child(path), id); } CreateElement { name } => { let node = Node::new(NodeType::Element { @@ -109,7 +140,7 @@ impl RealDom { }); let id = self.create_node(node); self.stack.push(id); - nodes_updated.push((id, NodeMask::ALL)); + mark_dirty(id, NodeMask::ALL, &mut nodes_updated); } CreateElementNamespace { name, namespace } => { let node = Node::new(NodeType::Element { @@ -120,20 +151,20 @@ impl RealDom { }); let id = self.create_node(node); self.stack.push(id); - nodes_updated.push((id, NodeMask::ALL)); + mark_dirty(id, NodeMask::ALL, &mut nodes_updated); } CreatePlaceholder { id } => { let node = Node::new(NodeType::Placeholder); let node_id = self.create_node(node); self.set_element_id(node_id, id); self.stack.push(node_id); - nodes_updated.push((node_id, NodeMask::ALL)); + mark_dirty(node_id, NodeMask::ALL, &mut nodes_updated); } CreateStaticPlaceholder => { let node = Node::new(NodeType::Placeholder); let id = self.create_node(node); self.stack.push(id); - nodes_updated.push((id, NodeMask::ALL)); + mark_dirty(id, NodeMask::ALL, &mut nodes_updated); } CreateStaticText { value } => { let node = Node::new(NodeType::Text { @@ -141,7 +172,7 @@ impl RealDom { }); let id = self.create_node(node); self.stack.push(id); - nodes_updated.push((id, NodeMask::new().with_text())); + mark_dirty(id, NodeMask::new().with_text(), &mut nodes_updated); } CreateTextNode { value, id } => { let node = Node::new(NodeType::Text { @@ -151,7 +182,7 @@ impl RealDom { let node = self.tree.get_mut(node_id).unwrap(); node.node_data.element_id = Some(id); self.stack.push(node_id); - nodes_updated.push((node_id, NodeMask::new().with_text())); + mark_dirty(node_id, NodeMask::new().with_text(), &mut nodes_updated); } HydrateText { path, value, id } => { let node_id = self.load_child(path); @@ -160,7 +191,7 @@ impl RealDom { if let NodeType::Text { text } = &mut node.node_data.node_type { *text = value.to_string(); } - nodes_updated.push((node_id, NodeMask::new().with_text())); + mark_dirty(node_id, NodeMask::new().with_text(), &mut nodes_updated); } LoadTemplate { name, index, id } => { let template_id = self.templates[name][index]; @@ -172,7 +203,7 @@ impl RealDom { let old_node_id = self.element_to_node_id(id); for new in new_nodes { self.tree.insert_after(old_node_id, new); - nodes_updated.push((new, NodeMask::ALL)); + mark_dirty(new, NodeMask::ALL, &mut nodes_updated); } self.tree.remove(old_node_id); } @@ -181,7 +212,7 @@ impl RealDom { let old_node_id = self.load_child(path); for new in new_nodes { self.tree.insert_after(old_node_id, new); - nodes_updated.push((new, NodeMask::ALL)); + mark_dirty(new, NodeMask::ALL, &mut nodes_updated); } self.tree.remove(old_node_id); } @@ -190,7 +221,7 @@ impl RealDom { let old_node_id = self.element_to_node_id(id); for new in new_nodes { self.tree.insert_after(old_node_id, new); - nodes_updated.push((new, NodeMask::ALL)); + mark_dirty(new, NodeMask::ALL, &mut nodes_updated); } } InsertBefore { id, m } => { @@ -198,7 +229,7 @@ impl RealDom { let old_node_id = self.element_to_node_id(id); for new in new_nodes { self.tree.insert_before(old_node_id, new); - nodes_updated.push((new, NodeMask::ALL)); + mark_dirty(new, NodeMask::ALL, &mut nodes_updated); } } SaveTemplate { name, m } => { @@ -223,10 +254,11 @@ impl RealDom { }, crate::node::OwnedAttributeValue::Text(value.to_string()), ); - nodes_updated.push(( + mark_dirty( node_id, NodeMask::new_with_attrs(AttributeMask::single(name)), - )); + &mut nodes_updated, + ); } } SetStaticAttribute { name, value, ns } => { @@ -242,10 +274,11 @@ impl RealDom { }, crate::node::OwnedAttributeValue::Text(value.to_string()), ); - nodes_updated.push(( + mark_dirty( *node_id, NodeMask::new_with_attrs(AttributeMask::single(name)), - )); + &mut nodes_updated, + ); } } SetBoolAttribute { name, value, id } => { @@ -261,10 +294,11 @@ impl RealDom { }, crate::node::OwnedAttributeValue::Bool(value), ); - nodes_updated.push(( + mark_dirty( node_id, NodeMask::new_with_attrs(AttributeMask::single(name)), - )); + &mut nodes_updated, + ); } } SetInnerText { value } => { @@ -276,7 +310,7 @@ impl RealDom { text: value.to_string(), }); let text_node_id = self.create_node(text_node); - self.tree.add_child(node_id, text_node_id); + self.add_child(node_id, text_node_id); } } SetText { value, id } => { @@ -285,7 +319,7 @@ impl RealDom { if let NodeType::Text { text } = &mut node.node_data.node_type { *text = value.to_string(); } - nodes_updated.push((node_id, NodeMask::new().with_text())); + mark_dirty(node_id, NodeMask::new().with_text(), &mut nodes_updated); } NewEventListener { event_name, @@ -321,14 +355,14 @@ impl RealDom { } Remove { id } => { let node_id = self.element_to_node_id(id); - self.remove(node_id); + self.tree.remove(node_id); } } } } // remove any nodes that were created and then removed in the same mutations from the dirty nodes list - nodes_updated.retain(|n| self.tree.get(n.0).is_some()); + nodes_updated.retain(|k, _| self.tree.get(*k).is_some()); nodes_updated } @@ -336,7 +370,7 @@ impl RealDom { /// Update the state of the dom, after appling some mutations. This will keep the nodes in the dom up to date with their VNode counterparts. pub fn update_state( &mut self, - nodes_updated: Vec<(RealNodeId, NodeMask)>, + nodes_updated: FxHashMap, ctx: AnyMap, ) -> FxHashSet { let (mut state_tree, node_tree) = self.split(); @@ -370,8 +404,12 @@ impl RealDom { let raw = self as *mut Self; // this is safe beacuse the treeview trait does not allow mutation of the position of elements, and within elements the access is disjoint. ( - unsafe { &mut *raw }.map(|n| &n.state, |n| &mut n.state), - unsafe { &mut *raw }.map(|n| &n.node_data, |n| &mut n.node_data), + unsafe { &mut *raw } + .tree + .map(|n| &n.state, |n| &mut n.state), + unsafe { &mut *raw } + .tree + .map(|n| &n.node_data, |n| &mut n.node_data), ) } @@ -385,7 +423,7 @@ impl RealDom { // this is safe because no node has itself as a child let self_mut = &mut *self_ptr; let child_id = self_mut.clone_node(*child); - self_mut.tree.add_child(new_id, child_id); + self_mut.add_child(new_id, child_id); } } new_id @@ -419,17 +457,3 @@ impl IndexMut for RealDom { self.tree.get_mut(idx).unwrap() } } - -impl Deref for RealDom { - type Target = Tree>; - - fn deref(&self) -> &Self::Target { - &self.tree - } -} - -impl DerefMut for RealDom { - fn deref_mut(&mut self) -> &mut Self::Target { - &mut self.tree - } -} diff --git a/packages/native-core/src/state.rs b/packages/native-core/src/state.rs index 9657a1c21..18d405ed7 100644 --- a/packages/native-core/src/state.rs +++ b/packages/native-core/src/state.rs @@ -5,7 +5,7 @@ use crate::node_ref::{NodeMask, NodeView}; use crate::tree::TreeView; use crate::RealNodeId; use anymap::AnyMap; -use rustc_hash::FxHashSet; +use rustc_hash::{FxHashMap, FxHashSet}; /// Join two sorted iterators pub(crate) fn union_ordered_iter<'a>( @@ -81,15 +81,15 @@ pub trait ChildDepState { /// The context is passed to the [ChildDepState::reduce] when it is resolved. type Ctx; /// A state from each child node that this node depends on. Typically this is Self, but it could be any state that is within the state tree. - /// This must be either a [ChildDepState], or [NodeDepState]. - type DepState; + /// Depstate must be a tuple containing any number of borrowed elements that are either [ChildDepState] or [NodeDepState]. + type DepState: ElementBorrowable; /// The part of a node that this state cares about. This is used to determine if the state should be updated when a node is updated. const NODE_MASK: NodeMask = NodeMask::NONE; /// Resolve the state current node's state from the state of the children, the state of the node, and some external context. fn reduce<'a>( &mut self, node: NodeView, - children: impl Iterator, + children: impl Iterator::ElementBorrowed<'a>>, ctx: &Self::Ctx, ) -> bool where @@ -143,15 +143,15 @@ pub trait ParentDepState { /// The context is passed to the [ParentDepState::reduce] when it is resolved. type Ctx; /// A state from from the parent node that this node depends on. Typically this is Self, but it could be any state that is within the state tree. - /// This must be either a [ParentDepState] or [NodeDepState] - type DepState; + /// Depstate must be a tuple containing any number of borrowed elements that are either [ParentDepState] or [NodeDepState]. + type DepState: ElementBorrowable; /// The part of a node that this state cares about. This is used to determine if the state should be updated when a node is updated. const NODE_MASK: NodeMask = NodeMask::NONE; /// Resolve the state current node's state from the state of the parent node, the state of the node, and some external context. fn reduce<'a>( &mut self, node: NodeView, - parent: Option<&'a Self::DepState>, + parent: Option<::ElementBorrowed<'a>>, ctx: &Self::Ctx, ) -> bool; } @@ -193,23 +193,27 @@ pub trait ParentDepState { /// } /// } /// ``` -/// The generic argument (Depstate) must be a tuple containing any number of borrowed elements that are either a [ChildDepState], [ParentDepState] or [NodeDepState]. -// Todo: once GATs land we can model multable dependencies better - -pub trait NodeDepState { +pub trait NodeDepState { + /// Depstate must be a tuple containing any number of borrowed elements that are either [ChildDepState], [ParentDepState] or [NodeDepState]. + type DepState: ElementBorrowable; /// The state passed to [NodeDepState::reduce] when it is resolved. type Ctx; /// The part of a node that this state cares about. This is used to determine if the state should be updated when a node is updated. const NODE_MASK: NodeMask = NodeMask::NONE; /// Resolve the state current node's state from the state of the sibling states, the state of the node, and some external context. - fn reduce(&mut self, node: NodeView, siblings: DepState, ctx: &Self::Ctx) -> bool; + fn reduce<'a>( + &mut self, + node: NodeView, + siblings: ::ElementBorrowed<'a>, + ctx: &Self::Ctx, + ) -> bool; } /// Do not implement this trait. It is only meant to be derived and used through [crate::real_dom::RealDom]. pub trait State: Default + Clone { #[doc(hidden)] fn update<'a, T: TreeView, T2: TreeView>( - dirty: &[(RealNodeId, NodeMask)], + dirty: &FxHashMap, state_tree: &'a mut T, rdom: &'a T2, ctx: &AnyMap, @@ -219,12 +223,7 @@ pub trait State: Default + Clone { impl ChildDepState for () { type Ctx = (); type DepState = (); - fn reduce<'a>( - &mut self, - _: NodeView, - _: impl Iterator, - _: &Self::Ctx, - ) -> bool + fn reduce<'a>(&mut self, _: NodeView, _: impl Iterator, _: &Self::Ctx) -> bool where Self::DepState: 'a, { @@ -235,14 +234,55 @@ impl ChildDepState for () { impl ParentDepState for () { type Ctx = (); type DepState = (); - fn reduce<'a>(&mut self, _: NodeView, _: Option<&'a Self::DepState>, _: &Self::Ctx) -> bool { + fn reduce<'a>(&mut self, _: NodeView, _: Option<()>, _: &Self::Ctx) -> bool { false } } -impl NodeDepState<()> for () { +impl NodeDepState for () { + type DepState = (); type Ctx = (); fn reduce(&mut self, _: NodeView, _sibling: (), _: &Self::Ctx) -> bool { false } } + +pub trait ElementBorrowable { + type ElementBorrowed<'a> + where + Self: 'a; + + fn borrow_elements(&self) -> Self::ElementBorrowed<'_>; +} + +macro_rules! impl_element_borrowable { + ($($t:ident),*) => { + impl< $($t),* > ElementBorrowable for ($($t,)*) { + type ElementBorrowed<'a> = ($(&'a $t,)*) where Self: 'a; + + #[allow(clippy::unused_unit, non_snake_case)] + fn borrow_elements<'a>(&'a self) -> Self::ElementBorrowed<'a> { + let ($($t,)*) = self; + ($(&$t,)*) + } + } + }; +} + +impl_element_borrowable!(); +impl_element_borrowable!(A); +impl_element_borrowable!(A, B); +impl_element_borrowable!(A, B, C); +impl_element_borrowable!(A, B, C, D); +impl_element_borrowable!(A, B, C, D, E); +impl_element_borrowable!(A, B, C, D, E, F); +impl_element_borrowable!(A, B, C, D, E, F, G); +impl_element_borrowable!(A, B, C, D, E, F, G, H); +impl_element_borrowable!(A, B, C, D, E, F, G, H, I); +impl_element_borrowable!(A, B, C, D, E, F, G, H, I, J); +impl_element_borrowable!(A, B, C, D, E, F, G, H, I, J, K); +impl_element_borrowable!(A, B, C, D, E, F, G, H, I, J, K, L); +impl_element_borrowable!(A, B, C, D, E, F, G, H, I, J, K, L, M); +impl_element_borrowable!(A, B, C, D, E, F, G, H, I, J, K, L, M, N); +impl_element_borrowable!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O); +impl_element_borrowable!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P); diff --git a/packages/native-core/src/tree.rs b/packages/native-core/src/tree.rs index 6931d2e23..04138b855 100644 --- a/packages/native-core/src/tree.rs +++ b/packages/native-core/src/tree.rs @@ -72,14 +72,11 @@ pub trait TreeView: Sized { unsafe { self.get_mut(id).unwrap_unchecked() } } - fn children<'a>(&'a self, id: NodeId) -> Option>; + fn children(&self, id: NodeId) -> Option>; - fn children_mut<'a>(&'a mut self, id: NodeId) -> Option>; + fn children_mut(&mut self, id: NodeId) -> Option>; - fn parent_child_mut<'a>( - &'a mut self, - id: NodeId, - ) -> Option<(&'a mut T, Self::IteratorMut<'a>)> { + fn parent_child_mut(&mut self, id: NodeId) -> Option<(&mut T, Self::IteratorMut<'_>)> { let mut_ptr: *mut Self = self; unsafe { // Safety: No node has itself as a child. @@ -91,7 +88,7 @@ pub trait TreeView: Sized { } } - fn children_ids<'a>(&'a self, id: NodeId) -> Option<&'a [NodeId]>; + fn children_ids(&self, id: NodeId) -> Option<&[NodeId]>; fn parent(&self, id: NodeId) -> Option<&T>; @@ -257,7 +254,7 @@ impl TreeView for Tree { self.nodes.get_mut(id.0).map(|node| &mut node.value) } - fn children<'a>(&'a self, id: NodeId) -> Option> { + fn children(&self, id: NodeId) -> Option> { self.children_ids(id).map(|children_ids| ChildNodeIterator { tree: self, children_ids, @@ -266,7 +263,7 @@ impl TreeView for Tree { }) } - fn children_mut<'a>(&'a mut self, id: NodeId) -> Option> { + fn children_mut(&mut self, id: NodeId) -> Option> { let raw_ptr = self as *mut Self; unsafe { // Safety: No node will appear as a child twice @@ -280,7 +277,7 @@ impl TreeView for Tree { } } - fn children_ids<'a>(&'a self, id: NodeId) -> Option<&'a [NodeId]> { + fn children_ids(&self, id: NodeId) -> Option<&[NodeId]> { self.nodes.get(id.0).map(|node| node.children.as_slice()) } @@ -462,7 +459,7 @@ where self.tree.get_mut(id).map(|node| (self.map_mut)(node)) } - fn children<'b>(&'b self, id: NodeId) -> Option> { + fn children(&self, id: NodeId) -> Option> { self.children_ids(id).map(|children_ids| ChildNodeIterator { tree: self, children_ids, @@ -471,7 +468,7 @@ where }) } - fn children_mut<'b>(&'b mut self, id: NodeId) -> Option> { + fn children_mut(&mut self, id: NodeId) -> Option> { let raw_ptr = self as *mut Self; unsafe { // Safety: No node can be a child twice. @@ -485,7 +482,7 @@ where } } - fn children_ids<'b>(&'b self, id: NodeId) -> Option<&'b [NodeId]> { + fn children_ids(&self, id: NodeId) -> Option<&[NodeId]> { self.tree.children_ids(id) } @@ -609,15 +606,15 @@ impl<'a, T, Tr: TreeView> TreeView for SharedView<'a, T, Tr> { self.with_node(id, |t| t.get_mut(id)) } - fn children<'b>(&'b self, id: NodeId) -> Option> { + fn children(&self, id: NodeId) -> Option> { self.with_node(id, |t| t.children(id)) } - fn children_mut<'b>(&'b mut self, id: NodeId) -> Option> { + fn children_mut(&mut self, id: NodeId) -> Option> { self.with_node(id, |t| t.children_mut(id)) } - fn children_ids<'b>(&'b self, id: NodeId) -> Option<&'b [NodeId]> { + fn children_ids(&self, id: NodeId) -> Option<&[NodeId]> { self.with_node(id, |t| t.children_ids(id)) } diff --git a/packages/native-core/src/worker_pool.rs b/packages/native-core/src/worker_pool.rs new file mode 100644 index 000000000..8b1378917 --- /dev/null +++ b/packages/native-core/src/worker_pool.rs @@ -0,0 +1 @@ +