diff --git a/packages/native-core/src/lib.rs b/packages/native-core/src/lib.rs index 1a449ca07..6e2f7a166 100644 --- a/packages/native-core/src/lib.rs +++ b/packages/native-core/src/lib.rs @@ -14,8 +14,6 @@ pub mod state; pub mod tree; pub mod utils; -/// A id for a node that lives in the real dom. -pub type RealNodeId = NodeId; pub type FxDashMap = dashmap::DashMap>; pub type FxDashSet = dashmap::DashSet>; pub type SendAnyMap = anymap::Map; @@ -25,11 +23,11 @@ pub type SendAnyMap = anymap::Map; #[doc(hidden)] pub struct HeightOrdering { pub height: u16, - pub id: RealNodeId, + pub id: NodeId, } impl HeightOrdering { - pub fn new(height: u16, id: RealNodeId) -> Self { + pub fn new(height: u16, id: NodeId) -> Self { HeightOrdering { height, id } } } diff --git a/packages/native-core/src/node.rs b/packages/native-core/src/node.rs index 4530fd350..58d378596 100644 --- a/packages/native-core/src/node.rs +++ b/packages/native-core/src/node.rs @@ -21,23 +21,24 @@ pub struct NodeData { pub node_type: NodeType, } +#[derive(Debug, Clone)] +pub struct ElementNode { + pub tag: String, + pub namespace: Option, + pub attributes: FxHashMap, + pub listeners: FxHashSet, +} + /// A type of node with data specific to the node type. The types are a subset of the [VNode] types. #[derive(Debug, Clone)] pub enum NodeType { - Text { - text: String, - }, - Element { - tag: String, - namespace: Option, - attributes: FxHashMap, - listeners: FxHashSet, - }, + Text(String), + Element(ElementNode), Placeholder, } impl Node { - pub(crate) fn new(node_type: NodeType) -> Self { + pub fn new(node_type: NodeType) -> Self { Node { state: S::default(), node_data: NodeData { diff --git a/packages/native-core/src/node_ref.rs b/packages/native-core/src/node_ref.rs index d178c2d18..1bd361175 100644 --- a/packages/native-core/src/node_ref.rs +++ b/packages/native-core/src/node_ref.rs @@ -1,9 +1,9 @@ use dioxus_core::ElementId; use crate::{ - node::{NodeData, NodeType, OwnedAttributeView}, + node::{ElementNode, NodeData, NodeType, OwnedAttributeView}, state::union_ordered_iter, - RealNodeId, + NodeId, }; /// A view into a [VNode] with limited access. @@ -28,7 +28,7 @@ impl<'a> NodeView<'a> { } /// Get the node id of the node - pub fn node_id(&self) -> RealNodeId { + pub fn node_id(&self) -> NodeId { self.inner.node_id } @@ -37,7 +37,7 @@ impl<'a> NodeView<'a> { self.mask .tag .then_some(match &self.inner.node_type { - NodeType::Element { tag, .. } => Some(&**tag), + NodeType::Element(ElementNode { tag, .. }) => Some(&**tag), _ => None, }) .flatten() @@ -48,7 +48,7 @@ impl<'a> NodeView<'a> { self.mask .namespace .then_some(match &self.inner.node_type { - NodeType::Element { namespace, .. } => namespace.as_deref(), + NodeType::Element(ElementNode { namespace, .. }) => namespace.as_deref(), _ => None, }) .flatten() @@ -57,7 +57,7 @@ impl<'a> NodeView<'a> { /// Get any attributes that are enabled in the mask pub fn attributes<'b>(&'b self) -> Option> + 'b> { match &self.inner.node_type { - NodeType::Element { attributes, .. } => Some( + NodeType::Element(ElementNode { attributes, .. }) => Some( attributes .iter() .filter(move |(attr, _)| self.mask.attritutes.contains_attribute(&attr.name)) @@ -75,7 +75,7 @@ impl<'a> NodeView<'a> { self.mask .text .then_some(match &self.inner.node_type { - NodeType::Text { text } => Some(&**text), + NodeType::Text(text) => Some(&**text), _ => None, }) .flatten() @@ -85,7 +85,9 @@ impl<'a> NodeView<'a> { pub fn listeners(&self) -> Option + '_> { if self.mask.listeners { match &self.inner.node_type { - NodeType::Element { listeners, .. } => Some(listeners.iter().map(|l| &**l)), + NodeType::Element(ElementNode { listeners, .. }) => { + Some(listeners.iter().map(|l| &**l)) + } _ => None, } } else { @@ -238,6 +240,28 @@ impl NodeMask { .with_element() .with_listeners(); + pub fn from_node(node: &NodeType) -> Self { + match node { + NodeType::Text { .. } => Self::new().with_text(), + NodeType::Element(ElementNode { + tag: _, + namespace: _, + attributes, + listeners, + }) => { + let mut mask = Self::new_with_attrs(AttributeMask::Dynamic( + attributes.keys().map(|key| key.name.clone()).collect(), + )) + .with_element(); + if !listeners.is_empty() { + mask = mask.with_listeners(); + } + mask + } + NodeType::Placeholder => Self::new().with_element(), + } + } + /// Check if two masks overlap pub fn overlaps(&self, other: &Self) -> bool { (self.tag && other.tag) @@ -280,12 +304,22 @@ impl NodeMask { self } + /// Set the mask to view the tag + pub fn set_tag(&mut self) { + self.tag = true; + } + /// Allow the mask to view the namespace pub const fn with_namespace(mut self) -> Self { self.namespace = true; self } + /// Set the mask to view the namespace + pub fn set_namespace(&mut self) { + self.namespace = true; + } + /// Allow the mask to view the namespace and tag pub const fn with_element(self) -> Self { self.with_namespace().with_tag() @@ -297,9 +331,24 @@ impl NodeMask { self } + /// Set the mask to view the text + pub fn set_text(&mut self) { + self.text = true; + } + /// Allow the mask to view the listeners pub const fn with_listeners(mut self) -> Self { self.listeners = true; self } + + /// Set the mask to view the listeners + pub fn set_listeners(&mut self) { + self.listeners = true; + } + + /// Allow the mask to view the given attributes + pub fn add_attributes(&mut self, attributes: AttributeMask) { + self.attritutes = self.attritutes.union(&attributes); + } } diff --git a/packages/native-core/src/passes.rs b/packages/native-core/src/passes.rs index 746cb6cc8..8640e8fc4 100644 --- a/packages/native-core/src/passes.rs +++ b/packages/native-core/src/passes.rs @@ -1,16 +1,14 @@ -use anymap::any; use anymap::AnyMap; use rustc_hash::FxHashMap; use rustc_hash::FxHashSet; use std::any::{Any, TypeId}; use std::collections::BTreeMap; -use std::ops::{BitAnd, BitAndAssign, BitOr, BitOrAssign}; -use std::sync::atomic::{AtomicU64, Ordering}; use std::sync::Arc; use crate::node::Node; use crate::node_ref::NodeView; use crate::state::State; +use crate::tree::TreeViewMut; use crate::tree::{Tree, TreeView}; use crate::{FxDashMap, FxDashSet, SendAnyMap}; use crate::{NodeId, NodeMask}; @@ -70,9 +68,6 @@ pub trait Pass: Any { { TypeErasedPass { this_type_id: TypeId::of::(), - parent_type_ids: Self::parent_type_ids().into_iter().collect(), - child_type_ids: Self::child_type_ids().into_iter().collect(), - node_type_ids: Self::node_type_ids().into_iter().collect(), combined_dependancy_type_ids: Self::all_dependanices().into_iter().collect(), dependants: FxHashSet::default(), mask: Self::MASK, @@ -155,10 +150,7 @@ pub trait Pass: Any { pub struct TypeErasedPass { pub(crate) this_type_id: TypeId, - parent_type_ids: FxHashSet, - child_type_ids: FxHashSet, - node_type_ids: FxHashSet, - combined_dependancy_type_ids: FxHashSet, + pub(crate) combined_dependancy_type_ids: FxHashSet, pub(crate) dependants: FxHashSet, pub(crate) mask: NodeMask, pass: PassCallback, @@ -392,7 +384,7 @@ impl DirtyNodeStates { pub fn resolve_passes( tree: &mut Tree>, dirty_nodes: DirtyNodeStates, - mut passes: &[TypeErasedPass], + passes: &[TypeErasedPass], ctx: SendAnyMap, ) -> FxDashSet { let dirty_states = Arc::new(dirty_nodes); @@ -446,539 +438,661 @@ pub fn resolve_passes( std::sync::Arc::try_unwrap(nodes_updated).unwrap() } -#[test] -fn node_pass() { - use crate::tree::{Tree, TreeLike}; - let mut tree = Tree::new(0); - - struct AddPass; - impl Pass for AddPass { - fn pass_id(&self) -> PassId { - PassId(0) - } - - fn dependancies(&self) -> &'static [PassId] { - &[] - } - - fn dependants(&self) -> &'static [PassId] { - &[] - } - - fn mask(&self) -> MemberMask { - MemberMask(0) - } - } - - impl NodePass for AddPass { - fn pass(&self, node: &mut i32, _: &SendAnyMap) -> bool { - *node += 1; - true - } - } - - let add_pass = AnyPass::Node(&AddPass); - let passes = vec![&add_pass]; - let dirty_nodes: DirtyNodeStates = DirtyNodeStates::default(); - dirty_nodes.insert(PassId(0), tree.root()); - resolve_passes(&mut tree, dirty_nodes, passes, SendAnyMap::new()); - - assert_eq!(tree.get(tree.root()).unwrap(), &1); -} - -#[test] -fn dependant_node_pass() { - use crate::tree::{Tree, TreeLike}; - let mut tree = Tree::new(0); - - struct AddPass; - impl Pass for AddPass { - fn pass_id(&self) -> PassId { - PassId(0) - } - - fn dependancies(&self) -> &'static [PassId] { - &[PassId(1)] - } - - fn dependants(&self) -> &'static [PassId] { - &[] - } - - fn mask(&self) -> MemberMask { - MemberMask(0) - } - } - - impl NodePass for AddPass { - fn pass(&self, node: &mut i32, _: &SendAnyMap) -> bool { - *node += 1; - true - } - } - - struct SubtractPass; - - impl Pass for SubtractPass { - fn pass_id(&self) -> PassId { - PassId(1) - } - - fn dependancies(&self) -> &'static [PassId] { - &[] - } - - fn dependants(&self) -> &'static [PassId] { - &[PassId(0)] - } - - fn mask(&self) -> MemberMask { - MemberMask(0) - } - } - impl NodePass for SubtractPass { - fn pass(&self, node: &mut i32, _: &SendAnyMap) -> bool { - *node -= 1; - true - } - } - - let add_pass = AnyPass::Node(&AddPass); - let subtract_pass = AnyPass::Node(&SubtractPass); - let passes = vec![&add_pass, &subtract_pass]; - let dirty_nodes: DirtyNodeStates = DirtyNodeStates::default(); - dirty_nodes.insert(PassId(1), tree.root()); - resolve_passes(&mut tree, dirty_nodes, passes, SendAnyMap::new()); - - assert_eq!(*tree.get(tree.root()).unwrap(), 0); -} - -#[test] -fn independant_node_pass() { - use crate::tree::{Tree, TreeLike}; - let mut tree = Tree::new((0, 0)); - - struct AddPass1; - impl Pass for AddPass1 { - fn pass_id(&self) -> PassId { - PassId(0) - } - - fn dependancies(&self) -> &'static [PassId] { - &[] - } - - fn dependants(&self) -> &'static [PassId] { - &[] - } - - fn mask(&self) -> MemberMask { - MemberMask(0) - } - } - - impl NodePass<(i32, i32)> for AddPass1 { - fn pass(&self, node: &mut (i32, i32), _: &SendAnyMap) -> bool { - node.0 += 1; - true - } - } - - struct AddPass2; - impl Pass for AddPass2 { - fn pass_id(&self) -> PassId { - PassId(1) - } - - fn dependancies(&self) -> &'static [PassId] { - &[] - } - - fn dependants(&self) -> &'static [PassId] { - &[] - } - - fn mask(&self) -> MemberMask { - MemberMask(1) - } - } - - impl NodePass<(i32, i32)> for AddPass2 { - fn pass(&self, node: &mut (i32, i32), _: &SendAnyMap) -> bool { - node.1 += 1; - true - } - } - - let add_pass1 = AnyPass::Node(&AddPass1); - let add_pass2 = AnyPass::Node(&AddPass2); - let passes = vec![&add_pass1, &add_pass2]; - let dirty_nodes: DirtyNodeStates = DirtyNodeStates::default(); - dirty_nodes.insert(PassId(0), tree.root()); - dirty_nodes.insert(PassId(1), tree.root()); - resolve_passes(&mut tree, dirty_nodes, passes, SendAnyMap::new()); - - assert_eq!(tree.get(tree.root()).unwrap(), &(1, 1)); -} - -#[test] -fn down_pass() { - use crate::tree::{Tree, TreeLike}; - let mut tree = Tree::new(1); - let parent = tree.root(); - let child1 = tree.create_node(1); - tree.add_child(parent, child1); - let grandchild1 = tree.create_node(1); - tree.add_child(child1, grandchild1); - let child2 = tree.create_node(1); - tree.add_child(parent, child2); - let grandchild2 = tree.create_node(1); - tree.add_child(child2, grandchild2); - - struct AddPass; - - impl Pass for AddPass { - fn pass_id(&self) -> PassId { - PassId(0) - } - - fn dependancies(&self) -> &'static [PassId] { - &[] - } - - fn dependants(&self) -> &'static [PassId] { - &[] - } - - fn mask(&self) -> MemberMask { - MemberMask(0) - } - } - impl DownwardPass for AddPass { - fn pass(&self, node: &mut i32, parent: Option<&mut i32>, _: &SendAnyMap) -> PassReturn { - if let Some(parent) = parent { - *node += *parent; - } - PassReturn { - progress: true, - mark_dirty: true, - } - } - } - - let add_pass = AnyPass::Downward(&AddPass); - let passes = vec![&add_pass]; - let dirty_nodes: DirtyNodeStates = DirtyNodeStates::default(); - dirty_nodes.insert(PassId(0), tree.root()); - resolve_passes(&mut tree, dirty_nodes, passes, SendAnyMap::new()); - - assert_eq!(tree.get(tree.root()).unwrap(), &1); - assert_eq!(tree.get(child1).unwrap(), &2); - assert_eq!(tree.get(grandchild1).unwrap(), &3); - assert_eq!(tree.get(child2).unwrap(), &2); - assert_eq!(tree.get(grandchild2).unwrap(), &3); -} - -#[test] -fn dependant_down_pass() { - use crate::tree::{Tree, TreeLike}; - // 0 - let mut tree = Tree::new(1); - let parent = tree.root(); - // 1 - let child1 = tree.create_node(1); - tree.add_child(parent, child1); - // 2 - let grandchild1 = tree.create_node(1); - tree.add_child(child1, grandchild1); - // 3 - let child2 = tree.create_node(1); - tree.add_child(parent, child2); - // 4 - let grandchild2 = tree.create_node(1); - tree.add_child(child2, grandchild2); - - struct AddPass; - impl Pass for AddPass { - fn pass_id(&self) -> PassId { - PassId(0) - } - - fn dependancies(&self) -> &'static [PassId] { - &[PassId(1)] - } - - fn dependants(&self) -> &'static [PassId] { - &[] - } - - fn mask(&self) -> MemberMask { - MemberMask(0) - } - } - impl DownwardPass for AddPass { - fn pass(&self, node: &mut i32, parent: Option<&mut i32>, _: &SendAnyMap) -> PassReturn { - if let Some(parent) = parent { - *node += *parent; - } else { - } - PassReturn { - progress: true, - mark_dirty: true, - } - } - } - - struct SubtractPass; - impl Pass for SubtractPass { - fn pass_id(&self) -> PassId { - PassId(1) - } - - fn dependancies(&self) -> &'static [PassId] { - &[] - } - - fn dependants(&self) -> &'static [PassId] { - &[PassId(0)] - } - - fn mask(&self) -> MemberMask { - MemberMask(0) - } - } - impl DownwardPass for SubtractPass { - fn pass(&self, node: &mut i32, parent: Option<&mut i32>, _: &SendAnyMap) -> PassReturn { - if let Some(parent) = parent { - *node -= *parent; - } else { - } - PassReturn { - progress: true, - mark_dirty: true, - } - } - } - - let add_pass = AnyPass::Downward(&AddPass); - let subtract_pass = AnyPass::Downward(&SubtractPass); - let passes = vec![&add_pass, &subtract_pass]; - let dirty_nodes: DirtyNodeStates = DirtyNodeStates::default(); - dirty_nodes.insert(PassId(1), tree.root()); - resolve_passes(&mut tree, dirty_nodes, passes, SendAnyMap::new()); - - // Tree before: - // 1=\ - // 1=\ - // 1 - // 1=\ - // 1 - // Tree after subtract: - // 1=\ - // 0=\ - // 1 - // 0=\ - // 1 - // Tree after add: - // 1=\ - // 1=\ - // 2 - // 1=\ - // 2 - assert_eq!(tree.get(tree.root()).unwrap(), &1); - assert_eq!(tree.get(child1).unwrap(), &1); - assert_eq!(tree.get(grandchild1).unwrap(), &2); - assert_eq!(tree.get(child2).unwrap(), &1); - assert_eq!(tree.get(grandchild2).unwrap(), &2); -} - -#[test] -fn up_pass() { - use crate::tree::{Tree, TreeLike}; - // Tree before: - // 0=\ - // 0=\ - // 1 - // 0=\ - // 1 - // Tree after: - // 2=\ - // 1=\ - // 1 - // 1=\ - // 1 - let mut tree = Tree::new(0); - let parent = tree.root(); - let child1 = tree.create_node(0); - tree.add_child(parent, child1); - let grandchild1 = tree.create_node(1); - tree.add_child(child1, grandchild1); - let child2 = tree.create_node(0); - tree.add_child(parent, child2); - let grandchild2 = tree.create_node(1); - tree.add_child(child2, grandchild2); - - struct AddPass; - impl Pass for AddPass { - fn pass_id(&self) -> PassId { - PassId(0) - } - - fn dependancies(&self) -> &'static [PassId] { - &[] - } - - fn dependants(&self) -> &'static [PassId] { - &[] - } - - fn mask(&self) -> MemberMask { - MemberMask(0) - } - } - impl UpwardPass for AddPass { - fn pass<'a>( - &self, - node: &mut i32, - children: &mut dyn Iterator, - _: &SendAnyMap, - ) -> PassReturn { - *node += children.map(|i| *i).sum::(); - PassReturn { - progress: true, - mark_dirty: true, - } - } - } - - let add_pass = AnyPass::Upward(&AddPass); - let passes = vec![&add_pass]; - let dirty_nodes: DirtyNodeStates = DirtyNodeStates::default(); - dirty_nodes.insert(PassId(0), grandchild1); - dirty_nodes.insert(PassId(0), grandchild2); - resolve_passes(&mut tree, dirty_nodes, passes, SendAnyMap::new()); - - assert_eq!(tree.get(tree.root()).unwrap(), &2); - assert_eq!(tree.get(child1).unwrap(), &1); - assert_eq!(tree.get(grandchild1).unwrap(), &1); - assert_eq!(tree.get(child2).unwrap(), &1); - assert_eq!(tree.get(grandchild2).unwrap(), &1); -} - -#[test] -fn dependant_up_pass() { - use crate::tree::{Tree, TreeLike}; - // 0 - let mut tree = Tree::new(0); - let parent = tree.root(); - // 1 - let child1 = tree.create_node(0); - tree.add_child(parent, child1); - // 2 - let grandchild1 = tree.create_node(1); - tree.add_child(child1, grandchild1); - // 3 - let child2 = tree.create_node(0); - tree.add_child(parent, child2); - // 4 - let grandchild2 = tree.create_node(1); - tree.add_child(child2, grandchild2); - - struct AddPass; - impl Pass for AddPass { - fn pass_id(&self) -> PassId { - PassId(0) - } - - fn dependancies(&self) -> &'static [PassId] { - &[PassId(1)] - } - - fn dependants(&self) -> &'static [PassId] { - &[] - } - - fn mask(&self) -> MemberMask { - MemberMask(0) - } - } - impl UpwardPass for AddPass { - fn pass<'a>( - &self, - node: &mut i32, - children: &mut dyn Iterator, - _: &SendAnyMap, - ) -> PassReturn { - *node += children.map(|i| *i).sum::(); - PassReturn { - progress: true, - mark_dirty: true, - } - } - } - - struct SubtractPass; - impl Pass for SubtractPass { - fn pass_id(&self) -> PassId { - PassId(1) - } - - fn dependancies(&self) -> &'static [PassId] { - &[] - } - - fn dependants(&self) -> &'static [PassId] { - &[PassId(0)] - } - - fn mask(&self) -> MemberMask { - MemberMask(0) - } - } - impl UpwardPass for SubtractPass { - fn pass<'a>( - &self, - node: &mut i32, - children: &mut dyn Iterator, - _: &SendAnyMap, - ) -> PassReturn { - *node -= children.map(|i| *i).sum::(); - PassReturn { - progress: true, - mark_dirty: true, - } - } - } - - let add_pass = AnyPass::Upward(&AddPass); - let subtract_pass = AnyPass::Upward(&SubtractPass); - let passes = vec![&add_pass, &subtract_pass]; - let dirty_nodes: DirtyNodeStates = DirtyNodeStates::default(); - dirty_nodes.insert(PassId(1), grandchild1); - dirty_nodes.insert(PassId(1), grandchild2); - resolve_passes(&mut tree, dirty_nodes, passes, SendAnyMap::new()); - - // Tree before: - // 0=\ - // 0=\ - // 1 - // 0=\ - // 1 - // Tree after subtract: - // 2=\ - // -1=\ - // 1 - // -1=\ - // 1 - // Tree after add: - // 2=\ - // 0=\ - // 1 - // 0=\ - // 1 - assert_eq!(tree.get(tree.root()).unwrap(), &2); - assert_eq!(tree.get(child1).unwrap(), &0); - assert_eq!(tree.get(grandchild1).unwrap(), &1); - assert_eq!(tree.get(child2).unwrap(), &0); - assert_eq!(tree.get(grandchild2).unwrap(), &1); -} +// #[test] +// fn node_pass() { +// use crate::real_dom::RealDom; +// use crate::tree::{Tree, TreeLike}; + +// #[derive(Debug, Default, Clone, PartialEq)] +// struct Number(i32); + +// impl State for Number { +// fn create_passes() -> Box<[TypeErasedPass]> { +// Box::new([Number::to_type_erased()]) +// } +// } + +// impl AnyMapLike for Number { +// fn get(&self) -> Option<&T> { +// if TypeId::of::() == TypeId::of::() { +// Some(unsafe { &*(self as *const Self as *const T) }) +// } else { +// None +// } +// } + +// fn get_mut(&mut self) -> Option<&mut T> { +// if TypeId::of::() == TypeId::of::() { +// Some(unsafe { &mut *(self as *mut Self as *mut T) }) +// } else { +// None +// } +// } +// } + +// impl Pass for Number { +// type ChildDependencies = (); +// type NodeDependencies = (); +// type ParentDependencies = (); +// type Ctx = (); +// const MASK: NodeMask = NodeMask::new(); + +// fn pass<'a>( +// &mut self, +// node_view: NodeView, +// node: ::ElementBorrowed<'a>, +// parent: Option<::ElementBorrowed<'a>>, +// children: Option< +// impl Iterator::ElementBorrowed<'a>>, +// >, +// context: ::ElementBorrowed<'a>, +// ) -> bool { +// self.0 += 1; +// true +// } +// } + +// let mut tree: RealDom = RealDom::new(); +// tree.dirty_nodes.insert(TypeId::of::(), NodeId(0)); +// tree.update_state(SendAnyMap::new()); + +// assert_eq!(tree.get(tree.root()).unwrap().state.0, 1); +// } + +// #[test] +// fn dependant_node_pass() { +// use crate::real_dom::RealDom; + +// #[derive(Debug, Default, Clone, PartialEq)] +// struct AddNumber(i32); + +// impl Pass for AddNumber { +// type ChildDependencies = (); +// type NodeDependencies = (SubtractNumber,); +// type ParentDependencies = (); +// type Ctx = (); +// const MASK: NodeMask = NodeMask::new(); + +// fn pass<'a>( +// &mut self, +// node_view: NodeView, +// node: ::ElementBorrowed<'a>, +// parent: Option<::ElementBorrowed<'a>>, +// children: Option< +// impl Iterator::ElementBorrowed<'a>>, +// >, +// context: ::ElementBorrowed<'a>, +// ) -> bool { +// self.0 += 1; +// true +// } +// } + +// #[derive(Debug, Default, Clone, PartialEq)] +// struct SubtractNumber(i32); + +// impl Pass for SubtractNumber { +// type ChildDependencies = (); +// type NodeDependencies = (); +// type ParentDependencies = (); +// type Ctx = (); +// const MASK: NodeMask = NodeMask::new(); + +// fn pass<'a>( +// &mut self, +// node_view: NodeView, +// node: ::ElementBorrowed<'a>, +// parent: Option<::ElementBorrowed<'a>>, +// children: Option< +// impl Iterator::ElementBorrowed<'a>>, +// >, +// context: ::ElementBorrowed<'a>, +// ) -> bool { +// self.0 -= 1; +// true +// } +// } + +// #[derive(Debug, Default, Clone, PartialEq)] +// struct NumberState { +// add_number: AddNumber, +// subtract_number: SubtractNumber, +// } + +// impl AnyMapLike for NumberState { +// fn get(&self) -> Option<&T> { +// if TypeId::of::() == TypeId::of::() { +// Some(unsafe { &*(&self.add_number as *const AddNumber as *const T) }) +// } else if TypeId::of::() == TypeId::of::() { +// Some(unsafe { &*(&self.subtract_number as *const SubtractNumber as *const T) }) +// } else { +// None +// } +// } + +// fn get_mut(&mut self) -> Option<&mut T> { +// if TypeId::of::() == TypeId::of::() { +// Some(unsafe { &mut *(&mut self.add_number as *mut AddNumber as *mut T) }) +// } else if TypeId::of::() == TypeId::of::() { +// Some(unsafe { &mut *(&mut self.subtract_number as *mut SubtractNumber as *mut T) }) +// } else { +// None +// } +// } +// } + +// impl State for NumberState { +// fn create_passes() -> Box<[TypeErasedPass]> { +// Box::new([ +// AddNumber::to_type_erased(), +// SubtractNumber::to_type_erased(), +// ]) +// } +// } + +// let mut tree: RealDom = RealDom::new(); +// tree.dirty_nodes +// .insert(TypeId::of::(), NodeId(0)); +// tree.update_state(dirty_nodes, SendAnyMap::new()); + +// assert_eq!( +// tree.get(tree.root()).unwrap().state, +// NumberState { +// add_number: AddNumber(1), +// subtract_number: SubtractNumber(-1) +// } +// ); +// } + +// #[test] +// fn independant_node_pass() { +// use crate::real_dom::RealDom; +// use crate::tree::{Tree, TreeLike}; + +// #[derive(Debug, Default, Clone, PartialEq)] +// struct AddNumber(i32); + +// impl Pass for AddNumber { +// type ChildDependencies = (); +// type NodeDependencies = (); +// type ParentDependencies = (); +// type Ctx = (); +// const MASK: NodeMask = NodeMask::new(); + +// fn pass<'a>( +// &mut self, +// node_view: NodeView, +// node: ::ElementBorrowed<'a>, +// parent: Option<::ElementBorrowed<'a>>, +// children: Option< +// impl Iterator::ElementBorrowed<'a>>, +// >, +// context: ::ElementBorrowed<'a>, +// ) -> bool { +// self.0 += 1; +// true +// } +// } + +// #[derive(Debug, Default, Clone, PartialEq)] +// struct SubtractNumber(i32); + +// impl Pass for SubtractNumber { +// type ChildDependencies = (); +// type NodeDependencies = (); +// type ParentDependencies = (); +// type Ctx = (); +// const MASK: NodeMask = NodeMask::new(); + +// fn pass<'a>( +// &mut self, +// node_view: NodeView, +// node: ::ElementBorrowed<'a>, +// parent: Option<::ElementBorrowed<'a>>, +// children: Option< +// impl Iterator::ElementBorrowed<'a>>, +// >, +// context: ::ElementBorrowed<'a>, +// ) -> bool { +// self.0 -= 1; +// true +// } +// } + +// #[derive(Debug, Default, Clone, PartialEq)] +// struct NumberState { +// add_number: AddNumber, +// subtract_number: SubtractNumber, +// } + +// impl AnyMapLike for NumberState { +// fn get(&self) -> Option<&T> { +// if TypeId::of::() == TypeId::of::() { +// Some(unsafe { &*(&self.add_number as *const AddNumber as *const T) }) +// } else if TypeId::of::() == TypeId::of::() { +// Some(unsafe { &*(&self.subtract_number as *const SubtractNumber as *const T) }) +// } else { +// None +// } +// } + +// fn get_mut(&mut self) -> Option<&mut T> { +// if TypeId::of::() == TypeId::of::() { +// Some(unsafe { &mut *(&mut self.add_number as *mut AddNumber as *mut T) }) +// } else if TypeId::of::() == TypeId::of::() { +// Some(unsafe { &mut *(&mut self.subtract_number as *mut SubtractNumber as *mut T) }) +// } else { +// None +// } +// } +// } + +// impl State for NumberState { +// fn create_passes() -> Box<[TypeErasedPass]> { +// Box::new([ +// AddNumber::to_type_erased(), +// SubtractNumber::to_type_erased(), +// ]) +// } +// } + +// let mut tree: RealDom = RealDom::new(); +// tree.dirty_nodes +// .insert(TypeId::of::(), NodeId(0)); +// tree.update_state(SendAnyMap::new()); + +// assert_eq!( +// tree.get(tree.root()).unwrap().state, +// NumberState { +// add_number: AddNumber(0), +// subtract_number: SubtractNumber(-1) +// } +// ); +// } + +// #[test] +// fn down_pass() { +// use crate::real_dom::RealDom; +// use crate::tree::{Tree, TreeLike}; + +// #[derive(Debug, Default, Clone, PartialEq)] +// struct AddNumber(i32); + +// impl Pass for AddNumber { +// type ChildDependencies = (); +// type NodeDependencies = (); +// type ParentDependencies = (AddNumber,); +// type Ctx = (); +// const MASK: NodeMask = NodeMask::new(); + +// fn pass<'a>( +// &mut self, +// node_view: NodeView, +// node: ::ElementBorrowed<'a>, +// parent: Option<::ElementBorrowed<'a>>, +// children: Option< +// impl Iterator::ElementBorrowed<'a>>, +// >, +// context: ::ElementBorrowed<'a>, +// ) -> bool { +// if let Some((parent,)) = parent { +// *self.0 += *parent.0; +// } +// true +// } +// } + +// #[derive(Debug, Default, Clone, PartialEq)] +// struct NumberState { +// add_number: AddNumber, +// } + +// impl AnyMapLike for NumberState { +// fn get(&self) -> Option<&T> { +// if TypeId::of::() == TypeId::of::() { +// Some(unsafe { &*(&self.add_number as *const AddNumber as *const T) }) +// } else { +// None +// } +// } + +// fn get_mut(&mut self) -> Option<&mut T> { +// if TypeId::of::() == TypeId::of::() { +// Some(unsafe { &mut *(&mut self.add_number as *mut AddNumber as *mut T) }) +// } else { +// None +// } +// } +// } + +// impl State for NumberState { +// fn create_passes() -> Box<[TypeErasedPass]> { +// Box::new([AddNumber::to_type_erased()]) +// } +// } + +// let mut tree: RealDom = RealDom::new(); +// let parent = tree.root(); +// let child1 = tree.create_node(1); +// tree.add_child(parent, child1); +// let grandchild1 = tree.create_node(1); +// tree.add_child(child1, grandchild1); +// let child2 = tree.create_node(1); +// tree.add_child(parent, child2); +// let grandchild2 = tree.create_node(1); +// tree.add_child(child2, grandchild2); + +// tree.dirty_nodes +// .insert(TypeId::of::(), NodeId(0)); +// tree.update_state(SendAnyMap::new()); + +// assert_eq!(tree.get(tree.root()).unwrap().state.add_number.0, 1); +// assert_eq!(tree.get(child1).unwrap().state.add_number.0, 2); +// assert_eq!(tree.get(grandchild1).unwrap().state.add_number.0, 3); +// assert_eq!(tree.get(child2).unwrap().state.add_number.0, 2); +// assert_eq!(tree.get(grandchild2).unwrap().state.add_number.0, 3); +// } + +// #[test] +// fn dependant_down_pass() { +// use crate::tree::{Tree, TreeLike}; +// // 0 +// let mut tree = Tree::new(1); +// let parent = tree.root(); +// // 1 +// let child1 = tree.create_node(1); +// tree.add_child(parent, child1); +// // 2 +// let grandchild1 = tree.create_node(1); +// tree.add_child(child1, grandchild1); +// // 3 +// let child2 = tree.create_node(1); +// tree.add_child(parent, child2); +// // 4 +// let grandchild2 = tree.create_node(1); +// tree.add_child(child2, grandchild2); + +// struct AddPass; +// impl Pass for AddPass { +// fn pass_id(&self) -> PassId { +// PassId(0) +// } + +// fn dependancies(&self) -> &'static [PassId] { +// &[PassId(1)] +// } + +// fn dependants(&self) -> &'static [PassId] { +// &[] +// } + +// fn mask(&self) -> MemberMask { +// MemberMask(0) +// } +// } +// impl DownwardPass for AddPass { +// fn pass(&self, node: &mut i32, parent: Option<&mut i32>, _: &SendAnyMap) -> PassReturn { +// if let Some(parent) = parent { +// *node += *parent; +// } else { +// } +// PassReturn { +// progress: true, +// mark_dirty: true, +// } +// } +// } + +// struct SubtractPass; +// impl Pass for SubtractPass { +// fn pass_id(&self) -> PassId { +// PassId(1) +// } + +// fn dependancies(&self) -> &'static [PassId] { +// &[] +// } + +// fn dependants(&self) -> &'static [PassId] { +// &[PassId(0)] +// } + +// fn mask(&self) -> MemberMask { +// MemberMask(0) +// } +// } +// impl DownwardPass for SubtractPass { +// fn pass(&self, node: &mut i32, parent: Option<&mut i32>, _: &SendAnyMap) -> PassReturn { +// if let Some(parent) = parent { +// *node -= *parent; +// } else { +// } +// PassReturn { +// progress: true, +// mark_dirty: true, +// } +// } +// } + +// let add_pass = AnyPass::Downward(&AddPass); +// let subtract_pass = AnyPass::Downward(&SubtractPass); +// let passes = vec![&add_pass, &subtract_pass]; +// let dirty_nodes: DirtyNodeStates = DirtyNodeStates::default(); +// dirty_nodes.insert(PassId(1), tree.root()); +// resolve_passes(&mut tree, dirty_nodes, passes, SendAnyMap::new()); + +// // Tree before: +// // 1=\ +// // 1=\ +// // 1 +// // 1=\ +// // 1 +// // Tree after subtract: +// // 1=\ +// // 0=\ +// // 1 +// // 0=\ +// // 1 +// // Tree after add: +// // 1=\ +// // 1=\ +// // 2 +// // 1=\ +// // 2 +// assert_eq!(tree.get(tree.root()).unwrap(), &1); +// assert_eq!(tree.get(child1).unwrap(), &1); +// assert_eq!(tree.get(grandchild1).unwrap(), &2); +// assert_eq!(tree.get(child2).unwrap(), &1); +// assert_eq!(tree.get(grandchild2).unwrap(), &2); +// } + +// #[test] +// fn up_pass() { +// use crate::tree::{Tree, TreeLike}; +// // Tree before: +// // 0=\ +// // 0=\ +// // 1 +// // 0=\ +// // 1 +// // Tree after: +// // 2=\ +// // 1=\ +// // 1 +// // 1=\ +// // 1 +// let mut tree = Tree::new(0); +// let parent = tree.root(); +// let child1 = tree.create_node(0); +// tree.add_child(parent, child1); +// let grandchild1 = tree.create_node(1); +// tree.add_child(child1, grandchild1); +// let child2 = tree.create_node(0); +// tree.add_child(parent, child2); +// let grandchild2 = tree.create_node(1); +// tree.add_child(child2, grandchild2); + +// struct AddPass; +// impl Pass for AddPass { +// fn pass_id(&self) -> PassId { +// PassId(0) +// } + +// fn dependancies(&self) -> &'static [PassId] { +// &[] +// } + +// fn dependants(&self) -> &'static [PassId] { +// &[] +// } + +// fn mask(&self) -> MemberMask { +// MemberMask(0) +// } +// } +// impl UpwardPass for AddPass { +// fn pass<'a>( +// &self, +// node: &mut i32, +// children: &mut dyn Iterator, +// _: &SendAnyMap, +// ) -> PassReturn { +// *node += children.map(|i| *i).sum::(); +// PassReturn { +// progress: true, +// mark_dirty: true, +// } +// } +// } + +// let add_pass = AnyPass::Upward(&AddPass); +// let passes = vec![&add_pass]; +// let dirty_nodes: DirtyNodeStates = DirtyNodeStates::default(); +// dirty_nodes.insert(PassId(0), grandchild1); +// dirty_nodes.insert(PassId(0), grandchild2); +// resolve_passes(&mut tree, dirty_nodes, passes, SendAnyMap::new()); + +// assert_eq!(tree.get(tree.root()).unwrap(), &2); +// assert_eq!(tree.get(child1).unwrap(), &1); +// assert_eq!(tree.get(grandchild1).unwrap(), &1); +// assert_eq!(tree.get(child2).unwrap(), &1); +// assert_eq!(tree.get(grandchild2).unwrap(), &1); +// } + +// #[test] +// fn dependant_up_pass() { +// use crate::tree::{Tree, TreeLike}; +// // 0 +// let mut tree = Tree::new(0); +// let parent = tree.root(); +// // 1 +// let child1 = tree.create_node(0); +// tree.add_child(parent, child1); +// // 2 +// let grandchild1 = tree.create_node(1); +// tree.add_child(child1, grandchild1); +// // 3 +// let child2 = tree.create_node(0); +// tree.add_child(parent, child2); +// // 4 +// let grandchild2 = tree.create_node(1); +// tree.add_child(child2, grandchild2); + +// struct AddPass; +// impl Pass for AddPass { +// fn pass_id(&self) -> PassId { +// PassId(0) +// } + +// fn dependancies(&self) -> &'static [PassId] { +// &[PassId(1)] +// } + +// fn dependants(&self) -> &'static [PassId] { +// &[] +// } + +// fn mask(&self) -> MemberMask { +// MemberMask(0) +// } +// } +// impl UpwardPass for AddPass { +// fn pass<'a>( +// &self, +// node: &mut i32, +// children: &mut dyn Iterator, +// _: &SendAnyMap, +// ) -> PassReturn { +// *node += children.map(|i| *i).sum::(); +// PassReturn { +// progress: true, +// mark_dirty: true, +// } +// } +// } + +// struct SubtractPass; +// impl Pass for SubtractPass { +// fn pass_id(&self) -> PassId { +// PassId(1) +// } + +// fn dependancies(&self) -> &'static [PassId] { +// &[] +// } + +// fn dependants(&self) -> &'static [PassId] { +// &[PassId(0)] +// } + +// fn mask(&self) -> MemberMask { +// MemberMask(0) +// } +// } +// impl UpwardPass for SubtractPass { +// fn pass<'a>( +// &self, +// node: &mut i32, +// children: &mut dyn Iterator, +// _: &SendAnyMap, +// ) -> PassReturn { +// *node -= children.map(|i| *i).sum::(); +// PassReturn { +// progress: true, +// mark_dirty: true, +// } +// } +// } + +// let add_pass = AnyPass::Upward(&AddPass); +// let subtract_pass = AnyPass::Upward(&SubtractPass); +// let passes = vec![&add_pass, &subtract_pass]; +// let dirty_nodes: DirtyNodeStates = DirtyNodeStates::default(); +// dirty_nodes.insert(PassId(1), grandchild1); +// dirty_nodes.insert(PassId(1), grandchild2); +// resolve_passes(&mut tree, dirty_nodes, passes, SendAnyMap::new()); + +// // Tree before: +// // 0=\ +// // 0=\ +// // 1 +// // 0=\ +// // 1 +// // Tree after subtract: +// // 2=\ +// // -1=\ +// // 1 +// // -1=\ +// // 1 +// // Tree after add: +// // 2=\ +// // 0=\ +// // 1 +// // 0=\ +// // 1 +// assert_eq!(tree.get(tree.root()).unwrap(), &2); +// assert_eq!(tree.get(child1).unwrap(), &0); +// assert_eq!(tree.get(grandchild1).unwrap(), &1); +// assert_eq!(tree.get(child2).unwrap(), &0); +// assert_eq!(tree.get(grandchild2).unwrap(), &1); +// } diff --git a/packages/native-core/src/real_dom.rs b/packages/native-core/src/real_dom.rs index dba68d618..338fc4c52 100644 --- a/packages/native-core/src/real_dom.rs +++ b/packages/native-core/src/real_dom.rs @@ -1,26 +1,17 @@ use dioxus_core::{ElementId, Mutations, TemplateNode}; use rustc_hash::{FxHashMap, FxHashSet}; +use std::any::TypeId; use std::fmt::Debug; -use std::ops::{Deref, DerefMut, Index, IndexMut}; +use std::ops::{Index, IndexMut}; -use crate::node::{Node, NodeType, OwnedAttributeDiscription, OwnedAttributeValue}; +use crate::node::{ + ElementNode, Node, NodeData, NodeType, OwnedAttributeDiscription, OwnedAttributeValue, +}; use crate::node_ref::{AttributeMask, NodeMask}; use crate::passes::{resolve_passes, DirtyNodeStates, TypeErasedPass}; use crate::state::State; -use crate::tree::{NodeId, Tree, TreeLike, TreeView}; -use crate::{FxDashSet, RealNodeId, SendAnyMap}; - -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); - } -} +use crate::tree::{NodeId, Tree, TreeLike, TreeView, TreeViewMut}; +use crate::{FxDashSet, SendAnyMap}; /// 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. @@ -28,12 +19,15 @@ fn mark_dirty( pub struct RealDom { pub tree: Tree>, /// a map from element id to real node id - node_id_mapping: Vec>, - nodes_listening: FxHashMap>, - stack: Vec, - templates: FxHashMap>, - root_initialized: bool, + node_id_mapping: Vec>, + nodes_listening: FxHashMap>, + stack: Vec, + templates: FxHashMap>, pub(crate) passes: Box<[TypeErasedPass]>, + pub(crate) nodes_updated: FxHashMap, + passes_updated: FxHashMap>, + parent_changed_nodes: FxHashSet, + child_changed_nodes: FxHashSet, } impl Debug for RealDom { @@ -44,7 +38,6 @@ impl Debug for RealDom { .field("nodes_listening", &self.nodes_listening) .field("stack", &self.stack) .field("templates", &self.templates) - .field("root_initialized", &self.root_initialized) .finish() } } @@ -57,18 +50,34 @@ impl Default for RealDom { impl RealDom { pub fn new() -> RealDom { - let mut root = Node::new(NodeType::Element { + let mut root = Node::new(NodeType::Element(ElementNode { tag: "Root".to_string(), namespace: Some("Root".to_string()), attributes: FxHashMap::default(), listeners: FxHashSet::default(), - }); + })); root.node_data.element_id = Some(ElementId(0)); let mut tree = Tree::new(root); let root_id = tree.root(); tree.get_mut(root_id).unwrap().node_data.node_id = root_id; - let passes = S::create_passes(); + let mut passes = S::create_passes(); + + // resolve dependants for each pass + for i in 1..passes.len() { + let (before, after) = passes.split_at_mut(i); + let (current, before) = before.split_last_mut().unwrap(); + for pass in before.iter_mut().chain(after.iter_mut()) { + for dependancy in ¤t.combined_dependancy_type_ids { + if pass.this_type_id == *dependancy { + pass.dependants.insert(current.this_type_id); + } + } + } + } + let mut nodes_updated = FxHashMap::default(); + let root_id = NodeId(0); + nodes_updated.insert(root_id, NodeMask::ALL); RealDom { tree, @@ -76,12 +85,31 @@ impl RealDom { nodes_listening: FxHashMap::default(), stack: vec![root_id], templates: FxHashMap::default(), - root_initialized: false, passes, + nodes_updated, + passes_updated: FxHashMap::default(), + parent_changed_nodes: FxHashSet::default(), + child_changed_nodes: FxHashSet::default(), } } - pub fn element_to_node_id(&self, element_id: ElementId) -> RealNodeId { + fn mark_dirty(&mut self, node_id: NodeId, mask: NodeMask) { + if let Some(node) = self.nodes_updated.get_mut(&node_id) { + *node = node.union(&mask); + } else { + self.nodes_updated.insert(node_id, mask); + } + } + + fn mark_parent_added_or_removed(&mut self, node_id: NodeId) { + self.parent_changed_nodes.insert(node_id); + } + + fn mark_child_changed(&mut self, node_id: NodeId) { + self.child_changed_nodes.insert(node_id); + } + + pub fn element_to_node_id(&self, element_id: ElementId) -> NodeId { self.node_id_mapping.get(element_id.0).unwrap().unwrap() } @@ -99,7 +127,7 @@ impl RealDom { self.node_id_mapping[element_id.0] = Some(node_id); } - fn load_child(&self, path: &[u8]) -> RealNodeId { + fn load_child(&self, path: &[u8]) -> NodeId { let mut current = *self.stack.last().unwrap(); for i in path { current = self.tree.children_ids(current).unwrap()[*i as usize]; @@ -107,18 +135,21 @@ impl RealDom { current } - fn create_node(&mut self, node: Node) -> RealNodeId { + fn create_node(&mut self, node: Node, mark_dirty: bool) -> NodeId { let node_id = self.tree.create_node(node); let node = self.tree.get_mut(node_id).unwrap(); node.node_data.node_id = node_id; + if mark_dirty { + self.nodes_updated.insert(node_id, NodeMask::ALL); + } node_id } - fn add_child(&mut self, node_id: RealNodeId, child_id: RealNodeId) { + fn add_child(&mut self, node_id: NodeId, child_id: NodeId) { self.tree.add_child(node_id, child_id); } - fn create_template_node(&mut self, node: &TemplateNode) -> RealNodeId { + fn create_template_node(&mut self, node: &TemplateNode) -> NodeId { match node { TemplateNode::Element { tag, @@ -126,7 +157,7 @@ impl RealDom { attrs, children, } => { - let node = Node::new(NodeType::Element { + let node = Node::new(NodeType::Element(ElementNode { tag: tag.to_string(), namespace: namespace.map(|s| s.to_string()), attributes: attrs @@ -148,30 +179,28 @@ impl RealDom { }) .collect(), listeners: FxHashSet::default(), - }); - let node_id = self.create_node(node); + })); + let node_id = self.create_node(node, true); for child in *children { let child_id = self.create_template_node(child); self.add_child(node_id, child_id); } node_id } - TemplateNode::Text { text } => self.create_node(Node::new(NodeType::Text { - text: text.to_string(), - })), - TemplateNode::Dynamic { .. } => self.create_node(Node::new(NodeType::Placeholder)), - TemplateNode::DynamicText { .. } => self.create_node(Node::new(NodeType::Text { - text: String::new(), - })), + TemplateNode::Text { text } => { + self.create_node(Node::new(NodeType::Text(text.to_string())), true) + } + TemplateNode::Dynamic { .. } => { + self.create_node(Node::new(NodeType::Placeholder), true) + } + TemplateNode::DynamicText { .. } => { + self.create_node(Node::new(NodeType::Text(String::new())), true) + } } } /// 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( - &mut self, - mutations: Mutations, - ) -> (DirtyNodeStates, FxHashMap) { - let mut nodes_updated: FxHashMap = FxHashMap::default(); + pub fn apply_mutations(&mut self, mutations: Mutations) { for template in mutations.templates { let mut template_root_ids = Vec::new(); for root in template.roots { @@ -181,11 +210,7 @@ impl RealDom { self.templates .insert(template.name.to_string(), template_root_ids); } - if !self.root_initialized { - self.root_initialized = true; - let root_id = self.tree.root(); - nodes_updated.insert(root_id, NodeMask::ALL); - } + for e in mutations.edits { use dioxus_core::Mutation::*; match e { @@ -194,7 +219,6 @@ impl RealDom { let parent = self.element_to_node_id(id); for child in children { self.add_child(parent, child); - mark_dirty(child, NodeMask::ALL, &mut nodes_updated); } } AssignId { path, id } => { @@ -202,38 +226,32 @@ impl RealDom { } CreatePlaceholder { id } => { let node = Node::new(NodeType::Placeholder); - let node_id = self.create_node(node); + let node_id = self.create_node(node, true); self.set_element_id(node_id, id); self.stack.push(node_id); - mark_dirty(node_id, NodeMask::ALL, &mut nodes_updated); } CreateTextNode { value, id } => { - let node = Node::new(NodeType::Text { - text: value.to_string(), - }); - let node_id = self.create_node(node); + let node = Node::new(NodeType::Text(value.to_string())); + let node_id = self.create_node(node, true); let node = self.tree.get_mut(node_id).unwrap(); node.node_data.element_id = Some(id); self.stack.push(node_id); - mark_dirty(node_id, NodeMask::new().with_text(), &mut nodes_updated); } HydrateText { path, value, id } => { let node_id = self.load_child(path); self.set_element_id(node_id, id); let node = self.tree.get_mut(node_id).unwrap(); - if let NodeType::Text { text } = &mut node.node_data.node_type { + if let NodeType::Text(text) = &mut node.node_data.node_type { *text = value.to_string(); } else { - node.node_data.node_type = NodeType::Text { - text: value.to_string(), - }; + node.node_data.node_type = NodeType::Text(value.to_string()); } - mark_dirty(node_id, NodeMask::new().with_text(), &mut nodes_updated); + self.mark_dirty(node_id, NodeMask::new().with_text()); } LoadTemplate { name, index, id } => { let template_id = self.templates[name][index]; - let clone_id = self.clone_node(template_id, &mut nodes_updated); + let clone_id = self.clone_node(template_id); self.set_element_id(clone_id, id); self.stack.push(clone_id); } @@ -242,7 +260,6 @@ 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); - mark_dirty(new, NodeMask::ALL, &mut nodes_updated); } self.tree.remove(old_node_id); } @@ -251,7 +268,6 @@ impl RealDom { let old_node_id = self.load_child(path); for new in new_nodes { self.tree.insert_before(old_node_id, new); - mark_dirty(new, NodeMask::ALL, &mut nodes_updated); } self.tree.remove(old_node_id); } @@ -260,7 +276,6 @@ impl RealDom { let old_node_id = self.element_to_node_id(id); for new in new_nodes.into_iter().rev() { self.tree.insert_after(old_node_id, new); - mark_dirty(new, NodeMask::ALL, &mut nodes_updated); } } InsertBefore { id, m } => { @@ -268,7 +283,6 @@ 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); - mark_dirty(new, NodeMask::ALL, &mut nodes_updated); } } SetAttribute { @@ -278,9 +292,9 @@ impl RealDom { ns, } => { let node_id = self.element_to_node_id(id); - let node = self.tree.get_mut(node_id).unwrap(); - if let NodeType::Element { attributes, .. } = &mut node.node_data.node_type { - attributes.insert( + let mut node = self.get_mut(node_id).unwrap(); + if let NodeTypeMut::Element(mut element) = node.node_type_mut() { + element.set_attribute( OwnedAttributeDiscription { name: name.to_string(), namespace: ns.map(|s| s.to_string()), @@ -288,18 +302,13 @@ impl RealDom { }, crate::node::OwnedAttributeValue::Text(value.to_string()), ); - mark_dirty( - node_id, - NodeMask::new_with_attrs(AttributeMask::single(name)), - &mut nodes_updated, - ); } } SetBoolAttribute { name, value, id } => { let node_id = self.element_to_node_id(id); - let node = self.tree.get_mut(node_id).unwrap(); - if let NodeType::Element { attributes, .. } = &mut node.node_data.node_type { - attributes.insert( + let mut node = self.get_mut(node_id).unwrap(); + if let NodeTypeMut::Element(mut element) = node.node_type_mut() { + element.set_attribute( OwnedAttributeDiscription { name: name.to_string(), namespace: None, @@ -307,25 +316,21 @@ impl RealDom { }, crate::node::OwnedAttributeValue::Bool(value), ); - mark_dirty( - node_id, - NodeMask::new_with_attrs(AttributeMask::single(name)), - &mut nodes_updated, - ); } } SetText { value, id } => { let node_id = self.element_to_node_id(id); - let node = self.tree.get_mut(node_id).unwrap(); - if let NodeType::Text { text } = &mut node.node_data.node_type { + let mut node = self.get_mut(node_id).unwrap(); + if let NodeTypeMut::Text(text) = node.node_type_mut() { *text = value.to_string(); } - mark_dirty(node_id, NodeMask::new().with_text(), &mut nodes_updated); } NewEventListener { name, id } => { let node_id = self.element_to_node_id(id); - let node = self.tree.get_mut(node_id).unwrap(); - if let NodeType::Element { listeners, .. } = &mut node.node_data.node_type { + let mut node = self.get_mut(node_id).unwrap(); + if let NodeTypeMut::Element(mut element) = node.node_type_mut() { + element.listeners_mut().insert(name.to_string()); + drop(node); match self.nodes_listening.get_mut(name) { Some(hs) => { hs.insert(node_id); @@ -336,14 +341,15 @@ impl RealDom { self.nodes_listening.insert(name.to_string(), hs); } } - listeners.insert(name.to_string()); } } RemoveEventListener { id, name } => { let node_id = self.element_to_node_id(id); - let node = self.tree.get_mut(node_id).unwrap(); - if let NodeType::Element { listeners, .. } = &mut node.node_data.node_type { - listeners.remove(name); + { + let mut node = self.get_mut(node_id).unwrap(); + if let NodeTypeMut::Element(mut element) = node.node_type_mut() { + element.listeners_mut().remove(name); + } } self.nodes_listening.get_mut(name).unwrap().remove(&node_id); } @@ -357,8 +363,17 @@ 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, + ctx: SendAnyMap, + ) -> (FxDashSet, FxHashMap) { + let tree = &mut self.tree; + let passes = &self.passes; let dirty_nodes = DirtyNodeStates::default(); + let nodes_updated = std::mem::take(&mut self.nodes_updated); for (&n, mask) in &nodes_updated { // remove any nodes that were created and then removed in the same mutations from the dirty nodes list if self.tree.contains(n) { @@ -370,18 +385,11 @@ impl RealDom { } } - (dirty_nodes, nodes_updated) - } - - /// 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: DirtyNodeStates, - ctx: SendAnyMap, - ) -> FxDashSet { - let tree = &mut self.tree; - let passes = &self.passes; - resolve_passes(tree, nodes_updated, passes, ctx) + todo!("incorporate other update members"); + ( + resolve_passes(tree, dirty_nodes, passes, ctx), + nodes_updated, + ) } /// Find all nodes that are listening for an event, sorted by there height in the dom progressing starting at the bottom and progressing up. @@ -411,39 +419,135 @@ impl RealDom { self.tree.root() } - fn clone_node( - &mut self, - node_id: NodeId, - nodes_updated: &mut FxHashMap, - ) -> RealNodeId { + fn clone_node(&mut self, node_id: NodeId) -> NodeId { let node = self.tree.get(node_id).unwrap(); - let new_node = node.clone(); - let new_id = self.create_node(new_node); - mark_dirty(new_id, NodeMask::ALL, nodes_updated); + let new_node = Node { + state: node.state.clone_or_default(), + node_data: node.node_data.clone(), + }; + let new_id = self.create_node(new_node, false); + if let Some(passes) = S::non_clone_nodes() { + for pass_id in &*passes { + self.passes_updated + .entry(node_id) + .or_default() + .insert(*pass_id); + } + } + let self_ptr = self as *mut Self; for child in self.tree.children_ids(node_id).unwrap() { unsafe { // 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, nodes_updated); + let child_id = self_mut.clone_node(*child); self_mut.add_child(new_id, child_id); } } new_id } -} -impl Deref for RealDom { - type Target = Tree>; + pub fn get_mut(&mut self, id: NodeId) -> Option> { + self.tree.get_mut(id).map(|node| NodeMut { + node: &mut node.node_data, + dirty: NodeMask::new(), + nodes_updated: &mut self.nodes_updated, + }) + } - fn deref(&self) -> &Self::Target { - &self.tree + /// WARNING: This escapes the reactive system that the real dom uses. Any changes made with this method will not trigger updates in states when [RealDom::update_state] is called. + pub fn get_mut_raw(&mut self, id: NodeId) -> Option<&mut Node> { + self.tree.get_mut(id) } } -impl DerefMut for RealDom { - fn deref_mut(&mut self) -> &mut Self::Target { - &mut self.tree +impl TreeView> for RealDom { + type Iterator<'a> = > as TreeView>>::Iterator<'a>; + + fn root(&self) -> NodeId { + self.tree.root() + } + + fn get(&self, id: NodeId) -> Option<&Node> { + self.tree.get(id) + } + + fn children(&self, id: NodeId) -> Option> { + self.tree.children(id) + } + + fn children_ids(&self, id: NodeId) -> Option<&[NodeId]> { + self.tree.children_ids(id) + } + + fn parent(&self, id: NodeId) -> Option<&Node> { + self.tree.parent(id) + } + + fn parent_id(&self, id: NodeId) -> Option { + self.tree.parent_id(id) + } + + fn height(&self, id: NodeId) -> Option { + self.tree.height(id) + } + + fn size(&self) -> usize { + self.tree.size() + } +} + +impl TreeLike> for RealDom { + fn create_node(&mut self, node: Node) -> NodeId { + let mask = NodeMask::ALL; + let id = self.tree.create_node(node); + self.tree.get_mut(id).unwrap().node_data.node_id = id; + self.mark_dirty(id, mask); + id + } + + fn add_child(&mut self, parent: NodeId, child: NodeId) { + // mark the parent's children changed + self.mark_child_changed(parent); + // mark the child's parent changed + self.mark_parent_added_or_removed(child); + self.tree.add_child(parent, child); + } + + fn remove(&mut self, id: NodeId) -> Option> { + if let Some(parent_id) = self.tree.parent_id(id) { + self.mark_child_changed(parent_id); + } + self.tree.remove(id) + } + + fn remove_all_children(&mut self, id: NodeId) -> Vec> { + self.mark_child_changed(id); + self.tree.remove_all_children(id) + } + + fn replace(&mut self, old: NodeId, new: NodeId) { + if let Some(parent_id) = self.tree.parent_id(old) { + self.mark_child_changed(parent_id); + self.mark_parent_added_or_removed(new); + } + self.tree.replace(old, new); + } + + fn insert_before(&mut self, id: NodeId, new: NodeId) { + if let Some(parent_id) = self.tree.parent_id(id) { + self.mark_child_changed(parent_id); + self.mark_parent_added_or_removed(new); + } + self.tree.insert_before(id, new); + } + + fn insert_after(&mut self, id: NodeId, new: NodeId) { + if let Some(parent_id) = self.tree.parent_id(id) { + self.mark_child_changed(parent_id); + self.mark_parent_added_or_removed(new); + } + self.tree.insert_after(id, new); } } @@ -455,10 +559,10 @@ impl Index for RealDom { } } -impl Index for RealDom { +impl Index for RealDom { type Output = Node; - fn index(&self, idx: RealNodeId) -> &Self::Output { + fn index(&self, idx: NodeId) -> &Self::Output { self.tree.get(idx).unwrap() } } @@ -469,8 +573,114 @@ impl IndexMut for RealDom { } } -impl IndexMut for RealDom { - fn index_mut(&mut self, idx: RealNodeId) -> &mut Self::Output { +impl IndexMut for RealDom { + fn index_mut(&mut self, idx: NodeId) -> &mut Self::Output { self.tree.get_mut(idx).unwrap() } } + +pub struct NodeMut<'a> { + node: &'a mut NodeData, + dirty: NodeMask, + nodes_updated: &'a mut FxHashMap, +} + +impl<'a> NodeMut<'a> { + pub fn node_type(&self) -> &NodeType { + &self.node.node_type + } + + pub fn node_type_mut(&mut self) -> NodeTypeMut<'_> { + match &mut self.node.node_type { + NodeType::Element(element) => NodeTypeMut::Element(ElementNodeMut { + element, + dirty: &mut self.dirty, + }), + NodeType::Text(text) => { + self.dirty.set_text(); + NodeTypeMut::Text(text) + } + NodeType::Placeholder => NodeTypeMut::Placeholder, + } + } +} + +impl Drop for NodeMut<'_> { + fn drop(&mut self) { + let node_id = self.node.node_id; + let mask = std::mem::take(&mut self.dirty); + if let Some(node) = self.nodes_updated.get_mut(&node_id) { + *node = node.union(&mask); + } else { + self.nodes_updated.insert(node_id, mask); + } + } +} + +pub enum NodeTypeMut<'a> { + Element(ElementNodeMut<'a>), + Text(&'a mut String), + Placeholder, +} + +pub struct ElementNodeMut<'a> { + element: &'a mut ElementNode, + dirty: &'a mut NodeMask, +} + +impl ElementNodeMut<'_> { + pub fn tag(&self) -> &str { + &self.element.tag + } + + pub fn tag_mut(&mut self) -> &mut String { + self.dirty.set_tag(); + &mut self.element.tag + } + + pub fn namespace(&self) -> Option<&str> { + self.element.namespace.as_deref() + } + + pub fn namespace_mut(&mut self) -> &mut Option { + self.dirty.set_namespace(); + &mut self.element.namespace + } + + pub fn attributes(&self) -> &FxHashMap { + &self.element.attributes + } + + pub fn attributes_mut( + &mut self, + ) -> &mut FxHashMap { + self.dirty.add_attributes(AttributeMask::All); + &mut self.element.attributes + } + + pub fn set_attribute( + &mut self, + name: OwnedAttributeDiscription, + value: OwnedAttributeValue, + ) -> Option { + self.dirty.add_attributes(AttributeMask::single(&name.name)); + self.element.attributes.insert(name, value) + } + + pub fn get_attribute_mut( + &mut self, + name: &OwnedAttributeDiscription, + ) -> Option<&mut OwnedAttributeValue> { + self.dirty.add_attributes(AttributeMask::single(&name.name)); + self.element.attributes.get_mut(name) + } + + pub fn listeners(&self) -> &FxHashSet { + &self.element.listeners + } + + pub fn listeners_mut(&mut self) -> &mut FxHashSet { + self.dirty.set_listeners(); + &mut self.element.listeners + } +} diff --git a/packages/native-core/src/state.rs b/packages/native-core/src/state.rs index beabb54c2..8fbdae6cb 100644 --- a/packages/native-core/src/state.rs +++ b/packages/native-core/src/state.rs @@ -1,10 +1,7 @@ -use std::cmp::Ordering; - -use crate::node::Node; use crate::node_ref::{NodeMask, NodeView}; -use crate::passes::{resolve_passes, AnyMapLike, DirtyNodeStates, Pass, TypeErasedPass}; -use crate::tree::{Tree, TreeView}; -use crate::{FxDashSet, RealNodeId, SendAnyMap}; +use crate::passes::{AnyMapLike, TypeErasedPass}; +use std::any::TypeId; +use std::cmp::Ordering; /// Join two sorted iterators pub(crate) fn union_ordered_iter<'a>( @@ -213,6 +210,16 @@ pub trait NodeDepState { pub trait State: Default + Clone + AnyMapLike + 'static { #[doc(hidden)] fn create_passes() -> Box<[TypeErasedPass]>; + + #[doc(hidden)] + fn clone_or_default(&self) -> Self { + self.clone() + } + + #[doc(hidden)] + fn non_clone_nodes() -> Option> { + None + } } impl ChildDepState for () { diff --git a/packages/native-core/src/tree.rs b/packages/native-core/src/tree.rs index 0824e0b51..5c14d159f 100644 --- a/packages/native-core/src/tree.rs +++ b/packages/native-core/src/tree.rs @@ -25,6 +25,17 @@ pub struct Tree { } impl Tree { + pub fn new(root: T) -> Self { + let mut nodes = Slab::default(); + let root = NodeId(nodes.insert(Node { + value: root, + parent: None, + children: Vec::new(), + height: 0, + })); + Self { nodes, root } + } + fn try_remove(&mut self, id: NodeId) -> Option> { self.nodes.try_remove(id.0).map(|node| { if let Some(parent) = node.parent { @@ -63,10 +74,6 @@ impl Tree { pub trait TreeView: Sized { type Iterator<'a>: Iterator - where - T: 'a, - Self: 'a; - type IteratorMut<'a>: Iterator where T: 'a, Self: 'a; @@ -83,69 +90,16 @@ pub trait TreeView: Sized { unsafe { self.get(id).unwrap_unchecked() } } - fn get_mut(&mut self, id: NodeId) -> Option<&mut T>; - - fn get_mut_unchecked(&mut self, id: NodeId) -> &mut T { - unsafe { self.get_mut(id).unwrap_unchecked() } - } - fn children(&self, id: NodeId) -> Option>; - fn children_mut(&mut self, id: NodeId) -> Option>; - - 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. - (*mut_ptr).get_mut(id).and_then(|parent| { - (*mut_ptr) - .children_mut(id) - .map(|children| (parent, children)) - }) - } - } - fn children_ids(&self, id: NodeId) -> Option<&[NodeId]>; fn parent(&self, id: NodeId) -> Option<&T>; - fn parent_mut(&mut self, id: NodeId) -> Option<&mut T>; - - fn node_parent_mut(&mut self, id: NodeId) -> Option<(&mut T, Option<&mut T>)> { - let mut_ptr: *mut Self = self; - unsafe { - // Safety: No node has itself as a parent. - (*mut_ptr) - .get_mut(id) - .map(|node| (node, (*mut_ptr).parent_mut(id))) - } - } - - fn node_parent_children_mut( - &mut self, - id: NodeId, - ) -> Option<(&mut T, Option<&mut T>, Option>)> { - let mut_ptr: *mut Self = self; - unsafe { - // Safety: No node has itself as a parent or child. - (*mut_ptr) - .get_mut(id) - .map(|node| (node, (*mut_ptr).parent_mut(id), (*mut_ptr).children_mut(id))) - } - } - fn parent_id(&self, id: NodeId) -> Option; fn height(&self, id: NodeId) -> Option; - fn map &T2, FMut: Fn(&mut T) -> &mut T2>( - &mut self, - map: F, - map_mut: FMut, - ) -> TreeMap { - TreeMap::new(self, map, map_mut) - } - fn size(&self) -> usize; fn traverse_depth_first(&self, mut f: impl FnMut(&T)) { @@ -160,18 +114,6 @@ pub trait TreeView: Sized { } } - fn traverse_depth_first_mut(&mut self, mut f: impl FnMut(&mut T)) { - let mut stack = vec![self.root()]; - while let Some(id) = stack.pop() { - if let Some(node) = self.get_mut(id) { - f(node); - if let Some(children) = self.children_ids(id) { - stack.extend(children.iter().copied().rev()); - } - } - } - } - fn traverse_breadth_first(&self, mut f: impl FnMut(&T)) { let mut queue = VecDeque::new(); queue.push_back(self.root()); @@ -186,6 +128,61 @@ pub trait TreeView: Sized { } } } +} + +pub trait TreeViewMut: Sized + TreeView { + type IteratorMut<'a>: Iterator + where + T: 'a, + Self: 'a; + + fn get_mut(&mut self, id: NodeId) -> Option<&mut T>; + + fn get_mut_unchecked(&mut self, id: NodeId) -> &mut T { + unsafe { self.get_mut(id).unwrap_unchecked() } + } + + fn children_mut(&mut self, id: NodeId) -> Option<>::IteratorMut<'_>>; + + fn parent_child_mut( + &mut self, + id: NodeId, + ) -> Option<(&mut T, >::IteratorMut<'_>)> { + let mut_ptr: *mut Self = self; + unsafe { + // Safety: No node has itself as a child. + (*mut_ptr).get_mut(id).and_then(|parent| { + (*mut_ptr) + .children_mut(id) + .map(|children| (parent, children)) + }) + } + } + + fn parent_mut(&mut self, id: NodeId) -> Option<&mut T>; + + fn node_parent_mut(&mut self, id: NodeId) -> Option<(&mut T, Option<&mut T>)>; + + fn node_parent_children_mut( + &mut self, + id: NodeId, + ) -> Option<( + &mut T, + Option<&mut T>, + Option<>::IteratorMut<'_>>, + )>; + + fn traverse_depth_first_mut(&mut self, mut f: impl FnMut(&mut T)) { + let mut stack = vec![self.root()]; + while let Some(id) = stack.pop() { + if let Some(node) = self.get_mut(id) { + f(node); + if let Some(children) = self.children_ids(id) { + stack.extend(children.iter().copied().rev()); + } + } + } + } fn traverse_breadth_first_mut(&mut self, mut f: impl FnMut(&mut T)) { let mut queue = VecDeque::new(); @@ -203,9 +200,7 @@ pub trait TreeView: Sized { } } -pub trait TreeLike: TreeView { - fn new(root: T) -> Self; - +pub trait TreeLike { fn create_node(&mut self, value: T) -> NodeId; fn add_child(&mut self, parent: NodeId, child: NodeId); @@ -239,22 +234,22 @@ impl<'a, T: 'a, Tr: TreeView> Iterator for ChildNodeIterator<'a, T, Tr> { } } -pub struct ChildNodeIteratorMut<'a, T, Tr: TreeView + 'a> { +pub struct ChildNodeIteratorMut<'a, T, Tr: TreeViewMut + 'a> { tree: *mut Tr, children_ids: &'a [NodeId], index: usize, node_type: PhantomData, } -unsafe impl<'a, T, Tr: TreeView + 'a> Sync for ChildNodeIteratorMut<'a, T, Tr> {} +unsafe impl<'a, T, Tr: TreeViewMut + 'a> Sync for ChildNodeIteratorMut<'a, T, Tr> {} -impl<'a, T, Tr: TreeView> ChildNodeIteratorMut<'a, T, Tr> { +impl<'a, T, Tr: TreeViewMut> ChildNodeIteratorMut<'a, T, Tr> { fn tree_mut(&mut self) -> &'a mut Tr { unsafe { &mut *self.tree } } } -impl<'a, T: 'a, Tr: TreeView> Iterator for ChildNodeIteratorMut<'a, T, Tr> { +impl<'a, T: 'a, Tr: TreeViewMut> Iterator for ChildNodeIteratorMut<'a, T, Tr> { type Item = &'a mut T; fn next(&mut self) -> Option { @@ -272,7 +267,6 @@ impl<'a, T: 'a, Tr: TreeView> Iterator for ChildNodeIteratorMut<'a, T, Tr> { impl TreeView for Tree { type Iterator<'a> = ChildNodeIterator<'a, T, Tree> where T: 'a; - type IteratorMut<'a> = ChildNodeIteratorMut<'a, T, Tree> where T: 'a; fn root(&self) -> NodeId { self.root @@ -282,10 +276,6 @@ impl TreeView for Tree { self.nodes.get(id.0).map(|node| &node.value) } - fn get_mut(&mut self, id: NodeId) -> Option<&mut T> { - self.nodes.get_mut(id.0).map(|node| &mut node.value) - } - fn children(&self, id: NodeId) -> Option> { self.children_ids(id).map(|children_ids| ChildNodeIterator { tree: self, @@ -295,20 +285,6 @@ impl TreeView for Tree { }) } - 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 - self.children_ids(id) - .map(|children_ids| ChildNodeIteratorMut { - tree: &mut *raw_ptr, - children_ids, - index: 0, - node_type: PhantomData, - }) - } - } - fn children_ids(&self, id: NodeId) -> Option<&[NodeId]> { self.nodes.get(id.0).map(|node| node.children.as_slice()) } @@ -320,6 +296,30 @@ impl TreeView for Tree { .map(|node| &node.value) } + fn parent_id(&self, id: NodeId) -> Option { + self.nodes.get(id.0).and_then(|node| node.parent) + } + + fn height(&self, id: NodeId) -> Option { + self.nodes.get(id.0).map(|n| n.height) + } + + fn get_unchecked(&self, id: NodeId) -> &T { + unsafe { &self.nodes.get_unchecked(id.0).value } + } + + fn size(&self) -> usize { + self.nodes.len() + } +} + +impl TreeViewMut for Tree { + type IteratorMut<'a> = ChildNodeIteratorMut<'a, T, Tree> where T: 'a; + + fn get_mut(&mut self, id: NodeId) -> Option<&mut T> { + self.nodes.get_mut(id.0).map(|node| &mut node.value) + } + fn parent_mut(&mut self, id: NodeId) -> Option<&mut T> { let self_ptr = self as *mut Self; unsafe { @@ -334,39 +334,52 @@ impl TreeView for Tree { } } - fn parent_id(&self, id: NodeId) -> Option { - self.nodes.get(id.0).and_then(|node| node.parent) - } - - fn height(&self, id: NodeId) -> Option { - self.nodes.get(id.0).map(|n| n.height) - } - - fn get_unchecked(&self, id: NodeId) -> &T { - unsafe { &self.nodes.get_unchecked(id.0).value } + 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 + self.children_ids(id) + .map(|children_ids| ChildNodeIteratorMut { + tree: &mut *raw_ptr, + children_ids, + index: 0, + node_type: PhantomData, + }) + } } fn get_mut_unchecked(&mut self, id: NodeId) -> &mut T { unsafe { &mut self.nodes.get_unchecked_mut(id.0).value } } - fn size(&self) -> usize { - self.nodes.len() + fn node_parent_mut(&mut self, id: NodeId) -> Option<(&mut T, Option<&mut T>)> { + if let Some(parent_id) = self.parent_id(id) { + self.nodes + .get2_mut(id.0, parent_id.0) + .map(|(node, parent)| (&mut node.value, Some(&mut parent.value))) + } else { + self.nodes.get_mut(id.0).map(|node| (&mut node.value, None)) + } + } + + fn node_parent_children_mut( + &mut self, + id: NodeId, + ) -> Option<( + &mut T, + Option<&mut T>, + Option<>::IteratorMut<'_>>, + )> { + // Safety: No node has itself as a parent. + let unbounded_self = unsafe { &mut *(self as *mut Self) }; + self.node_parent_mut(id).map(move |(node, parent)| { + let children = unbounded_self.children_mut(id); + (node, parent, children) + }) } } impl TreeLike for Tree { - fn new(root: T) -> Self { - let mut nodes = Slab::default(); - let root = NodeId(nodes.insert(Node { - value: root, - parent: None, - children: Vec::new(), - height: 0, - })); - Self { nodes, root } - } - fn create_node(&mut self, value: T) -> NodeId { NodeId(self.nodes.insert(Node { value, @@ -448,248 +461,6 @@ impl TreeLike for Tree { self.set_height(new, height); } } - -pub struct TreeMap<'a, T1, T2, Tr, F, FMut> -where - Tr: TreeView, - F: Fn(&T1) -> &T2, - FMut: Fn(&mut T1) -> &mut T2, -{ - tree: &'a mut Tr, - map: F, - map_mut: FMut, - in_node_type: PhantomData, - out_node_type: PhantomData, -} - -impl<'a, T1, T2, Tr, F, FMut> TreeMap<'a, T1, T2, Tr, F, FMut> -where - Tr: TreeView, - F: Fn(&T1) -> &T2, - FMut: Fn(&mut T1) -> &mut T2, -{ - pub fn new(tree: &'a mut Tr, map: F, map_mut: FMut) -> Self { - TreeMap { - tree, - map, - map_mut, - in_node_type: PhantomData, - out_node_type: PhantomData, - } - } -} - -impl<'a, T1, T2, Tr, F, FMut> TreeView for TreeMap<'a, T1, T2, Tr, F, FMut> -where - Tr: TreeView, - F: Fn(&T1) -> &T2, - FMut: Fn(&mut T1) -> &mut T2, -{ - type Iterator<'b> = ChildNodeIterator<'b, T2, TreeMap<'a, T1, T2, Tr, F, FMut>> - where - T2: 'b, - Self:'b; - type IteratorMut<'b> = ChildNodeIteratorMut<'b, T2, TreeMap<'a, T1, T2, Tr, F, FMut>> - where - T2: 'b, - Self:'b; - - fn root(&self) -> NodeId { - self.tree.root() - } - - fn get(&self, id: NodeId) -> Option<&T2> { - self.tree.get(id).map(|node| (self.map)(node)) - } - - fn get_mut(&mut self, id: NodeId) -> Option<&mut T2> { - self.tree.get_mut(id).map(|node| (self.map_mut)(node)) - } - - fn children(&self, id: NodeId) -> Option> { - self.children_ids(id).map(|children_ids| ChildNodeIterator { - tree: self, - children_ids, - index: 0, - node_type: PhantomData, - }) - } - - fn children_mut(&mut self, id: NodeId) -> Option> { - let raw_ptr = self as *mut Self; - unsafe { - // Safety: No node can be a child twice. - self.children_ids(id) - .map(|children_ids| ChildNodeIteratorMut { - tree: &mut *raw_ptr, - children_ids, - index: 0, - node_type: PhantomData, - }) - } - } - - fn children_ids(&self, id: NodeId) -> Option<&[NodeId]> { - self.tree.children_ids(id) - } - - fn parent(&self, id: NodeId) -> Option<&T2> { - self.tree.parent(id).map(|node| (self.map)(node)) - } - - fn parent_mut(&mut self, id: NodeId) -> Option<&mut T2> { - self.tree.parent_mut(id).map(|node| (self.map_mut)(node)) - } - - fn parent_id(&self, id: NodeId) -> Option { - self.tree.parent_id(id) - } - - fn height(&self, id: NodeId) -> Option { - self.tree.height(id) - } - - fn get_unchecked(&self, id: NodeId) -> &T2 { - (self.map)(self.tree.get_unchecked(id)) - } - - fn get_mut_unchecked(&mut self, id: NodeId) -> &mut T2 { - (self.map_mut)(self.tree.get_mut_unchecked(id)) - } - - fn size(&self) -> usize { - self.tree.size() - } -} - -/// A view into a tree that can be shared between multiple threads. Nodes are locked invividually. -pub struct SharedView<'a, T, Tr: TreeView> { - tree: Arc>, - node_locks: Arc>>, - node_type: PhantomData, -} - -impl<'a, T, Tr: TreeView> SharedView<'a, T, Tr> { - /// Checks if a node is currently locked. Returns None if the node does not exist. - pub fn check_lock(&self, id: NodeId) -> Option { - let locks = self.node_locks.read(); - locks.get(id.0).map(|lock| lock.is_locked()) - } -} - -unsafe impl<'a, T, Tr: TreeView> Send for SharedView<'a, T, Tr> {} -unsafe impl<'a, T, Tr: TreeView> Sync for SharedView<'a, T, Tr> {} -impl<'a, T, Tr: TreeView> Clone for SharedView<'a, T, Tr> { - fn clone(&self) -> Self { - Self { - tree: self.tree.clone(), - node_locks: self.node_locks.clone(), - node_type: PhantomData, - } - } -} - -impl<'a, T, Tr: TreeView> SharedView<'a, T, Tr> { - pub fn new(tree: &'a mut Tr) -> Self { - let tree = Arc::new(UnsafeCell::new(tree)); - let mut node_locks = Vec::new(); - for _ in 0..unsafe { (*tree.get()).size() } { - node_locks.push(RawMutex::INIT); - } - Self { - tree, - node_locks: Arc::new(RwLock::new(node_locks)), - node_type: PhantomData, - } - } - - fn lock_node(&self, node: NodeId) { - let read = self.node_locks.read(); - let lock = read.get(node.0); - match lock { - Some(lock) => lock.lock(), - None => { - drop(read); - let mut write = self.node_locks.write(); - write.resize_with(node.0 + 1, || RawMutex::INIT); - unsafe { write.get_unchecked(node.0).lock() } - } - } - } - - fn unlock_node(&self, node: NodeId) { - let read = self.node_locks.read(); - let lock = read.get(node.0); - match lock { - Some(lock) => unsafe { lock.unlock() }, - None => { - panic!("unlocking node that was not locked") - } - } - } - - fn with_node(&self, node_id: NodeId, f: impl FnOnce(&'a mut Tr) -> R) -> R { - self.lock_node(node_id); - let tree = unsafe { &mut *self.tree.get() }; - let r = f(tree); - self.unlock_node(node_id); - r - } -} - -impl<'a, T, Tr: TreeView> TreeView for SharedView<'a, T, Tr> { - type Iterator<'b> = Tr::Iterator<'b> where T: 'b, Self: 'b; - - type IteratorMut<'b>=Tr::IteratorMut<'b> - where - T: 'b, - Self: 'b; - - fn root(&self) -> NodeId { - unsafe { (*self.tree.get()).root() } - } - - fn get(&self, id: NodeId) -> Option<&T> { - self.with_node(id, |t| t.get(id)) - } - - fn get_mut(&mut self, id: NodeId) -> Option<&mut T> { - self.with_node(id, |t| t.get_mut(id)) - } - - fn children(&self, id: NodeId) -> Option> { - self.with_node(id, |t| t.children(id)) - } - - fn children_mut(&mut self, id: NodeId) -> Option> { - self.with_node(id, |t| t.children_mut(id)) - } - - fn children_ids(&self, id: NodeId) -> Option<&[NodeId]> { - self.with_node(id, |t| t.children_ids(id)) - } - - fn parent(&self, id: NodeId) -> Option<&T> { - self.with_node(id, |t| t.get(id)) - } - - fn parent_mut(&mut self, id: NodeId) -> Option<&mut T> { - self.with_node(id, |t| t.parent_mut(id)) - } - - fn parent_id(&self, id: NodeId) -> Option { - self.with_node(id, |t| t.parent_id(id)) - } - - fn height(&self, id: NodeId) -> Option { - unsafe { (*self.tree.get()).height(id) } - } - - fn size(&self) -> usize { - unsafe { (*self.tree.get()).size() } - } -} - #[test] fn creation() { let mut tree = Tree::new(1); @@ -798,60 +569,6 @@ fn deletion() { assert_eq!(tree.children_ids(parent).unwrap(), &[]); } -#[test] -fn shared_view() { - use std::thread; - let mut tree = Tree::new(1); - let parent = tree.root(); - let child = tree.create_node(0); - tree.add_child(parent, child); - - let shared = SharedView::new(&mut tree); - - thread::scope(|s| { - let (mut shared1, mut shared2, mut shared3) = - (shared.clone(), shared.clone(), shared.clone()); - s.spawn(move || { - assert_eq!(*shared1.get_mut(parent).unwrap(), 1); - assert_eq!(*shared1.get_mut(child).unwrap(), 0); - }); - s.spawn(move || { - assert_eq!(*shared2.get_mut(child).unwrap(), 0); - assert_eq!(*shared2.get_mut(parent).unwrap(), 1); - }); - s.spawn(move || { - assert_eq!(*shared3.get_mut(parent).unwrap(), 1); - assert_eq!(*shared3.get_mut(child).unwrap(), 0); - }); - }); -} - -#[test] -fn map() { - #[derive(Debug, PartialEq)] - struct Value { - value: i32, - } - impl Value { - fn new(value: i32) -> Self { - Self { value } - } - } - - let mut tree = Tree::new(Value::new(1)); - let parent = tree.root(); - let child = tree.create_node(Value::new(0)); - tree.add_child(parent, child); - - let mut mapped = tree.map(|x| &x.value, |x| &mut x.value); - - *mapped.get_mut(child).unwrap() = 1; - *mapped.get_mut(parent).unwrap() = 2; - - assert_eq!(*tree.get(parent).unwrap(), Value::new(2)); - assert_eq!(*tree.get(child).unwrap(), Value::new(1)); -} - #[test] fn traverse_depth_first() { let mut tree = Tree::new(0); diff --git a/packages/native-core/src/utils/persistant_iterator.rs b/packages/native-core/src/utils/persistant_iterator.rs index 6db60f086..dfbcb4638 100644 --- a/packages/native-core/src/utils/persistant_iterator.rs +++ b/packages/native-core/src/utils/persistant_iterator.rs @@ -1,10 +1,10 @@ use crate::{ - node::NodeType, + node::{ElementNode, NodeType}, passes::{AnyMapLike, TypeErasedPass}, real_dom::RealDom, state::State, tree::TreeView, - NodeId, RealNodeId, + NodeId, }; use dioxus_core::{Mutation, Mutations}; use std::fmt::Debug; @@ -12,12 +12,12 @@ use std::fmt::Debug; #[derive(Debug)] pub enum ElementProduced { /// The iterator produced an element by progressing to the next node in a depth first order. - Progressed(RealNodeId), + Progressed(NodeId), /// The iterator reached the end of the tree and looped back to the root - Looped(RealNodeId), + Looped(NodeId), } impl ElementProduced { - pub fn id(&self) -> RealNodeId { + pub fn id(&self) -> NodeId { match self { ElementProduced::Progressed(id) => *id, ElementProduced::Looped(id) => *id, @@ -56,7 +56,7 @@ impl NodePosition { /// The iterator loops around when it reaches the end or the beginning. pub struct PersistantElementIter { // stack of elements and fragments - stack: smallvec::SmallVec<[(RealNodeId, NodePosition); 5]>, + stack: smallvec::SmallVec<[(NodeId, NodePosition); 5]>, } impl Default for PersistantElementIter { @@ -141,7 +141,7 @@ impl PersistantElementIter { let (last, old_child_idx) = self.stack.last_mut().unwrap(); let node = &rdom[*last]; match &node.node_data.node_type { - NodeType::Element { .. } => { + NodeType::Element(ElementNode { .. }) => { let children = rdom.tree.children_ids(*last).unwrap(); *old_child_idx = old_child_idx.map(|i| i + 1); // if we have children, go to the next child @@ -151,7 +151,8 @@ impl PersistantElementIter { self.next(rdom) } else { let id = children[child_idx]; - if let NodeType::Element { .. } = &rdom[id].node_data.node_type { + if let NodeType::Element(ElementNode { .. }) = &rdom[id].node_data.node_type + { self.stack.push((id, NodePosition::AtNode)); } ElementProduced::Progressed(id) @@ -170,12 +171,12 @@ impl PersistantElementIter { pub fn prev(&mut self, rdom: &RealDom) -> ElementProduced { // recursively add the last child element to the stack fn push_back( - stack: &mut smallvec::SmallVec<[(RealNodeId, NodePosition); 5]>, - new_node: RealNodeId, + stack: &mut smallvec::SmallVec<[(NodeId, NodePosition); 5]>, + new_node: NodeId, rdom: &RealDom, - ) -> RealNodeId { + ) -> NodeId { match &rdom[new_node].node_data.node_type { - NodeType::Element { .. } => { + NodeType::Element(ElementNode { .. }) => { let children = rdom.tree.children_ids(new_node).unwrap(); if children.is_empty() { new_node @@ -194,7 +195,7 @@ impl PersistantElementIter { let (last, old_child_idx) = self.stack.last_mut().unwrap(); let node = &rdom[*last]; match &node.node_data.node_type { - NodeType::Element { .. } => { + NodeType::Element(ElementNode { .. }) => { let children = rdom.tree.children_ids(*last).unwrap(); // if we have children, go to the next child if let NodePosition::InChild(0) = old_child_idx { @@ -228,7 +229,7 @@ impl PersistantElementIter { } } - fn pop(&mut self) -> RealNodeId { + fn pop(&mut self) -> NodeId { self.stack.pop().unwrap().0 } } @@ -280,68 +281,68 @@ fn traverse() { let div_tag = "div".to_string(); assert!(matches!( &rdom[iter.next(&rdom).id()].node_data.node_type, - NodeType::Element { tag: div_tag, .. } + NodeType::Element(ElementNode { tag: div_tag, .. }) )); assert!(matches!( &rdom[iter.next(&rdom).id()].node_data.node_type, - NodeType::Element { tag: div_tag, .. } + NodeType::Element(ElementNode { tag: div_tag, .. }) )); let text1 = "hello".to_string(); assert!(matches!( &rdom[iter.next(&rdom).id()].node_data.node_type, - NodeType::Text { text: text1, .. } + NodeType::Text(text1) )); let p_tag = "p".to_string(); assert!(matches!( &rdom[iter.next(&rdom).id()].node_data.node_type, - NodeType::Element { tag: p_tag, .. } + NodeType::Element(ElementNode { tag: p_tag, .. }) )); let text2 = "world".to_string(); assert!(matches!( &rdom[iter.next(&rdom).id()].node_data.node_type, - NodeType::Text { text: text2, .. } + NodeType::Text(text2) )); let text3 = "hello world".to_string(); assert!(matches!( &rdom[iter.next(&rdom).id()].node_data.node_type, - NodeType::Text { text: text3, .. } + NodeType::Text(text3) )); assert!(matches!( &rdom[iter.next(&rdom).id()].node_data.node_type, - NodeType::Element { tag: div_tag, .. } + NodeType::Element(ElementNode { tag: div_tag, .. }) )); assert!(matches!( &rdom[iter.prev(&rdom).id()].node_data.node_type, - NodeType::Text { text: text3, .. } + NodeType::Text(text3) )); assert!(matches!( &rdom[iter.prev(&rdom).id()].node_data.node_type, - NodeType::Text { text: text2, .. } + NodeType::Text(text2) )); assert!(matches!( &rdom[iter.prev(&rdom).id()].node_data.node_type, - NodeType::Element { tag: p_tag, .. } + NodeType::Element(ElementNode { tag: p_tag, .. }) )); assert!(matches!( &rdom[iter.prev(&rdom).id()].node_data.node_type, - NodeType::Text { text: text1, .. } + NodeType::Text(text1) )); assert!(matches!( &rdom[iter.prev(&rdom).id()].node_data.node_type, - NodeType::Element { tag: div_tag, .. } + NodeType::Element(ElementNode { tag: div_tag, .. }) )); assert!(matches!( &rdom[iter.prev(&rdom).id()].node_data.node_type, - NodeType::Element { tag: div_tag, .. } + NodeType::Element(ElementNode { tag: div_tag, .. }) )); assert!(matches!( &rdom[iter.prev(&rdom).id()].node_data.node_type, - NodeType::Element { tag: div_tag, .. } + NodeType::Element(ElementNode { tag: div_tag, .. }) )); assert!(matches!( &rdom[iter.prev(&rdom).id()].node_data.node_type, - NodeType::Text { text: text3, .. } + NodeType::Text(text3) )); } @@ -416,14 +417,14 @@ fn persist_removes() { dbg!(&rdom[idx].node_data.node_type); assert!(matches!( &rdom[idx].node_data.node_type, - NodeType::Element { tag: root_tag, .. } + NodeType::Element(ElementNode { tag: root_tag, .. }) )); let idx = iter2.next(&rdom).id(); dbg!(&rdom[idx].node_data.node_type); assert!(matches!( &rdom[idx].node_data.node_type, - NodeType::Element { tag: root_tag, .. } + NodeType::Element(ElementNode { tag: root_tag, .. }) )); } @@ -479,7 +480,7 @@ fn persist_instertions_before() { let idx = iter.next(&rdom).id(); assert!(matches!( &rdom[idx].node_data.node_type, - NodeType::Element { tag: p_tag, .. } + NodeType::Element(ElementNode { tag: p_tag, .. }) )); } @@ -534,12 +535,12 @@ fn persist_instertions_after() { let idx = iter.next(&rdom).id(); assert!(matches!( &rdom[idx].node_data.node_type, - NodeType::Element { tag: p_tag, .. } + NodeType::Element(ElementNode { tag: p_tag, .. }) )); let text = "hello world".to_string(); let idx = iter.next(&rdom).id(); assert!(matches!( &rdom[idx].node_data.node_type, - NodeType::Text { text, .. } + NodeType::Text(text) )); } diff --git a/packages/tui/src/focus.rs b/packages/tui/src/focus.rs index 90d9e9da0..a77eef0a2 100644 --- a/packages/tui/src/focus.rs +++ b/packages/tui/src/focus.rs @@ -3,7 +3,7 @@ use crate::{node::PreventDefault, TuiDom}; use dioxus_native_core::{ tree::TreeView, utils::{ElementProduced, PersistantElementIter}, - RealNodeId, + NodeId, }; use dioxus_native_core_macro::sorted_str_slice; @@ -120,7 +120,7 @@ const FOCUS_ATTRIBUTES: &[&str] = &sorted_str_slice!(["tabindex"]); #[derive(Default)] pub(crate) struct FocusState { pub(crate) focus_iter: PersistantElementIter, - pub(crate) last_focused_id: Option, + pub(crate) last_focused_id: Option, pub(crate) focus_level: FocusLevel, pub(crate) dirty: bool, } @@ -236,11 +236,7 @@ impl FocusState { } pub(crate) fn prune(&mut self, mutations: &dioxus_core::Mutations, rdom: &TuiDom) { - fn remove_children( - to_prune: &mut [&mut Option], - rdom: &TuiDom, - removed: RealNodeId, - ) { + fn remove_children(to_prune: &mut [&mut Option], rdom: &TuiDom, removed: NodeId) { for opt in to_prune.iter_mut() { if let Some(id) = opt { if *id == removed { @@ -274,7 +270,7 @@ impl FocusState { } } - pub(crate) fn set_focus(&mut self, rdom: &mut TuiDom, id: RealNodeId) { + pub(crate) fn set_focus(&mut self, rdom: &mut TuiDom, id: NodeId) { if let Some(old) = self.last_focused_id.replace(id) { rdom[old].state.focused = false; }