From 1587b41829b0db4edc4e50f1008ee85272db420e Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Thu, 19 Jan 2023 14:40:56 -0600 Subject: [PATCH] WIP make ECS work with reactive system --- packages/native-core/Cargo.toml | 2 +- packages/native-core/src/lib.rs | 2 - packages/native-core/src/node.rs | 26 +- packages/native-core/src/node_ref.rs | 38 +- packages/native-core/src/passes.rs | 366 ++++++++-------- packages/native-core/src/real_dom.rs | 368 ++++++++-------- packages/native-core/src/state.rs | 46 -- packages/native-core/src/tree.rs | 395 ++++++++---------- packages/native-core/src/utils/mod.rs | 4 +- .../src/utils/persistant_iterator.rs | 2 - 10 files changed, 564 insertions(+), 685 deletions(-) delete mode 100644 packages/native-core/src/state.rs diff --git a/packages/native-core/Cargo.toml b/packages/native-core/Cargo.toml index 5a837e33a..bf1f9ba92 100644 --- a/packages/native-core/Cargo.toml +++ b/packages/native-core/Cargo.toml @@ -20,7 +20,7 @@ smallvec = "1.6" rustc-hash = "1.1.0" anymap = "1.0.0-beta.2" slab = "0.4" -parking_lot = "0.12.1" +parking_lot = { version = "0.12.1", features = ["send_guard"] } crossbeam-deque = "0.8.2" dashmap = "5.4.0" hashbrown = { version = "0.13.2", features = ["raw"] } diff --git a/packages/native-core/src/lib.rs b/packages/native-core/src/lib.rs index c264155af..051a8731d 100644 --- a/packages/native-core/src/lib.rs +++ b/packages/native-core/src/lib.rs @@ -5,7 +5,6 @@ pub use node_ref::NodeMask; pub use passes::AnyMapLike; pub use passes::{Dependancy, Pass, TypeErasedPass}; use rustc_hash::FxHasher; -pub use state::State; pub use tree::NodeId; pub mod layout_attributes; @@ -13,7 +12,6 @@ pub mod node; pub mod node_ref; mod passes; pub mod real_dom; -pub mod state; pub mod tree; pub mod utils; diff --git a/packages/native-core/src/node.rs b/packages/native-core/src/node.rs index 137221864..7eb0fb31e 100644 --- a/packages/native-core/src/node.rs +++ b/packages/native-core/src/node.rs @@ -1,17 +1,8 @@ -use crate::{state::State, tree::NodeId}; +use crate::tree::NodeId; use dioxus_core::{AnyValue, BorrowedAttributeValue, ElementId}; use rustc_hash::{FxHashMap, FxHashSet}; use std::fmt::Debug; -/// The node is stored client side and stores only basic data about the node. -#[derive(Debug, Clone)] -pub struct Node, V: FromAnyValue = ()> { - /// The transformed state of the node. - pub state: S, - /// The raw data for the node - pub node_data: NodeData, -} - #[derive(Debug, Clone)] pub struct NodeData { /// The id of the node @@ -38,21 +29,18 @@ pub enum NodeType { Placeholder, } -impl, V: FromAnyValue> Node { +impl NodeData { pub(crate) fn new(node_type: NodeType) -> Self { - Node { - state: S::default(), - node_data: NodeData { - element_id: None, - node_type, - node_id: NodeId(0), - }, + NodeData { + element_id: None, + node_type, + node_id: NodeId(0), } } /// get the mounted id of the node pub fn mounted_id(&self) -> Option { - self.node_data.element_id + self.element_id } } diff --git a/packages/native-core/src/node_ref.rs b/packages/native-core/src/node_ref.rs index 6530d8dd3..a62a97d24 100644 --- a/packages/native-core/src/node_ref.rs +++ b/packages/native-core/src/node_ref.rs @@ -1,11 +1,47 @@ +use std::cmp::Ordering; + use dioxus_core::ElementId; use crate::{ node::{ElementNode, FromAnyValue, NodeData, NodeType, OwnedAttributeView}, - state::union_ordered_iter, NodeId, }; +/// Join two sorted iterators +pub(crate) fn union_ordered_iter<'a>( + s_iter: impl Iterator, + o_iter: impl Iterator, + new_len_guess: usize, +) -> Vec { + let mut s_peekable = s_iter.peekable(); + let mut o_peekable = o_iter.peekable(); + let mut v = Vec::with_capacity(new_len_guess); + while let Some(s_i) = s_peekable.peek() { + while let Some(o_i) = o_peekable.peek() { + match o_i.cmp(s_i) { + Ordering::Greater => { + break; + } + Ordering::Less => { + v.push(o_peekable.next().unwrap().to_string()); + } + Ordering::Equal => { + o_peekable.next(); + break; + } + } + } + v.push(s_peekable.next().unwrap().to_string()); + } + for o_i in o_peekable { + v.push(o_i.to_string()); + } + for w in v.windows(2) { + debug_assert!(w[1] > w[0]); + } + v +} + /// A view into a [VNode] with limited access. #[derive(Debug)] pub struct NodeView<'a, V: FromAnyValue = ()> { diff --git a/packages/native-core/src/passes.rs b/packages/native-core/src/passes.rs index e89a95ebf..b6a173b2b 100644 --- a/packages/native-core/src/passes.rs +++ b/packages/native-core/src/passes.rs @@ -1,18 +1,115 @@ use anymap::AnyMap; +use parking_lot::RwLock; use rustc_hash::FxHashSet; -use std::any::{Any, TypeId}; +use std::any::{self, Any, TypeId}; use std::collections::BTreeMap; +use std::marker::PhantomData; use std::sync::Arc; -use crate::node::{FromAnyValue, Node}; +use crate::node::{FromAnyValue, NodeData}; use crate::node_ref::NodeView; -use crate::state::State; -use crate::tree::TreeViewMut; -use crate::tree::{Tree, TreeView}; +use crate::real_dom::RealDom; +use crate::tree::{Node, TreeStateView}; use crate::{FxDashMap, FxDashSet, SendAnyMap}; use crate::{NodeId, NodeMask}; -pub trait Pass: Any { +#[derive(Default)] +struct DirtyNodes { + passes_dirty: Vec, +} + +impl DirtyNodes { + pub fn add_node(&mut self, node_id: NodeId) { + let node_id = node_id.0; + let index = node_id / 64; + let bit = node_id % 64; + let encoded = 1 << bit; + if let Some(passes) = self.passes_dirty.get_mut(index) { + *passes |= encoded; + } else { + self.passes_dirty.resize(index + 1, 0); + self.passes_dirty[index] |= encoded; + } + } + + pub fn is_empty(&self) -> bool { + self.passes_dirty.iter().all(|dirty| *dirty == 0) + } + + pub fn pop(&mut self) -> Option { + let index = self.passes_dirty.iter().position(|dirty| *dirty != 0)?; + let passes = self.passes_dirty[index]; + let node_id = passes.trailing_zeros(); + let encoded = 1 << node_id; + self.passes_dirty[index] &= !encoded; + Some(NodeId((index * 64) + node_id as usize)) + } +} + +#[derive(Default, Clone)] +pub struct DirtyNodeStates { + dirty: Arc>>>, +} + +impl DirtyNodeStates { + pub fn insert(&self, pass_id: TypeId, node_id: NodeId, height: u16) { + let mut dirty = self.dirty.write(); + if let Some(dirty) = dirty.get_mut(&height) { + if let Some(mut entry) = dirty.get_mut(&pass_id) { + entry.add_node(node_id); + } else { + let mut entry = DirtyNodes::default(); + entry.add_node(node_id); + dirty.insert(pass_id, entry); + } + } else { + let mut entry = DirtyNodes::default(); + entry.add_node(node_id); + let hm = FxDashMap::default(); + hm.insert(pass_id, entry); + dirty.insert(height, hm); + } + } + + fn pop_front(&self, pass_id: TypeId) -> Option<(u16, NodeId)> { + let dirty_read = self.dirty.read(); + let (&height, values) = dirty_read + .iter() + .find(|(_, values)| values.contains_key(&pass_id))?; + let mut dirty = values.get_mut(&pass_id)?; + let node_id = dirty.pop()?; + if dirty.is_empty() { + values.remove(&pass_id); + } + if values.is_empty() { + let mut dirty_write = self.dirty.write(); + dirty_write.remove(&height); + } + + Some((height, node_id)) + } + + fn pop_back(&self, pass_id: TypeId) -> Option<(u16, NodeId)> { + let dirty_read = self.dirty.read(); + let (&height, values) = dirty_read + .iter() + .rev() + .find(|(_, values)| values.contains_key(&pass_id))?; + let mut dirty = values.get_mut(&pass_id)?; + let node_id = dirty.pop()?; + if dirty.is_empty() { + values.remove(&pass_id); + } + if values.is_empty() { + let mut dirty_write = self.dirty.write(); + dirty_write.remove(&height); + } + + Some((height, node_id)) + } +} + +pub trait Pass: Any { /// This is a tuple of (T: Any, ..) type ParentDependencies: Dependancy; /// This is a tuple of (T: Any, ..) @@ -26,23 +123,21 @@ pub trait Pass: Any { node_view: NodeView, node: ::ElementBorrowed<'a>, parent: Option<::ElementBorrowed<'a>>, - children: Option< - impl Iterator::ElementBorrowed<'a>>, - >, + children: Option::ElementBorrowed<'a>>>, context: &SendAnyMap, ) -> bool; fn validate() { // no type can be a child and parent dependency - for type_id in Self::parent_type_ids() { - for type_id2 in Self::child_type_ids() { + for type_id in Self::parent_type_ids().into_iter().copied() { + for type_id2 in Self::child_type_ids().into_iter().copied() { if type_id == type_id2 { panic!("type cannot be both a parent and child dependency"); } } } // this type should not be a node dependency - for type_id in Self::node_type_ids() { + for type_id in Self::node_type_ids().into_iter().copied() { if type_id == TypeId::of::() { panic!("The current type cannot be a node dependency"); } @@ -58,85 +153,74 @@ pub trait Pass: Any { } } - fn to_type_erased>() -> TypeErasedPass + fn to_type_erased() -> TypeErasedPass where Self: Sized, { Self::validate(); TypeErasedPass { this_type_id: TypeId::of::(), - combined_dependancy_type_ids: Self::all_dependanices().into_iter().collect(), + combined_dependancy_type_ids: Self::all_dependanices().into_iter().copied().collect(), parent_dependant: !Self::parent_type_ids().is_empty(), child_dependant: !Self::child_type_ids().is_empty(), dependants: FxHashSet::default(), mask: Self::NODE_MASK, pass_direction: Self::pass_direction(), pass: Box::new( - |node_id: NodeId, any_map: &mut Tree>, context: &SendAnyMap| { - let (current_node, parent, children) = any_map - .node_parent_children_mut(node_id) - .expect("tried to run pass on node that does not exist"); - let current_node_raw = current_node as *mut Node; - let node = Self::NodeDependencies::borrow_elements_from(¤t_node.state) - .expect("tried to get a pass that does not exist"); - let parent = parent.map(|parent| { - Self::ParentDependencies::borrow_elements_from(&parent.state) - .expect("tried to get a pass that does not exist") - }); - let children = children.map(|children| { - children.map(|child| { - Self::ChildDependencies::borrow_elements_from(&child.state) - .expect("tried to get a pass that does not exist") - }) - }); - // safety: we have varified the pass is valid in the is_valid function - let myself: &mut Self = unsafe { - (*current_node_raw) - .state - .get_mut() - .expect("tried to get a pass that does not exist") - }; + |node_id: NodeId, tree: &mut TreeStateView, context: &SendAnyMap| { + debug_assert!(!Self::NodeDependencies::type_ids() + .into_iter() + .any(|id| *id == TypeId::of::())); + // get all of the states from the tree view + // Safety: No node has itself as a parent or child. + let node_raw = tree.get_mut::(node_id).unwrap() as *mut Self; + let node_data = tree.get_single::>(node_id).unwrap(); + let node = tree.get::(node_id).unwrap(); + let children = tree.children::(node_id); + let parent = tree.parent::(node_id); + let myself = unsafe { &mut *node_raw }; + myself.pass( - NodeView::new(¤t_node.node_data, Self::NODE_MASK), + NodeView::new(&node_data, Self::NODE_MASK), node, parent, children, context, ) }, - ) - as Box>, &SendAnyMap) -> bool + Send + Sync>, + ) as PassCallback, + phantom: PhantomData, } } - fn parent_type_ids() -> Vec { + fn parent_type_ids() -> Box<[TypeId]> { Self::ParentDependencies::type_ids() } - fn child_type_ids() -> Vec { + fn child_type_ids() -> Box<[TypeId]> { Self::ChildDependencies::type_ids() } - fn node_type_ids() -> Vec { + fn node_type_ids() -> Box<[TypeId]> { Self::NodeDependencies::type_ids() } - fn all_dependanices() -> Vec { - let mut dependencies = Self::parent_type_ids(); - dependencies.extend(Self::child_type_ids()); - dependencies.extend(Self::node_type_ids()); - dependencies + fn all_dependanices() -> Box<[TypeId]> { + let mut dependencies = Self::parent_type_ids().to_vec(); + dependencies.extend(Self::child_type_ids().into_iter()); + dependencies.extend(Self::node_type_ids().into_iter()); + dependencies.into_boxed_slice() } fn pass_direction() -> PassDirection { if Self::child_type_ids() .into_iter() - .any(|type_id| type_id == TypeId::of::()) + .any(|type_id| *type_id == TypeId::of::()) { PassDirection::ChildToParent } else if Self::parent_type_ids() .into_iter() - .any(|type_id| type_id == TypeId::of::()) + .any(|type_id| *type_id == TypeId::of::()) { PassDirection::ParentToChild } else { @@ -145,63 +229,57 @@ pub trait Pass: Any { } } -pub struct TypeErasedPass, V: FromAnyValue = ()> { +pub struct TypeErasedPass { pub(crate) this_type_id: TypeId, pub(crate) parent_dependant: bool, pub(crate) child_dependant: bool, pub(crate) combined_dependancy_type_ids: FxHashSet, pub(crate) dependants: FxHashSet, pub(crate) mask: NodeMask, - pass: PassCallback, + pass: PassCallback, pub(crate) pass_direction: PassDirection, + phantom: PhantomData, } -impl, V: FromAnyValue> TypeErasedPass { +impl TypeErasedPass { fn resolve( &self, - tree: &mut Tree>, - mut dirty: DirtyNodes, - dirty_states: &DirtyNodeStates, + mut tree: TreeStateView, + dirty: &DirtyNodeStates, nodes_updated: &FxDashSet, ctx: &SendAnyMap, ) { match self.pass_direction { PassDirection::ParentToChild => { - while let Some(id) = dirty.pop_front() { - if (self.pass)(id, tree, ctx) { + while let Some((height, id)) = dirty.pop_front(self.this_type_id) { + if (self.pass)(id, &mut tree, ctx) { nodes_updated.insert(id); for id in tree.children_ids(id).unwrap() { for dependant in &self.dependants { - dirty_states.insert(*dependant, *id); + dirty.insert(*dependant, id, height + 1); } - - let height = tree.height(*id).unwrap(); - dirty.insert(height, *id); } } } } PassDirection::ChildToParent => { - while let Some(id) = dirty.pop_back() { - if (self.pass)(id, tree, ctx) { + while let Some((height, id)) = dirty.pop_back(self.this_type_id) { + if (self.pass)(id, &mut tree, ctx) { nodes_updated.insert(id); if let Some(id) = tree.parent_id(id) { for dependant in &self.dependants { - dirty_states.insert(*dependant, id); + dirty.insert(*dependant, id, height - 1); } - - let height = tree.height(id).unwrap(); - dirty.insert(height, id); } } } } PassDirection::AnyOrder => { - while let Some(id) = dirty.pop_back() { - if (self.pass)(id, tree, ctx) { + while let Some((height, id)) = dirty.pop_back(self.this_type_id) { + if (self.pass)(id, &mut tree, ctx) { nodes_updated.insert(id); for dependant in &self.dependants { - dirty_states.insert(*dependant, id); + dirty.insert(*dependant, id, height); } } } @@ -217,30 +295,20 @@ pub enum PassDirection { AnyOrder, } -type PassCallback = - Box>, &SendAnyMap) -> bool + Send + Sync>; +type PassCallback = Box bool + Send + Sync>; -pub trait AnyMapLike { - fn get(&self) -> Option<&T>; - fn get_mut(&mut self) -> Option<&mut T>; +pub trait AnyMapLike<'a> { + fn get(self) -> Option<&'a T>; } -impl AnyMapLike for AnyMap { - fn get(&self) -> Option<&T> { +impl<'a> AnyMapLike<'a> for &'a AnyMap { + fn get(self) -> Option<&'a T> { self.get() } - - fn get_mut(&mut self) -> Option<&mut T> { - self.get_mut() - } } -impl AnyMapLike for SendAnyMap { - fn get(&self) -> Option<&T> { - todo!() - } - - fn get_mut(&mut self) -> Option<&mut T> { +impl<'a> AnyMapLike<'a> for &'a SendAnyMap { + fn get(self) -> Option<&'a T> { todo!() } } @@ -250,8 +318,10 @@ pub trait Dependancy { where Self: 'a; - fn borrow_elements_from(map: &T) -> Option>; - fn type_ids() -> Vec; + fn borrow_elements_from<'a, T: AnyMapLike<'a> + Copy>( + map: T, + ) -> Option>; + fn type_ids() -> Box<[TypeId]>; } macro_rules! impl_dependancy { @@ -260,12 +330,12 @@ macro_rules! impl_dependancy { type ElementBorrowed<'a> = ($(&'a $t,)*) where Self: 'a; #[allow(unused_variables, clippy::unused_unit, non_snake_case)] - fn borrow_elements_from(map: &T) -> Option> { + fn borrow_elements_from<'a, T: AnyMapLike<'a> + Copy>(map: T) -> Option> { Some(($(map.get::<$t>()?,)*)) } - fn type_ids() -> Vec { - vec![$(TypeId::of::<$t>()),*] + fn type_ids() -> Box<[TypeId]> { + Box::new([$(TypeId::of::<$t>()),*]) } } }; @@ -289,96 +359,12 @@ impl_dependancy!(A, B, C, D, E, F, G, H, I, J, K, L, M, N); impl_dependancy!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O); impl_dependancy!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P); -#[derive(Debug, Clone, PartialEq, Eq, Default)] -pub struct DirtyNodes { - map: BTreeMap>, -} - -impl DirtyNodes { - fn add_node(&mut self, node_id: NodeId) { - let node_id = node_id.0; - let index = node_id / 64; - let bit = node_id % 64; - let encoded = 1 << bit; - if let Some(passes) = self.passes_dirty.get_mut(index) { - *passes |= encoded; - } else { - self.passes_dirty.resize(index + 1, 0); - self.passes_dirty[index] |= encoded; - } - } - - fn is_empty(&self) -> bool { - self.passes_dirty.iter().all(|dirty| *dirty == 0) - } - - fn pop(&mut self) -> Option { - let index = self.passes_dirty.iter().position(|dirty| *dirty != 0)?; - let passes = self.passes_dirty[index]; - let node_id = passes.trailing_zeros(); - let encoded = 1 << node_id; - self.passes_dirty[index] &= !encoded; - Some(NodeId((index * 64) + node_id as usize)) - } -} - -#[derive(Default)] -pub struct DirtyNodeStates { - dirty: FxDashMap>, -} - -impl DirtyNodeStates { - pub fn insert(&self, pass_id: TypeId, node_id: NodeId) { - if let Some(mut dirty) = self.dirty.get_mut(&node_id) { - dirty.insert(pass_id); - } else { - let mut v = FxHashSet::default(); - v.insert(pass_id); - self.dirty.insert(node_id, v); - } - } - - fn all_dirty(&self, pass_id: TypeId, dirty_nodes: &mut DirtyNodes, tree: &impl TreeView) { - for entry in self.dirty.iter() { - let node_id = entry.key(); - let dirty = entry.value(); - if dirty.contains(&pass_id) { - dirty_nodes.insert(tree.height(*node_id).unwrap(), *node_id); - } - } - if values.is_empty() { - self.dirty.remove(&height); - } - - Some((height, node_id)) - } - - fn pop_back(&mut self, pass_id: PassId) -> Option<(u16, NodeId)> { - let (&height, values) = self - .dirty - .iter_mut() - .rev() - .find(|(_, values)| values.contains_key(&pass_id))?; - let dirty = values.get_mut(&pass_id)?; - let node_id = dirty.pop()?; - if dirty.is_empty() { - values.remove(&pass_id); - } - if values.is_empty() { - self.dirty.remove(&height); - } - - Some((height, node_id)) - } -} - -pub fn resolve_passes + Send, V: FromAnyValue + Send>( - tree: &mut Tree>, +pub fn resolve_passes( + tree: &mut RealDom, dirty_nodes: DirtyNodeStates, - passes: &[TypeErasedPass], ctx: SendAnyMap, ) -> FxDashSet { - let dirty_states = Arc::new(dirty_nodes); + let passes = &tree.passes; let mut resolved_passes: FxHashSet = FxHashSet::default(); let mut resolving = Vec::new(); let nodes_updated = Arc::new(FxDashSet::default()); @@ -399,21 +385,15 @@ pub fn resolve_passes + Send, V: FromAnyValue + Send>( pass_indexes_remaining.remove(i); resolving.push(pass_id); currently_in_use.insert(pass.this_type_id); - // this is safe because each pass only has mutable access to the member associated with this_type_id and we have verified that the pass does not overlap with any other pass currently running - let tree_unbounded_mut = unsafe { &mut *(tree as *mut _) }; - let dirty_states = dirty_states.clone(); + let tree_view = tree.tree.state_views( + [pass.this_type_id], + pass.combined_dependancy_type_ids.iter().copied(), + ); + let dirty_nodes = dirty_nodes.clone(); let nodes_updated = nodes_updated.clone(); let ctx = ctx.clone(); s.spawn(move || { - let mut dirty = DirtyNodes::default(); - dirty_states.all_dirty(pass_id, &mut dirty, tree_unbounded_mut); - pass.resolve( - tree_unbounded_mut, - dirty, - &dirty_states, - &nodes_updated, - &ctx, - ); + pass.resolve(tree_view, &dirty_nodes, &nodes_updated, &ctx); }); } else { i += 1; diff --git a/packages/native-core/src/real_dom.rs b/packages/native-core/src/real_dom.rs index 9e7a909fb..4574d23c6 100644 --- a/packages/native-core/src/real_dom.rs +++ b/packages/native-core/src/real_dom.rs @@ -1,15 +1,14 @@ use dioxus_core::{BorrowedAttributeValue, ElementId, Mutations, TemplateNode}; +use parking_lot::{MappedRwLockReadGuard, MappedRwLockWriteGuard}; use rustc_hash::{FxHashMap, FxHashSet}; -use std::ops::{Index, IndexMut}; +use std::any::Any; use crate::node::{ - ElementNode, FromAnyValue, Node, NodeData, NodeType, OwnedAttributeDiscription, - OwnedAttributeValue, + ElementNode, FromAnyValue, 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, TreeViewMut}; +use crate::tree::{EntryBuilder, NodeId, Tree}; use crate::{FxDashSet, SendAnyMap}; /// A Dom that can sync with the VirtualDom mutations intended for use in lazy renderers. @@ -18,41 +17,36 @@ use crate::{FxDashSet, SendAnyMap}; /// /// # Custom values /// To allow custom values to be passed into attributes implement FromAnyValue on a type that can represent your custom value and specify the V generic to be that type. If you have many different custom values, it can be useful to use a enum type to represent the varients. -pub struct RealDom, V: FromAnyValue = ()> { - tree: Tree>, +pub struct RealDom { + pub(crate) tree: Tree, /// a map from element id to real node id node_id_mapping: Vec>, nodes_listening: FxHashMap>, stack: Vec, templates: FxHashMap>, - pub(crate) passes: Box<[TypeErasedPass]>, + pub(crate) passes: Box<[TypeErasedPass]>, pub(crate) nodes_updated: FxHashMap, passes_updated: DirtyNodeStates, parent_changed_nodes: FxHashSet, child_changed_nodes: FxHashSet, nodes_created: FxHashSet, + phantom: std::marker::PhantomData, } -impl, V: FromAnyValue> Default for RealDom { - fn default() -> Self { - Self::new() - } -} - -impl, V: FromAnyValue> RealDom { - pub fn new() -> RealDom { - let mut root = Node::new(NodeType::Element(ElementNode { +impl RealDom { + pub fn new(mut passes: Box<[TypeErasedPass]>) -> RealDom { + let tree = Tree::new(); + let root_id = tree.root(); + let root = tree.get_node(root_id); + let mut root_node: NodeData = NodeData::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 mut passes = S::create_passes(); + root_node.element_id = Some(ElementId(0)); + root_node.node_id = root_id; + root.insert(root_node); // resolve dependants for each pass for i in 1..passes.len() { @@ -83,6 +77,7 @@ impl, V: FromAnyValue> RealDom { parent_changed_nodes: FxHashSet::default(), child_changed_nodes: FxHashSet::default(), nodes_created: FxHashSet::default(), + phantom: std::marker::PhantomData, } } @@ -107,9 +102,9 @@ impl, V: FromAnyValue> RealDom { } fn set_element_id(&mut self, node_id: NodeId, element_id: ElementId) { - let node = self.tree.get_mut(node_id).unwrap(); - let node_id = node.node_data.node_id; - node.node_data.element_id = Some(element_id); + let mut node = self.tree.write::(node_id).unwrap(); + let node_id = node.node_id; + node.element_id = Some(element_id); if self.node_id_mapping.len() <= element_id.0 { self.node_id_mapping.resize(element_id.0 + 1, None); } @@ -124,14 +119,21 @@ impl, V: FromAnyValue> RealDom { current } - 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; + fn create_node( + &mut self, + mut node: NodeData, + id: Option, + mark_dirty: bool, + ) -> EntryBuilder<'_> { + let mut node_entry = self.tree.create_node(); + let node_id = node_entry.id(); + node.node_id = node_id; + node.element_id = id; + node_entry.insert(node); if mark_dirty { self.nodes_created.insert(node_id); } - node_id + node_entry } fn add_child(&mut self, node_id: NodeId, child_id: NodeId) { @@ -146,7 +148,7 @@ impl, V: FromAnyValue> RealDom { attrs, children, } => { - let node = Node::new(NodeType::Element(ElementNode { + let node = NodeData::new(NodeType::Element(ElementNode { tag: tag.to_string(), namespace: namespace.map(|s| s.to_string()), attributes: attrs @@ -169,22 +171,22 @@ impl, V: FromAnyValue> RealDom { .collect(), listeners: FxHashSet::default(), })); - let node_id = self.create_node(node, true); + let node_id = self.create_node(node, None, true).id(); 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.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) - } + TemplateNode::Text { text } => self + .create_node(NodeData::new(NodeType::Text(text.to_string())), None, true) + .id(), + TemplateNode::Dynamic { .. } => self + .create_node(NodeData::new(NodeType::Placeholder), None, true) + .id(), + TemplateNode::DynamicText { .. } => self + .create_node(NodeData::new(NodeType::Text(String::new())), None, true) + .id(), } } @@ -214,29 +216,26 @@ impl, V: FromAnyValue> RealDom { self.set_element_id(self.load_child(path), id); } CreatePlaceholder { id } => { - let node = Node::new(NodeType::Placeholder); - let node_id = self.create_node(node, true); + let node = NodeData::new(NodeType::Placeholder); + let node_id = self.create_node(node, None, true).id(); self.set_element_id(node_id, id); self.stack.push(node_id); } CreateTextNode { value, id } => { - 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); + let node_data = NodeData::new(NodeType::Text(value.to_string())); + let node_id = self.create_node(node_data, None, true).id(); + self.set_element_id(node_id, id); self.stack.push(node_id); } 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 { + let mut node = self.get_mut(node_id).unwrap(); + if let NodeTypeMut::Text(text) = node.node_type_mut() { *text = value.to_string(); } else { - node.node_data.node_type = NodeType::Text(value.to_string()); + node.set_type(NodeType::Text(value.to_string())); } - - self.mark_dirty(node_id, NodeMask::new().with_text()); } LoadTemplate { name, index, id } => { let template_id = self.templates[name][index]; @@ -350,15 +349,14 @@ impl, V: FromAnyValue> RealDom { /// Find all nodes that are listening for an event, sorted by there height in the dom progressing starting at the bottom and progressing up. /// This can be useful to avoid creating duplicate events. - pub fn get_listening_sorted(&self, event: &'static str) -> Vec<&Node> { + pub fn get_listening_sorted(&self, event: &'static str) -> Vec { if let Some(nodes) = self.nodes_listening.get(event) { - let mut listening: Vec<_> = nodes.iter().map(|id| self.get(*id).unwrap()).collect(); - listening.sort_by(|n1, n2| { - (self.tree.height(n1.node_data.node_id)) - .cmp(&self.tree.height(n2.node_data.node_id)) - .reverse() - }); - listening + let mut listening: Vec<_> = nodes + .iter() + .map(|id| (*id, self.tree.height(*id).unwrap())) + .collect(); + listening.sort_by(|(_, h1), (_, h2)| h1.cmp(h2).reverse()); + listening.into_iter().map(|(id, _)| id).collect() } else { Vec::new() } @@ -376,160 +374,94 @@ impl, V: FromAnyValue> RealDom { } fn clone_node(&mut self, node_id: NodeId) -> NodeId { - let node = self.tree.get(node_id).unwrap(); - let new_node = Node { - state: node.state.clone(), - node_data: node.node_data.clone(), - }; - let new_id = self.create_node(new_node, true); + let node = self.get(node_id).unwrap(); + let new_node = node.node_data().clone(); + let new_id = self.create_node(new_node, None, true).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); - self_mut.add_child(new_id, child_id); - } + let child_id = self.clone_node(child); + self.add_child(new_id, child_id); } new_id } + fn root(&self) -> NodeId { + self.tree.root() + } + + fn get(&self, id: NodeId) -> Option> { + self.tree.contains(id).then(|| NodeRef { id, dom: &self }) + } + pub fn get_mut(&mut self, id: NodeId) -> Option> { - self.tree.get_mut(id).map(|node| NodeMut { - node: &mut node.node_data, + self.tree.contains(id).then(|| NodeMut { + id, dirty: NodeMask::new(), - nodes_updated: &mut self.nodes_updated, + dom: self, }) } /// 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) + pub fn get_mut_raw(&mut self, id: NodeId) -> Option<&mut NodeData> { + self.tree.write(id) } -} -impl + Send, V: FromAnyValue + Send> 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 passes = &self.passes; let dirty_nodes = std::mem::take(&mut self.passes_updated); let nodes_updated = std::mem::take(&mut self.nodes_updated); for (&node, 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(node) { + if let Some(height) = self.tree.height(node) { for pass in &*self.passes { if mask.overlaps(&pass.mask) { - dirty_nodes.insert(pass.this_type_id, node); + dirty_nodes.insert(pass.this_type_id, node, height); } } } } for node in std::mem::take(&mut self.child_changed_nodes) { // remove any nodes that were created and then removed in the same mutations from the dirty nodes list - if self.tree.contains(node) { + if let Some(height) = self.tree.height(node) { for pass in &*self.passes { if pass.child_dependant { - dirty_nodes.insert(pass.this_type_id, node); + dirty_nodes.insert(pass.this_type_id, node, height); } } } } for node in std::mem::take(&mut self.parent_changed_nodes) { // remove any nodes that were created and then removed in the same mutations from the dirty nodes list - if self.tree.contains(node) { + if let Some(height) = self.tree.height(node) { for pass in &*self.passes { if pass.parent_dependant { - dirty_nodes.insert(pass.this_type_id, node); + dirty_nodes.insert(pass.this_type_id, node, height); } } } } for node in std::mem::take(&mut self.nodes_created) { // remove any nodes that were created and then removed in the same mutations from the dirty nodes list - if self.tree.contains(node) { + if let Some(height) = self.tree.height(node) { for pass in &*self.passes { - dirty_nodes.insert(pass.this_type_id, node); + dirty_nodes.insert(pass.this_type_id, node, height); } } } - let tree = &mut self.tree; - - ( - resolve_passes(tree, dirty_nodes, passes, ctx), - nodes_updated, - ) - } -} - -impl, V: FromAnyValue> TreeView> for RealDom { - type Iterator<'a> = > as TreeView>>::Iterator<'a>; - - fn root(&self) -> NodeId { - self.tree.root() + (resolve_passes(self, dirty_nodes, ctx), nodes_updated) } - 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, V: FromAnyValue> TreeLike> for RealDom { - fn create_node(&mut self, node: Node) -> NodeId { - let id = self.tree.create_node(node); - self.tree.get_mut(id).unwrap().node_data.node_id = id; - self.nodes_created.insert(id); - 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> { + fn remove(&mut self, id: NodeId) { 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); @@ -555,68 +487,108 @@ impl, V: FromAnyValue> TreeLike> for RealDom { } } -impl + Send, V: FromAnyValue> Index for RealDom { - type Output = Node; +// impl Index for RealDom { +// type Output = Node; - fn index(&self, id: ElementId) -> &Self::Output { - self.tree.get(self.element_to_node_id(id)).unwrap() +// fn index(&self, id: ElementId) -> &Self::Output { +// self.tree.get(self.element_to_node_id(id)).unwrap() +// } +// } + +// impl Index for RealDom { +// type Output = Node; + +// fn index(&self, idx: NodeId) -> &Self::Output { +// self.tree.get(idx).unwrap() +// } +// } + +// impl IndexMut for RealDom { +// fn index_mut(&mut self, id: ElementId) -> &mut Self::Output { +// self.tree.get_mut(self.element_to_node_id(id)).unwrap() +// } +// } + +// impl IndexMut for RealDom { +// fn index_mut(&mut self, idx: NodeId) -> &mut Self::Output { +// self.tree.get_mut(idx).unwrap() +// } +// } + +pub struct NodeRef<'a, V: FromAnyValue + Send = ()> { + id: NodeId, + dom: &'a RealDom, +} + +impl<'a, V: FromAnyValue + Send> NodeRef<'a, V> { + pub fn node_data(&self) -> &NodeData { + self.read().unwrap() } -} -impl + Send, V: FromAnyValue> Index for RealDom { - type Output = Node; - - fn index(&self, idx: NodeId) -> &Self::Output { - self.tree.get(idx).unwrap() - } -} - -impl + Send, V: FromAnyValue> IndexMut for RealDom { - fn index_mut(&mut self, id: ElementId) -> &mut Self::Output { - self.tree.get_mut(self.element_to_node_id(id)).unwrap() - } -} - -impl + Send, V: FromAnyValue> IndexMut for RealDom { - fn index_mut(&mut self, idx: NodeId) -> &mut Self::Output { - self.tree.get_mut(idx).unwrap() - } -} - -pub struct NodeMut<'a, V: FromAnyValue = ()> { - node: &'a mut NodeData, - dirty: NodeMask, - nodes_updated: &'a mut FxHashMap, -} - -impl<'a, V: FromAnyValue> NodeMut<'a, V> { pub fn node_type(&self) -> &NodeType { - &self.node.node_type + &self.node_data().node_type + } + + pub fn read(&self) -> Option<&T> { + self.dom.tree.read(self.id) + } +} + +pub struct NodeMut<'a, V: FromAnyValue + Send = ()> { + id: NodeId, + dom: &'a mut RealDom, + dirty: NodeMask, +} + +impl<'a, V: FromAnyValue + Send> NodeMut<'a, V> { + fn node_data(&self) -> &NodeData { + self.read().unwrap() + } + + fn node_data_mut(&mut self) -> &mut NodeData { + self.dom.tree.write(self.id).unwrap() + } + + pub fn node_type(&self) -> &NodeType { + &self.node_data().node_type } pub fn node_type_mut(&mut self) -> NodeTypeMut<'_, V> { - match &mut self.node.node_type { - NodeType::Element(element) => NodeTypeMut::Element(ElementNodeMut { - element, - dirty: &mut self.dirty, - }), + let Self { id, dom, dirty } = self; + let node_type = &mut dom.tree.write::>(*id).unwrap().node_type; + match node_type { + NodeType::Element(element) => NodeTypeMut::Element(ElementNodeMut { element, dirty }), NodeType::Text(text) => { - self.dirty.set_text(); + dirty.set_text(); NodeTypeMut::Text(text) } NodeType::Placeholder => NodeTypeMut::Placeholder, } } + + pub fn set_type(&mut self, new: NodeType) { + self.node_data_mut().node_type = new; + self.dirty = NodeMask::ALL; + } + + pub fn read(&self) -> Option<&T> { + self.dom.tree.read(self.id) + } + + pub fn write(&mut self) -> Option<&T> { + todo!("get_mut with mark as dirty") + } } -impl Drop for NodeMut<'_, V> { +impl Drop for NodeMut<'_, V> { fn drop(&mut self) { - let node_id = self.node.node_id; + let node_id = self.node_data().node_id; let mask = std::mem::take(&mut self.dirty); - if let Some(node) = self.nodes_updated.get_mut(&node_id) { + let nodes_updated = &mut self.dom.nodes_updated; + if let Some(node) = nodes_updated.get_mut(&node_id) { *node = node.union(&mask); } else { - self.nodes_updated.insert(node_id, mask); + nodes_updated.insert(node_id, mask); } } } diff --git a/packages/native-core/src/state.rs b/packages/native-core/src/state.rs deleted file mode 100644 index ef30a7fb6..000000000 --- a/packages/native-core/src/state.rs +++ /dev/null @@ -1,46 +0,0 @@ -use crate::{ - node::FromAnyValue, - passes::{AnyMapLike, TypeErasedPass}, -}; -use std::cmp::Ordering; - -/// Join two sorted iterators -pub(crate) fn union_ordered_iter<'a>( - s_iter: impl Iterator, - o_iter: impl Iterator, - new_len_guess: usize, -) -> Vec { - let mut s_peekable = s_iter.peekable(); - let mut o_peekable = o_iter.peekable(); - let mut v = Vec::with_capacity(new_len_guess); - while let Some(s_i) = s_peekable.peek() { - while let Some(o_i) = o_peekable.peek() { - match o_i.cmp(s_i) { - Ordering::Greater => { - break; - } - Ordering::Less => { - v.push(o_peekable.next().unwrap().to_string()); - } - Ordering::Equal => { - o_peekable.next(); - break; - } - } - } - v.push(s_peekable.next().unwrap().to_string()); - } - for o_i in o_peekable { - v.push(o_i.to_string()); - } - for w in v.windows(2) { - debug_assert!(w[1] > w[0]); - } - v -} - -/// Do not implement this trait. It is only meant to be derived and used through [crate::real_dom::RealDom]. -pub trait State: Default + Clone + AnyMapLike + 'static { - #[doc(hidden)] - fn create_passes() -> Box<[TypeErasedPass]>; -} diff --git a/packages/native-core/src/tree.rs b/packages/native-core/src/tree.rs index 26b89a580..a6ad60a9a 100644 --- a/packages/native-core/src/tree.rs +++ b/packages/native-core/src/tree.rs @@ -7,17 +7,19 @@ use std::collections::VecDeque; use std::fmt::Debug; use std::hash::BuildHasherDefault; -#[derive(PartialEq, Eq, Clone, Copy, Debug)] +use crate::{AnyMapLike, Dependancy}; + +#[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Debug, Hash)] pub struct NodeId(pub usize); #[derive(PartialEq, Eq, Clone, Debug)] -pub struct Node { +pub(crate) struct Node { parent: Option, children: Vec, height: u16, } -pub struct NodeView<'a> { +pub(crate) struct NodeView<'a> { tree: &'a Tree, id: NodeId, } @@ -27,25 +29,21 @@ impl NodeView<'_> { where T: Any, { - self.tree.nodes.get_slab_mut::().insert(self.id, data); + self.tree.nodes.write_slab::().insert(self.id, data); } - pub fn get(&self) -> MappedRwLockReadGuard<'_, T> + pub fn get(&self) -> &T where T: Any, { - MappedRwLockReadGuard::map(self.tree.nodes.get_slab::(), |slab| { - slab.get(self.id).unwrap() - }) + self.tree.nodes.read_slab::().get(self.id).unwrap() } - pub fn get_mut(&self) -> MappedRwLockWriteGuard<'_, T> + pub fn get_mut(&self) -> &mut T where T: Any, { - MappedRwLockWriteGuard::map(self.tree.nodes.get_slab_mut::(), |slab| { - slab.get_mut(self.id).unwrap() - }) + self.tree.nodes.write_slab::().get_mut(self.id).unwrap() } pub fn height(&self) -> u16 { @@ -66,7 +64,7 @@ impl NodeView<'_> { } #[derive(Debug)] -pub struct Tree { +pub(crate) struct Tree { nodes: AnySlab, root: NodeId, } @@ -84,20 +82,20 @@ impl Tree { Self { nodes, root } } - fn node_slab(&self) -> MappedRwLockReadGuard<'_, SlabStorage> { - self.nodes.get_slab() + fn node_slab(&self) -> &SlabStorage { + self.nodes.read_slab() } - pub fn get_node_data(&self, id: NodeId) -> MappedRwLockReadGuard<'_, Node> { - MappedRwLockReadGuard::map(self.node_slab(), |slab| slab.get(id).unwrap()) + pub fn get_node_data(&self, id: NodeId) -> &Node { + self.node_slab().get(id).unwrap() } - fn node_slab_mut(&self) -> MappedRwLockWriteGuard<'_, SlabStorage> { - self.nodes.get_slab_mut() + fn node_slab_mut(&self) -> &mut SlabStorage { + self.nodes.write_slab() } - pub fn get_node_data_mut(&self, id: NodeId) -> MappedRwLockWriteGuard<'_, Node> { - MappedRwLockWriteGuard::map(self.node_slab_mut(), |slab| slab.get_mut(id).unwrap()) + pub fn get_node_data_mut(&self, id: NodeId) -> &mut Node { + self.node_slab_mut().get_mut(id).unwrap() } pub fn remove(&mut self, id: NodeId) { @@ -131,7 +129,7 @@ impl Tree { } } - pub fn create_node(&mut self) -> Entry<'_> { + pub fn create_node(&mut self) -> EntryBuilder<'_> { let mut node = self.nodes.insert(); node.insert(Node { parent: None, @@ -206,7 +204,7 @@ impl Tree { self.set_height(new_id, height); } - pub fn insert(&mut self, id: NodeId, value: T) { + pub fn insert(&mut self, id: NodeId, value: T) { self.nodes.add(id, value); } @@ -214,42 +212,60 @@ impl Tree { self.nodes.len() } - pub fn state_view(&self) -> TreeStateView<'_, T> { + pub fn state_views( + &self, + immutable: impl IntoIterator, + mutable: impl IntoIterator, + ) -> TreeStateView<'_> { TreeStateView { nodes_data: self.node_slab(), - nodes: self.nodes.get_slab(), + nodes: immutable + .into_iter() + .map(|id| (id, MaybeRead::Read(self.nodes.data.get(&id).unwrap()))) + .chain( + mutable + .into_iter() + .map(|id| (id, MaybeRead::Write(self.nodes.data.get_mut(&id).unwrap()))), + ) + .collect(), root: self.root, } } - pub fn state_view_mut(&mut self) -> TreeStateViewMut<'_, T> { - TreeStateViewMut { - nodes_data: self.node_slab(), - nodes: self.nodes.get_slab_mut(), - root: self.root, - } + pub fn read(&self, id: NodeId) -> Option<&T> { + self.nodes.read_slab().get(id) } -} -impl NodeDataView for Tree { - fn root(&self) -> NodeId { + pub fn write(&mut self, id: NodeId) -> Option<&mut T> { + self.nodes.write_slab().get_mut(id) + } + + pub fn get_node(&self, id: NodeId) -> NodeView<'_> { + NodeView { tree: self, id } + } + + pub fn contains(&self, id: NodeId) -> bool { + self.nodes.contains(id) + } + + pub fn root(&self) -> NodeId { self.root } - fn parent_id(&self, id: NodeId) -> Option { + pub fn parent_id(&self, id: NodeId) -> Option { self.get_node_data(id).parent } - fn children_ids(&self, id: NodeId) -> Option> { + pub fn children_ids(&self, id: NodeId) -> Option> { Some(self.get_node_data(id).children.clone()) } - fn height(&self, id: NodeId) -> Option { + pub fn height(&self, id: NodeId) -> Option { Some(self.get_node_data(id).height) } } -pub trait NodeDataView { +pub(crate) trait NodeDataView { fn root(&self) -> NodeId; fn parent_id(&self, id: NodeId) -> Option; @@ -259,7 +275,7 @@ pub trait NodeDataView { fn height(&self, id: NodeId) -> Option; } -pub trait TreeView: Sized + NodeDataView { +trait TreeView: Sized + NodeDataView { fn get(&self, id: NodeId) -> Option<&T>; fn get_unchecked(&self, id: NodeId) -> &T { @@ -298,7 +314,7 @@ pub trait TreeView: Sized + NodeDataView { } } -pub trait TreeViewMut: Sized + TreeView { +trait TreeViewMut: Sized + TreeView { fn get_mut(&mut self, id: NodeId) -> Option<&mut T>; unsafe fn get_mut_unchecked(&mut self, id: NodeId) -> &mut T { @@ -357,175 +373,91 @@ pub trait TreeViewMut: Sized + TreeView { } } -pub trait TreeLike { - fn create_node(&mut self) -> Entry; - - fn add_child(&mut self, parent: NodeId, child: NodeId); - - fn remove(&mut self, id: NodeId); - - fn replace(&mut self, old: NodeId, new: NodeId); - - fn insert_before(&mut self, id: NodeId, new: NodeId); - - fn insert_after(&mut self, id: NodeId, new: NodeId); +enum MaybeRead<'a> { + Read(&'a Box), + Write(&'a mut Box), } -pub struct TreeStateView<'a, T> { - nodes_data: MappedRwLockReadGuard<'a, SlabStorage>, - nodes: MappedRwLockReadGuard<'a, SlabStorage>, +#[derive(Clone, Copy)] +struct TreeStateViewEntry<'a> { + view: &'a TreeStateView<'a>, + id: NodeId, +} + +impl<'a> AnyMapLike<'a> for TreeStateViewEntry<'a> { + fn get(self) -> Option<&'a T> { + self.view.get_slab().and_then(|slab| slab.get(self.id)) + } +} + +pub struct TreeStateView<'a> { + nodes_data: &'a SlabStorage, + nodes: hashbrown::HashMap, BuildHasherDefault>, root: NodeId, } -pub struct TreeStateViewMut<'a, T> { - nodes_data: MappedRwLockReadGuard<'a, SlabStorage>, - nodes: MappedRwLockWriteGuard<'a, SlabStorage>, - root: NodeId, -} +impl<'a> TreeStateView<'a> { + fn get_slab(&self) -> Option<&SlabStorage> { + self.nodes + .get(&TypeId::of::()) + .and_then(|gaurd| match gaurd { + MaybeRead::Read(gaurd) => gaurd.as_any().downcast_ref::>(), + MaybeRead::Write(gaurd) => gaurd.as_any().downcast_ref::>(), + }) + } + + fn get_slab_mut(&mut self) -> Option<&mut SlabStorage> { + self.nodes + .get_mut(&TypeId::of::()) + .and_then(|gaurd| match gaurd { + MaybeRead::Read(gaurd) => None, + MaybeRead::Write(gaurd) => gaurd.as_any_mut().downcast_mut::>(), + }) + } -impl<'a, T> NodeDataView for TreeStateView<'a, T> { fn root(&self) -> NodeId { self.root } - fn children_ids(&self, id: NodeId) -> Option> { + pub fn children_ids(&self, id: NodeId) -> Option> { self.nodes_data.get(id).map(|node| node.children.clone()) } - fn parent_id(&self, id: NodeId) -> Option { + pub fn parent_id(&self, id: NodeId) -> Option { self.nodes_data.get(id).and_then(|node| node.parent) } - fn height(&self, id: NodeId) -> Option { + pub fn height(&self, id: NodeId) -> Option { self.nodes_data.get(id).map(|n| n.height) } -} -impl<'a, T> TreeView for TreeStateView<'a, T> { - fn get(&self, id: NodeId) -> Option<&T> { - self.nodes.get(id) + pub fn get(&self, id: NodeId) -> Option> { + T::borrow_elements_from(self.entry(id)) } - fn children(&self, id: NodeId) -> Option> { + pub fn get_single(&self, id: NodeId) -> Option<&T> { + self.get_slab().and_then(|slab| slab.get(id)) + } + + pub fn get_mut(&mut self, id: NodeId) -> Option<&mut T> { + self.get_slab_mut().and_then(|slab| slab.get_mut(id)) + } + + fn entry(&self, id: NodeId) -> TreeStateViewEntry<'_> { + TreeStateViewEntry { view: self, id } + } + + pub fn children(&self, id: NodeId) -> Option>> { let ids = self.children_ids(id); - ids.map(|ids| ids.iter().map(|id| self.get_unchecked(*id)).collect()) - } - - fn parent(&self, id: NodeId) -> Option<&T> { - self.nodes_data - .get(id) - .and_then(|node| node.parent.map(|id| self.nodes.get(id).unwrap())) - } - - fn get_unchecked(&self, id: NodeId) -> &T { - unsafe { &self.nodes.get_unchecked(id) } - } -} - -impl<'a, T> NodeDataView for TreeStateViewMut<'a, T> { - fn root(&self) -> NodeId { - self.root - } - - fn children_ids(&self, id: NodeId) -> Option> { - self.nodes_data.get(id).map(|node| node.children.clone()) - } - - fn parent_id(&self, id: NodeId) -> Option { - self.nodes_data.get(id).and_then(|node| node.parent) - } - - fn height(&self, id: NodeId) -> Option { - self.nodes_data.get(id).map(|n| n.height) - } -} - -impl<'a, T> TreeView for TreeStateViewMut<'a, T> { - fn get(&self, id: NodeId) -> Option<&T> { - self.nodes.get(id) - } - - fn children(&self, id: NodeId) -> Option> { - let ids = self.children_ids(id); - ids.map(|ids| ids.iter().map(|id| self.get_unchecked(*id)).collect()) - } - fn parent(&self, id: NodeId) -> Option<&T> { - self.nodes_data - .get(id) - .and_then(|node| node.parent.map(|id| self.nodes.get(id).unwrap())) - } - - fn get_unchecked(&self, id: NodeId) -> &T { - unsafe { &self.nodes.get_unchecked(id) } - } -} - -impl<'a, T> TreeViewMut for TreeStateViewMut<'a, T> { - fn get_mut(&mut self, id: NodeId) -> Option<&mut T> { - self.nodes.get_mut(id) - } - - fn parent_mut(&mut self, id: NodeId) -> Option<&mut T> { - let parent_id = self.parent_id(id)?; - unsafe { Some(self.get_mut_unchecked(parent_id)) } - } - - fn children_mut(&mut self, id: NodeId) -> Option> { - // Safety: No node has itself as a parent. - if let Some(children_ids) = self.children_ids(id) { - let children_ids = children_ids.to_vec(); - unsafe { - self.nodes - .get_many_mut_unchecked(children_ids.into_iter().rev().map(|id| id)) - } - } else { - None - } - } - - unsafe fn get_mut_unchecked(&mut self, id: NodeId) -> &mut T { - unsafe { self.nodes.get_unchecked_mut(id) } - } - - 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, parent_id) - .map(|(node, parent)| (node, Some(parent))) - } else { - self.nodes.get_mut(id).map(|node| (node, None)) - } - } - - fn node_parent_children_mut( - &mut self, - id: NodeId, - ) -> Option<(&mut T, Option<&mut T>, Option>)> { - // 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) + ids.and_then(|ids| { + ids.iter() + .map(|id| T::borrow_elements_from(self.entry(*id))) + .collect() }) } - fn parent_child_mut(&mut self, id: NodeId) -> Option<(&mut T, Vec<&mut T>)> { - // Safety: No node will appear as a child twice - if let Some(children_ids) = self.children_ids(id) { - debug_assert!(!children_ids.iter().any(|child_id| *child_id == id)); - let mut borrowed = unsafe { - let as_vec = children_ids.to_vec(); - self.nodes - .get_many_mut_unchecked( - as_vec.into_iter().map(|id| id).chain(std::iter::once(id)), - ) - .unwrap() - }; - let node = borrowed.pop().unwrap(); - Some((node, borrowed)) - } else { - None - } + pub fn parent(&self, id: NodeId) -> Option> { + T::borrow_elements_from(self.entry(id)) } } @@ -727,7 +659,7 @@ fn get_node_children_mut() { } #[derive(Debug)] -struct SlabStorage { +pub(crate) struct SlabStorage { data: Vec>, } @@ -737,7 +669,7 @@ impl Default for SlabStorage { } } -trait AnySlabStorageImpl: Any { +trait AnySlabStorageImpl: Any + Send + Sync { fn remove(&mut self, id: NodeId); fn as_any(&self) -> &dyn Any; fn as_any_mut(&mut self) -> &mut dyn Any; @@ -806,7 +738,7 @@ impl SlabStorage { } } -impl AnySlabStorageImpl for SlabStorage { +impl AnySlabStorageImpl for SlabStorage { fn remove(&mut self, id: NodeId) { self.data[id.0].take(); } @@ -820,12 +752,9 @@ impl AnySlabStorageImpl for SlabStorage { } } -struct AnySlab { - data: hashbrown::HashMap< - TypeId, - RwLock>, - BuildHasherDefault, - >, +pub(crate) struct AnySlab { + data: hashbrown::HashMap, BuildHasherDefault>, + filled: Vec, free: VecDeque, len: usize, } @@ -850,80 +779,104 @@ impl AnySlab { fn new() -> Self { Self { data: Default::default(), + filled: Default::default(), free: VecDeque::new(), len: 0, } } - fn try_get_slab(&self) -> Option>> { + fn try_read_slab(&self) -> Option<&SlabStorage> { self.data .get(&TypeId::of::()) - .map(|x| RwLockReadGuard::map(x.read(), |x| x.as_any().downcast_ref().unwrap())) + .map(|x| x.as_any().downcast_ref().unwrap()) } - fn get_slab(&self) -> MappedRwLockReadGuard<'_, SlabStorage> { - self.try_get_slab().unwrap() + fn read_slab(&self) -> &SlabStorage { + self.try_read_slab().unwrap() } - fn try_get_slab_mut(&self) -> Option>> { + fn try_write_slab(&self) -> Option<&mut SlabStorage> { self.data .get(&TypeId::of::()) - .map(|x| RwLockWriteGuard::map(x.write(), |x| x.as_any_mut().downcast_mut().unwrap())) + .map(|x| x.as_any_mut().downcast_mut().unwrap()) } - fn get_slab_mut(&self) -> MappedRwLockWriteGuard<'_, SlabStorage> { - self.try_get_slab_mut().unwrap() + fn write_slab(&self) -> &mut SlabStorage { + self.try_write_slab().unwrap() } - fn get_or_insert_slab_mut(&mut self) -> MappedRwLockWriteGuard<'_, SlabStorage> { - RwLockWriteGuard::map( - self.data - .entry(TypeId::of::()) - .or_insert_with(|| RwLock::new(Box::new(SlabStorage::::default()))) - .write(), - |x| x.as_any_mut().downcast_mut().unwrap(), - ) + fn get_slab_mut_borrow(&mut self) -> &mut SlabStorage { + self.data + .get_mut(&TypeId::of::()) + .unwrap() + .as_any_mut() + .downcast_mut() + .unwrap() } - fn insert(&mut self) -> Entry<'_> { + fn get_or_insert_slab_mut(&mut self) -> &mut SlabStorage { + self.data + .entry(TypeId::of::()) + .or_insert_with(|| Box::new(SlabStorage::::default())) + .as_any_mut() + .downcast_mut() + .unwrap() + } + + fn insert(&mut self) -> EntryBuilder<'_> { let id = if let Some(id) = self.free.pop_front() { + self.filled[id.0] = true; id } else { let id = self.len; + self.filled.push(true); self.len += 1; NodeId(id) }; - Entry { id, inner: self } + EntryBuilder { id, inner: self } } - fn add(&mut self, id: NodeId, value: T) { + fn add(&mut self, id: NodeId, value: T) { self.get_or_insert_slab_mut().insert(id, value); } fn remove(&mut self, id: NodeId) { for slab in self.data.values_mut() { - slab.write().remove(id); + slab.remove(id); } + self.filled[id.0] = true; self.free.push_back(id); } fn len(&self) -> usize { self.len - self.free.len() } + + fn contains(&self, id: NodeId) -> bool { + self.filled.get(id.0).copied().unwrap_or_default() + } } -pub struct Entry<'a> { +pub struct EntryBuilder<'a> { id: NodeId, inner: &'a mut AnySlab, } -impl Entry<'_> { - pub fn insert(&mut self, value: T) { +impl EntryBuilder<'_> { + pub fn insert(&mut self, value: T) { self.inner .get_or_insert_slab_mut::() .insert(self.id, value); } + pub fn get(&self) -> Option<&T> { + self.inner.read_slab().get(self.id) + } + + pub fn get_mut(&mut self) -> Option<&mut T> { + self.inner.write_slab().get_mut(self.id) + } + pub fn remove(self) { self.inner.remove(self.id); } @@ -946,7 +899,7 @@ fn remove() { slab.remove(node1_id); - assert!(slab.get_slab::().get(node1_id).is_none()); + assert!(slab.read_slab::().get(node1_id).is_none()); assert_eq!(slab.len(), 1); } @@ -966,7 +919,7 @@ fn get_many_mut_unchecked() { println!("ids: {:#?}", [parent, child, grandchild]); { - let mut i32_slab = slab.get_slab_mut::(); + let mut i32_slab = slab.write_slab::(); let all = unsafe { i32_slab.get_many_mut_unchecked([parent, child, grandchild].into_iter()) } .unwrap(); @@ -974,7 +927,7 @@ fn get_many_mut_unchecked() { } { - let mut i32_slab = slab.get_slab_mut::(); + let mut i32_slab = slab.write_slab::(); assert!( unsafe { i32_slab.get_many_mut_unchecked([NodeId(3), NodeId(100)].into_iter()) } .is_none() @@ -1001,8 +954,8 @@ fn get_many_many_mut_unchecked() { println!("slab: {:#?}", slab); - let mut num_entries = slab.get_slab_mut::(); - let mut str_entries = slab.get_slab_mut::<&str>(); + let mut num_entries = slab.write_slab::(); + let mut str_entries = slab.write_slab::<&str>(); let all_num = unsafe { num_entries diff --git a/packages/native-core/src/utils/mod.rs b/packages/native-core/src/utils/mod.rs index 58e98b0fa..9ddb1a1c7 100644 --- a/packages/native-core/src/utils/mod.rs +++ b/packages/native-core/src/utils/mod.rs @@ -1,3 +1,3 @@ -mod persistant_iterator; -pub use persistant_iterator::*; +// mod persistant_iterator; +// pub use persistant_iterator::*; pub mod cursor; diff --git a/packages/native-core/src/utils/persistant_iterator.rs b/packages/native-core/src/utils/persistant_iterator.rs index 0ca13492e..f5423cb76 100644 --- a/packages/native-core/src/utils/persistant_iterator.rs +++ b/packages/native-core/src/utils/persistant_iterator.rs @@ -2,8 +2,6 @@ use crate::{ node::{ElementNode, FromAnyValue, NodeType}, passes::{AnyMapLike, TypeErasedPass}, real_dom::RealDom, - state::State, - tree::TreeView, NodeId, }; use dioxus_core::{Mutation, Mutations};