From e76cd63ee394574f04535433d46bc1872278a158 Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Fri, 30 Dec 2022 20:29:28 -0600 Subject: [PATCH] create new state system --- packages/native-core/src/lib.rs | 6 +- packages/native-core/src/passes.rs | 594 ++++++++++-------- packages/native-core/src/real_dom.rs | 48 +- packages/native-core/src/state.rs | 20 +- packages/native-core/src/tree.rs | 14 + .../src/utils/persistant_iterator.rs | 32 +- 6 files changed, 413 insertions(+), 301 deletions(-) diff --git a/packages/native-core/src/lib.rs b/packages/native-core/src/lib.rs index ae739af86..1a449ca07 100644 --- a/packages/native-core/src/lib.rs +++ b/packages/native-core/src/lib.rs @@ -1,16 +1,14 @@ use std::hash::BuildHasherDefault; pub use node_ref::NodeMask; -pub use passes::{ - AnyPass, DownwardPass, MemberMask, NodePass, Pass, PassId, PassReturn, UpwardPass, -}; +pub use passes::Pass; use rustc_hash::FxHasher; pub use tree::NodeId; pub mod layout_attributes; pub mod node; pub mod node_ref; -pub mod passes; +mod passes; pub mod real_dom; pub mod state; pub mod tree; diff --git a/packages/native-core/src/passes.rs b/packages/native-core/src/passes.rs index bdc7c7e5b..746cb6cc8 100644 --- a/packages/native-core/src/passes.rs +++ b/packages/native-core/src/passes.rs @@ -1,11 +1,308 @@ -use crate::tree::{NodeId, TreeView}; -use crate::{FxDashMap, FxDashSet, SendAnyMap}; -use rustc_hash::{FxHashMap, FxHashSet}; +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::{Tree, TreeView}; +use crate::{FxDashMap, FxDashSet, SendAnyMap}; +use crate::{NodeId, NodeMask}; + +pub trait Pass: Any { + /// This is a tuple of (T: Any, ..) + type ParentDependencies: Dependancy; + /// This is a tuple of (T: Any, ..) + type ChildDependencies: Dependancy; + /// This is a tuple of (T: Any, ..) + type NodeDependencies: Dependancy; + /// This is a tuple of (T: Any, ..) + type Ctx: Dependancy; + const MASK: NodeMask; + + 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; + + fn is_valid(&self) -> bool { + // 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() { + if type_id == type_id2 { + return false; + } + } + } + // this type should not be a node dependency + for type_id in Self::node_type_ids() { + if type_id == TypeId::of::() { + return false; + } + } + // no states have the same type id + if Self::all_dependanices() + .into_iter() + .collect::>() + .len() + != Self::all_dependanices().len() + { + return false; + } + true + } + + fn to_type_erased() -> TypeErasedPass + where + Self: Sized, + { + 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, + 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") + }; + let context = Self::Ctx::borrow_elements_from(context) + .expect("tried to get a pass that does not exist"); + myself.pass( + NodeView::new(¤t_node.node_data, Self::MASK), + node, + parent, + children, + context, + ) + }, + ) + as Box>, &SendAnyMap) -> bool + Send + Sync>, + } + } + + fn parent_type_ids() -> Vec { + Self::ParentDependencies::type_ids() + } + + fn child_type_ids() -> Vec { + Self::ChildDependencies::type_ids() + } + + fn node_type_ids() -> Vec { + 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 pass_direction() -> PassDirection { + if Self::child_type_ids() + .into_iter() + .any(|type_id| type_id == TypeId::of::()) + { + PassDirection::ChildToParent + } else if Self::parent_type_ids() + .into_iter() + .any(|type_id| type_id == TypeId::of::()) + { + PassDirection::ParentToChild + } else { + PassDirection::AnyOrder + } + } +} + +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) dependants: FxHashSet, + pub(crate) mask: NodeMask, + pass: PassCallback, + pass_direction: PassDirection, +} + +impl TypeErasedPass { + fn resolve( + &self, + tree: &mut Tree>, + mut dirty: DirtyNodes, + dirty_states: &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) { + nodes_updated.insert(id); + for id in tree.children_ids(id).unwrap() { + for dependant in &self.dependants { + dirty_states.insert(*dependant, *id); + } + + 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) { + nodes_updated.insert(id); + if let Some(id) = tree.parent_id(id) { + for dependant in &self.dependants { + dirty_states.insert(*dependant, id); + } + + 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) { + nodes_updated.insert(id); + for dependant in &self.dependants { + dirty_states.insert(*dependant, id); + } + } + } + } + } + } +} + +pub enum PassDirection { + ParentToChild, + ChildToParent, + AnyOrder, +} + +type PassCallback = Box>, &SendAnyMap) -> bool + Send + Sync>; + +pub trait AnyMapLike { + fn get(&self) -> Option<&T>; + fn get_mut(&mut self) -> Option<&mut T>; +} + +impl AnyMapLike for AnyMap { + fn get(&self) -> Option<&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> { + todo!() + } +} + +pub trait Dependancy { + type ElementBorrowed<'a> + where + Self: 'a; + + fn borrow_elements(&self) -> Self::ElementBorrowed<'_>; + fn borrow_elements_from(map: &T) -> Option>; + fn type_ids() -> Vec; +} + +macro_rules! impl_dependancy { + ($($t:ident),*) => { + impl< $($t: Any),* > Dependancy for ($($t,)*) { + type ElementBorrowed<'a> = ($(&'a $t,)*) where Self: 'a; + + #[allow(clippy::unused_unit, non_snake_case)] + fn borrow_elements<'a>(&'a self) -> Self::ElementBorrowed<'a> { + let ($($t,)*) = self; + ($($t,)*) + } + + #[allow(unused_variables, clippy::unused_unit, non_snake_case)] + fn borrow_elements_from(map: &T) -> Option> { + Some(($(map.get::<$t>()?,)*)) + } + + fn type_ids() -> Vec { + vec![$(TypeId::of::<$t>()),*] + } + } + }; +} + +impl_dependancy!(); +impl_dependancy!(A); +impl_dependancy!(A, B); +impl_dependancy!(A, B, C); +impl_dependancy!(A, B, C, D); +impl_dependancy!(A, B, C, D, E); +impl_dependancy!(A, B, C, D, E, F); +impl_dependancy!(A, B, C, D, E, F, G); +impl_dependancy!(A, B, C, D, E, F, G, H); +impl_dependancy!(A, B, C, D, E, F, G, H, I); +impl_dependancy!(A, B, C, D, E, F, G, H, I, J); +impl_dependancy!(A, B, C, D, E, F, G, H, I, J, K); +impl_dependancy!(A, B, C, D, E, F, G, H, I, J, K, L); +impl_dependancy!(A, B, C, D, E, F, G, H, I, J, K, L, M); +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>, @@ -57,11 +354,11 @@ fn dirty_nodes() { #[derive(Default)] pub struct DirtyNodeStates { - dirty: FxDashMap>, + dirty: FxDashMap>, } impl DirtyNodeStates { - pub fn new(starting_nodes: FxHashMap>) -> Self { + pub fn new(starting_nodes: FxHashMap>) -> Self { let this = Self::default(); for (node, nodes) in starting_nodes { for pass_id in nodes { @@ -71,290 +368,71 @@ impl DirtyNodeStates { this } - pub fn insert(&self, pass_id: PassId, node_id: NodeId) { - let pass_id = pass_id.0; - let index = pass_id / 64; - let bit = pass_id % 64; - let encoded = 1 << bit; - if let Some(dirty) = self.dirty.get(&node_id) { - if let Some(atomic) = dirty.get(index as usize) { - atomic.fetch_or(encoded, Ordering::Relaxed); - } else { - drop(dirty); - let mut write = self.dirty.get_mut(&node_id).unwrap(); - write.resize_with(index as usize + 1, || AtomicU64::new(0)); - write[index as usize].fetch_or(encoded, Ordering::Relaxed); - } + 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 = Vec::with_capacity(index as usize + 1); - v.resize_with(index as usize + 1, || AtomicU64::new(0)); - v[index as usize].fetch_or(encoded, Ordering::Relaxed); + let mut v = FxHashSet::default(); + v.insert(pass_id); self.dirty.insert(node_id, v); } } - fn all_dirty(&self, pass_id: PassId, dirty_nodes: &mut DirtyNodes, tree: &impl TreeView) { - let pass_id = pass_id.0; - let index = pass_id / 64; - let bit = pass_id % 64; - let encoded = 1 << bit; + 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 let Some(atomic) = dirty.get(index as usize) { - if atomic.load(Ordering::Relaxed) & encoded != 0 { - dirty_nodes.insert(tree.height(*node_id).unwrap(), *node_id); - } + if dirty.contains(&pass_id) { + dirty_nodes.insert(tree.height(*node_id).unwrap(), *node_id); } } } } -#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy, PartialOrd, Ord)] -pub struct PassId(pub u64); - -#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy, Default)] -pub struct MemberMask(pub u64); - -impl MemberMask { - pub fn overlaps(&self, other: Self) -> bool { - (*self & other).0 != 0 - } -} - -impl BitAndAssign for MemberMask { - fn bitand_assign(&mut self, rhs: Self) { - self.0 &= rhs.0; - } -} - -impl BitAnd for MemberMask { - type Output = Self; - - fn bitand(self, rhs: Self) -> Self::Output { - MemberMask(self.0 & rhs.0) - } -} - -impl BitOrAssign for MemberMask { - fn bitor_assign(&mut self, rhs: Self) { - self.0 |= rhs.0; - } -} - -impl BitOr for MemberMask { - type Output = Self; - - fn bitor(self, rhs: Self) -> Self::Output { - Self(self.0 | rhs.0) - } -} - -pub struct PassReturn { - pub progress: bool, - pub mark_dirty: bool, -} - -pub trait Pass { - fn pass_id(&self) -> PassId; - fn dependancies(&self) -> &'static [PassId]; - fn dependants(&self) -> &'static [PassId]; - fn mask(&self) -> MemberMask; -} - -pub trait UpwardPass: Pass { - fn pass<'a>( - &self, - node: &mut T, - children: &mut dyn Iterator, - ctx: &SendAnyMap, - ) -> PassReturn; -} - -fn resolve_upward_pass + ?Sized>( - tree: &mut impl TreeView, - pass: &P, - mut dirty: DirtyNodes, - dirty_states: &DirtyNodeStates, - nodes_updated: &FxDashSet, - ctx: &SendAnyMap, -) { - while let Some(id) = dirty.pop_back() { - let (node, mut children) = tree.parent_child_mut(id).unwrap(); - let result = pass.pass(node, &mut children, ctx); - drop(children); - if result.progress || result.mark_dirty { - nodes_updated.insert(id); - if let Some(id) = tree.parent_id(id) { - if result.mark_dirty { - for dependant in pass.dependants() { - dirty_states.insert(*dependant, id); - } - } - if result.progress { - let height = tree.height(id).unwrap(); - dirty.insert(height, id); - } - } - } - } -} - -pub trait DownwardPass: Pass { - fn pass(&self, node: &mut T, parent: Option<&mut T>, ctx: &SendAnyMap) -> PassReturn; -} - -fn resolve_downward_pass + ?Sized>( - tree: &mut impl TreeView, - pass: &P, - mut dirty: DirtyNodes, - dirty_states: &DirtyNodeStates, - nodes_updated: &FxDashSet, - ctx: &SendAnyMap, -) { - while let Some(id) = dirty.pop_front() { - let (node, parent) = tree.node_parent_mut(id).unwrap(); - let result = pass.pass(node, parent, ctx); - if result.mark_dirty { - nodes_updated.insert(id); - } - if result.mark_dirty || result.progress { - for id in tree.children_ids(id).unwrap() { - if result.mark_dirty { - for dependant in pass.dependants() { - dirty_states.insert(*dependant, *id); - } - } - if result.progress { - let height = tree.height(*id).unwrap(); - dirty.insert(height, *id); - } - } - } - } -} - -pub trait NodePass: Pass { - fn pass(&self, node: &mut T, ctx: &SendAnyMap) -> bool; -} - -fn resolve_node_pass + ?Sized>( - tree: &mut impl TreeView, - pass: &P, - mut dirty: DirtyNodes, - dirty_states: &DirtyNodeStates, - nodes_updated: &FxDashSet, - ctx: &SendAnyMap, -) { - while let Some(id) = dirty.pop_back() { - let node = tree.get_mut(id).unwrap(); - if pass.pass(node, ctx) { - nodes_updated.insert(id); - for dependant in pass.dependants() { - dirty_states.insert(*dependant, id); - } - } - } -} - -pub enum AnyPass { - Upward(&'static (dyn UpwardPass + Send + Sync + 'static)), - Downward(&'static (dyn DownwardPass + Send + Sync + 'static)), - Node(&'static (dyn NodePass + Send + Sync + 'static)), -} - -impl AnyPass { - pub fn pass_id(&self) -> PassId { - match self { - Self::Upward(pass) => pass.pass_id(), - Self::Downward(pass) => pass.pass_id(), - Self::Node(pass) => pass.pass_id(), - } - } - - pub fn dependancies(&self) -> &'static [PassId] { - match self { - Self::Upward(pass) => pass.dependancies(), - Self::Downward(pass) => pass.dependancies(), - Self::Node(pass) => pass.dependancies(), - } - } - - fn mask(&self) -> MemberMask { - match self { - Self::Upward(pass) => pass.mask(), - Self::Downward(pass) => pass.mask(), - Self::Node(pass) => pass.mask(), - } - } - - fn resolve( - &self, - tree: &mut impl TreeView, - dirty: DirtyNodes, - dirty_states: &DirtyNodeStates, - nodes_updated: &FxDashSet, - ctx: &SendAnyMap, - ) { - match self { - Self::Downward(pass) => { - resolve_downward_pass(tree, *pass, dirty, dirty_states, nodes_updated, ctx) - } - Self::Upward(pass) => { - resolve_upward_pass(tree, *pass, dirty, dirty_states, nodes_updated, ctx) - } - Self::Node(pass) => { - resolve_node_pass(tree, *pass, dirty, dirty_states, nodes_updated, ctx) - } - } - } -} - -struct RawPointer(*mut T); -unsafe impl Send for RawPointer {} -unsafe impl Sync for RawPointer {} - -pub fn resolve_passes>( - tree: &mut Tr, +pub fn resolve_passes( + tree: &mut Tree>, dirty_nodes: DirtyNodeStates, - mut passes: Vec<&AnyPass>, + mut passes: &[TypeErasedPass], ctx: SendAnyMap, ) -> FxDashSet { let dirty_states = Arc::new(dirty_nodes); - let mut resolved_passes: FxHashSet = FxHashSet::default(); + let mut resolved_passes: FxHashSet = FxHashSet::default(); let mut resolving = Vec::new(); let nodes_updated = Arc::new(FxDashSet::default()); let ctx = Arc::new(ctx); - while !passes.is_empty() { - let mut currently_borrowed = MemberMask::default(); + let mut pass_indexes_remaining: Vec<_> = (0..passes.len()).collect::>(); + while !pass_indexes_remaining.is_empty() { + let mut currently_in_use = FxHashSet::::default(); std::thread::scope(|s| { let mut i = 0; - while i < passes.len() { - let pass = &passes[i]; - let pass_id = pass.pass_id(); - let pass_mask = pass.mask(); + while i < pass_indexes_remaining.len() { + let passes_idx = pass_indexes_remaining[i]; + let pass = &passes[passes_idx]; + let pass_id = pass.this_type_id; + // check if the pass is ready to be run if pass - .dependancies() + .combined_dependancy_type_ids .iter() .all(|d| resolved_passes.contains(d) || *d == pass_id) - && !pass_mask.overlaps(currently_borrowed) { - let pass = passes.remove(i); + pass_indexes_remaining.remove(i); resolving.push(pass_id); - currently_borrowed |= pass_mask; - let tree_mut = tree as *mut _; - let raw_ptr = RawPointer(tree_mut); + currently_in_use.insert(pass.this_type_id); + // this is safe because the member_mask acts as a per-member mutex and we have verified that the pass does not overlap with any other pass + let tree_unbounded_mut = unsafe { &mut *(tree as *mut _) }; let dirty_states = dirty_states.clone(); let nodes_updated = nodes_updated.clone(); let ctx = ctx.clone(); - s.spawn(move || unsafe { - // let tree_mut: &mut Tr = &mut *raw_ptr.0; - let raw = raw_ptr; - // this is safe because the member_mask acts as a per-member mutex and we have verified that the pass does not overlap with any other pass - let tree_mut: &mut Tr = &mut *raw.0; + s.spawn(move || { let mut dirty = DirtyNodes::default(); - dirty_states.all_dirty(pass_id, &mut dirty, tree_mut); - pass.resolve(tree_mut, dirty, &dirty_states, &nodes_updated, &ctx); + dirty_states.all_dirty(pass_id, &mut dirty, tree_unbounded_mut); + pass.resolve( + tree_unbounded_mut, + dirty, + &dirty_states, + &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 00b9afb03..dba68d618 100644 --- a/packages/native-core/src/real_dom.rs +++ b/packages/native-core/src/real_dom.rs @@ -5,7 +5,7 @@ use std::ops::{Deref, DerefMut, Index, IndexMut}; use crate::node::{Node, NodeType, OwnedAttributeDiscription, OwnedAttributeValue}; use crate::node_ref::{AttributeMask, NodeMask}; -use crate::passes::DirtyNodeStates; +use crate::passes::{resolve_passes, DirtyNodeStates, TypeErasedPass}; use crate::state::State; use crate::tree::{NodeId, Tree, TreeLike, TreeView}; use crate::{FxDashSet, RealNodeId, SendAnyMap}; @@ -25,8 +25,7 @@ fn mark_dirty( /// A Dom that can sync with the VirtualDom mutations intended for use in lazy renderers. /// The render state passes from parent to children and or accumulates state from children to parents. /// To get started implement [crate::state::ParentDepState], [crate::state::NodeDepState], or [crate::state::ChildDepState] and call [RealDom::apply_mutations] to update the dom and [RealDom::update_state] to update the state of the nodes. -#[derive(Debug)] -pub struct RealDom { +pub struct RealDom { pub tree: Tree>, /// a map from element id to real node id node_id_mapping: Vec>, @@ -34,15 +33,29 @@ pub struct RealDom { stack: Vec, templates: FxHashMap>, root_initialized: bool, + pub(crate) passes: Box<[TypeErasedPass]>, } -impl Default for RealDom { +impl Debug for RealDom { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("RealDom") + .field("tree", &self.tree) + .field("node_id_mapping", &self.node_id_mapping) + .field("nodes_listening", &self.nodes_listening) + .field("stack", &self.stack) + .field("templates", &self.templates) + .field("root_initialized", &self.root_initialized) + .finish() + } +} + +impl Default for RealDom { fn default() -> Self { Self::new() } } -impl RealDom { +impl RealDom { pub fn new() -> RealDom { let mut root = Node::new(NodeType::Element { tag: "Root".to_string(), @@ -55,6 +68,8 @@ impl RealDom { let root_id = tree.root(); tree.get_mut(root_id).unwrap().node_data.node_id = root_id; + let passes = S::create_passes(); + RealDom { tree, node_id_mapping: vec![Some(root_id)], @@ -62,6 +77,7 @@ impl RealDom { stack: vec![root_id], templates: FxHashMap::default(), root_initialized: false, + passes, } } @@ -346,9 +362,9 @@ impl RealDom { 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) { - for (m, p) in S::MASKS.iter().zip(S::PASSES.iter()) { - if mask.overlaps(m) { - dirty_nodes.insert(p.pass_id(), n); + for pass in &*self.passes { + if mask.overlaps(&pass.mask) { + dirty_nodes.insert(pass.this_type_id, n); } } } @@ -363,7 +379,9 @@ impl RealDom { nodes_updated: DirtyNodeStates, ctx: SendAnyMap, ) -> FxDashSet { - S::update(nodes_updated, &mut self.tree, ctx) + let tree = &mut self.tree; + let passes = &self.passes; + resolve_passes(tree, nodes_updated, passes, ctx) } /// Find all nodes that are listening for an event, sorted by there height in the dom progressing starting at the bottom and progressing up. @@ -415,7 +433,7 @@ impl RealDom { } } -impl Deref for RealDom { +impl Deref for RealDom { type Target = Tree>; fn deref(&self) -> &Self::Target { @@ -423,13 +441,13 @@ impl Deref for RealDom { } } -impl DerefMut for RealDom { +impl DerefMut for RealDom { fn deref_mut(&mut self) -> &mut Self::Target { &mut self.tree } } -impl Index for RealDom { +impl Index for RealDom { type Output = Node; fn index(&self, id: ElementId) -> &Self::Output { @@ -437,7 +455,7 @@ impl Index for RealDom { } } -impl Index for RealDom { +impl Index for RealDom { type Output = Node; fn index(&self, idx: RealNodeId) -> &Self::Output { @@ -445,13 +463,13 @@ impl Index for RealDom { } } -impl IndexMut for RealDom { +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 { +impl IndexMut for RealDom { fn index_mut(&mut self, idx: RealNodeId) -> &mut Self::Output { self.tree.get_mut(idx).unwrap() } diff --git a/packages/native-core/src/state.rs b/packages/native-core/src/state.rs index 7e6c5266a..beabb54c2 100644 --- a/packages/native-core/src/state.rs +++ b/packages/native-core/src/state.rs @@ -2,8 +2,8 @@ use std::cmp::Ordering; use crate::node::Node; use crate::node_ref::{NodeMask, NodeView}; -use crate::passes::{resolve_passes, AnyPass, DirtyNodeStates}; -use crate::tree::TreeView; +use crate::passes::{resolve_passes, AnyMapLike, DirtyNodeStates, Pass, TypeErasedPass}; +use crate::tree::{Tree, TreeView}; use crate::{FxDashSet, RealNodeId, SendAnyMap}; /// Join two sorted iterators @@ -210,21 +210,9 @@ pub trait NodeDepState { } /// Do not implement this trait. It is only meant to be derived and used through [crate::real_dom::RealDom]. -pub trait State: Default + Clone + 'static { +pub trait State: Default + Clone + AnyMapLike + 'static { #[doc(hidden)] - const PASSES: &'static [AnyPass>]; - #[doc(hidden)] - const MASKS: &'static [NodeMask]; - - #[doc(hidden)] - fn update>>( - dirty: DirtyNodeStates, - tree: &mut T, - ctx: SendAnyMap, - ) -> FxDashSet { - let passes = Self::PASSES.iter().collect(); - resolve_passes(tree, dirty, passes, ctx) - } + fn create_passes() -> Box<[TypeErasedPass]>; } impl ChildDepState for () { diff --git a/packages/native-core/src/tree.rs b/packages/native-core/src/tree.rs index 0547fc3a9..0824e0b51 100644 --- a/packages/native-core/src/tree.rs +++ b/packages/native-core/src/tree.rs @@ -121,6 +121,19 @@ pub trait TreeView: Sized { } } + 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; @@ -824,6 +837,7 @@ fn map() { Self { value } } } + let mut tree = Tree::new(Value::new(1)); let parent = tree.root(); let child = tree.create_node(Value::new(0)); diff --git a/packages/native-core/src/utils/persistant_iterator.rs b/packages/native-core/src/utils/persistant_iterator.rs index 75bcf9064..6db60f086 100644 --- a/packages/native-core/src/utils/persistant_iterator.rs +++ b/packages/native-core/src/utils/persistant_iterator.rs @@ -1,4 +1,11 @@ -use crate::{node::NodeType, real_dom::RealDom, state::State, tree::TreeView, NodeId, RealNodeId}; +use crate::{ + node::NodeType, + passes::{AnyMapLike, TypeErasedPass}, + real_dom::RealDom, + state::State, + tree::TreeView, + NodeId, RealNodeId, +}; use dioxus_core::{Mutation, Mutations}; use std::fmt::Debug; @@ -67,7 +74,7 @@ impl PersistantElementIter { /// remove stale element refreneces /// returns true if the focused element is removed - pub fn prune(&mut self, mutations: &Mutations, rdom: &RealDom) -> bool { + pub fn prune(&mut self, mutations: &Mutations, rdom: &RealDom) -> bool { let mut changed = false; let ids_removed: Vec<_> = mutations .edits @@ -124,7 +131,7 @@ impl PersistantElementIter { } /// get the next element - pub fn next(&mut self, rdom: &RealDom) -> ElementProduced { + pub fn next(&mut self, rdom: &RealDom) -> ElementProduced { if self.stack.is_empty() { let id = NodeId(0); let new = (id, NodePosition::AtNode); @@ -160,9 +167,9 @@ impl PersistantElementIter { } /// get the previous element - pub fn prev(&mut self, rdom: &RealDom) -> ElementProduced { + pub fn prev(&mut self, rdom: &RealDom) -> ElementProduced { // recursively add the last child element to the stack - fn push_back( + fn push_back( stack: &mut smallvec::SmallVec<[(RealNodeId, NodePosition); 5]>, new_node: RealNodeId, rdom: &RealDom, @@ -228,10 +235,19 @@ impl PersistantElementIter { #[derive(Default, Clone, Debug)] struct Empty {} -impl State for Empty { - const PASSES: &'static [crate::AnyPass>] = &[]; +impl AnyMapLike for Empty { + fn get(&self) -> Option<&T> { + None + } - const MASKS: &'static [crate::NodeMask] = &[]; + fn get_mut(&mut self) -> Option<&mut T> { + None + } +} +impl State for Empty { + fn create_passes() -> Box<[TypeErasedPass]> { + Box::new([]) + } } #[test]