浏览代码

create new state system

Evan Almloff 2 年之前
父节点
当前提交
e76cd63ee3

+ 2 - 4
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;

+ 336 - 258
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: <Self::NodeDependencies as Dependancy>::ElementBorrowed<'a>,
+        parent: Option<<Self::ParentDependencies as Dependancy>::ElementBorrowed<'a>>,
+        children: Option<
+            impl Iterator<Item = <Self::ChildDependencies as Dependancy>::ElementBorrowed<'a>>,
+        >,
+        context: <Self::Ctx as Dependancy>::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::<Self>() {
+                return false;
+            }
+        }
+        // no states have the same type id
+        if Self::all_dependanices()
+            .into_iter()
+            .collect::<FxDashSet<_>>()
+            .len()
+            != Self::all_dependanices().len()
+        {
+            return false;
+        }
+        true
+    }
+
+    fn to_type_erased<T: AnyMapLike + State>() -> TypeErasedPass<T>
+    where
+        Self: Sized,
+    {
+        TypeErasedPass {
+            this_type_id: TypeId::of::<Self>(),
+            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<Node<T>>, 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<T>;
+                    let node = Self::NodeDependencies::borrow_elements_from(&current_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(&current_node.node_data, Self::MASK),
+                        node,
+                        parent,
+                        children,
+                        context,
+                    )
+                },
+            )
+                as Box<dyn Fn(NodeId, &mut Tree<Node<T>>, &SendAnyMap) -> bool + Send + Sync>,
+        }
+    }
+
+    fn parent_type_ids() -> Vec<TypeId> {
+        Self::ParentDependencies::type_ids()
+    }
+
+    fn child_type_ids() -> Vec<TypeId> {
+        Self::ChildDependencies::type_ids()
+    }
+
+    fn node_type_ids() -> Vec<TypeId> {
+        Self::NodeDependencies::type_ids()
+    }
+
+    fn all_dependanices() -> Vec<TypeId> {
+        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::<Self>())
+        {
+            PassDirection::ChildToParent
+        } else if Self::parent_type_ids()
+            .into_iter()
+            .any(|type_id| type_id == TypeId::of::<Self>())
+        {
+            PassDirection::ParentToChild
+        } else {
+            PassDirection::AnyOrder
+        }
+    }
+}
+
+pub struct TypeErasedPass<T: AnyMapLike + State> {
+    pub(crate) this_type_id: TypeId,
+    parent_type_ids: FxHashSet<TypeId>,
+    child_type_ids: FxHashSet<TypeId>,
+    node_type_ids: FxHashSet<TypeId>,
+    combined_dependancy_type_ids: FxHashSet<TypeId>,
+    pub(crate) dependants: FxHashSet<TypeId>,
+    pub(crate) mask: NodeMask,
+    pass: PassCallback<T>,
+    pass_direction: PassDirection,
+}
+
+impl<T: AnyMapLike + State> TypeErasedPass<T> {
+    fn resolve(
+        &self,
+        tree: &mut Tree<Node<T>>,
+        mut dirty: DirtyNodes,
+        dirty_states: &DirtyNodeStates,
+        nodes_updated: &FxDashSet<NodeId>,
+        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<T> = Box<dyn Fn(NodeId, &mut Tree<Node<T>>, &SendAnyMap) -> bool + Send + Sync>;
+
+pub trait AnyMapLike {
+    fn get<T: Any>(&self) -> Option<&T>;
+    fn get_mut<T: Any>(&mut self) -> Option<&mut T>;
+}
+
+impl AnyMapLike for AnyMap {
+    fn get<T: Any>(&self) -> Option<&T> {
+        self.get()
+    }
+
+    fn get_mut<T: Any>(&mut self) -> Option<&mut T> {
+        self.get_mut()
+    }
+}
+
+impl AnyMapLike for SendAnyMap {
+    fn get<T: Any>(&self) -> Option<&T> {
+        todo!()
+    }
+
+    fn get_mut<T: Any>(&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<T: AnyMapLike>(map: &T) -> Option<Self::ElementBorrowed<'_>>;
+    fn type_ids() -> Vec<TypeId>;
+}
+
+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<T: AnyMapLike>(map: &T) -> Option<Self::ElementBorrowed<'_>> {
+                Some(($(map.get::<$t>()?,)*))
+            }
+
+            fn type_ids() -> Vec<TypeId> {
+                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<u16, FxHashSet<NodeId>>,
@@ -57,11 +354,11 @@ fn dirty_nodes() {
 
 #[derive(Default)]
 pub struct DirtyNodeStates {
-    dirty: FxDashMap<NodeId, Vec<AtomicU64>>,
+    dirty: FxDashMap<NodeId, FxHashSet<TypeId>>,
 }
 
 impl DirtyNodeStates {
-    pub fn new(starting_nodes: FxHashMap<NodeId, FxHashSet<PassId>>) -> Self {
+    pub fn new(starting_nodes: FxHashMap<NodeId, FxHashSet<TypeId>>) -> 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<T>(&self, pass_id: PassId, dirty_nodes: &mut DirtyNodes, tree: &impl TreeView<T>) {
-        let pass_id = pass_id.0;
-        let index = pass_id / 64;
-        let bit = pass_id % 64;
-        let encoded = 1 << bit;
+    fn all_dirty<T>(&self, pass_id: TypeId, dirty_nodes: &mut DirtyNodes, tree: &impl TreeView<T>) {
         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);
-                }
-            }
-        }
-    }
-}
-
-#[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<T>: Pass {
-    fn pass<'a>(
-        &self,
-        node: &mut T,
-        children: &mut dyn Iterator<Item = &'a mut T>,
-        ctx: &SendAnyMap,
-    ) -> PassReturn;
-}
-
-fn resolve_upward_pass<T, P: UpwardPass<T> + ?Sized>(
-    tree: &mut impl TreeView<T>,
-    pass: &P,
-    mut dirty: DirtyNodes,
-    dirty_states: &DirtyNodeStates,
-    nodes_updated: &FxDashSet<NodeId>,
-    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);
-                }
+            if dirty.contains(&pass_id) {
+                dirty_nodes.insert(tree.height(*node_id).unwrap(), *node_id);
             }
         }
     }
 }
 
-pub trait DownwardPass<T>: Pass {
-    fn pass(&self, node: &mut T, parent: Option<&mut T>, ctx: &SendAnyMap) -> PassReturn;
-}
-
-fn resolve_downward_pass<T, P: DownwardPass<T> + ?Sized>(
-    tree: &mut impl TreeView<T>,
-    pass: &P,
-    mut dirty: DirtyNodes,
-    dirty_states: &DirtyNodeStates,
-    nodes_updated: &FxDashSet<NodeId>,
-    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<T>: Pass {
-    fn pass(&self, node: &mut T, ctx: &SendAnyMap) -> bool;
-}
-
-fn resolve_node_pass<T, P: NodePass<T> + ?Sized>(
-    tree: &mut impl TreeView<T>,
-    pass: &P,
-    mut dirty: DirtyNodes,
-    dirty_states: &DirtyNodeStates,
-    nodes_updated: &FxDashSet<NodeId>,
-    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<T: 'static> {
-    Upward(&'static (dyn UpwardPass<T> + Send + Sync + 'static)),
-    Downward(&'static (dyn DownwardPass<T> + Send + Sync + 'static)),
-    Node(&'static (dyn NodePass<T> + Send + Sync + 'static)),
-}
-
-impl<T> AnyPass<T> {
-    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<T>,
-        dirty: DirtyNodes,
-        dirty_states: &DirtyNodeStates,
-        nodes_updated: &FxDashSet<NodeId>,
-        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<T>(*mut T);
-unsafe impl<T> Send for RawPointer<T> {}
-unsafe impl<T> Sync for RawPointer<T> {}
-
-pub fn resolve_passes<T, Tr: TreeView<T>>(
-    tree: &mut Tr,
+pub fn resolve_passes<T: AnyMapLike + State + Send>(
+    tree: &mut Tree<Node<T>>,
     dirty_nodes: DirtyNodeStates,
-    mut passes: Vec<&AnyPass<T>>,
+    mut passes: &[TypeErasedPass<T>],
     ctx: SendAnyMap,
 ) -> FxDashSet<NodeId> {
     let dirty_states = Arc::new(dirty_nodes);
-    let mut resolved_passes: FxHashSet<PassId> = FxHashSet::default();
+    let mut resolved_passes: FxHashSet<TypeId> = 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::<Vec<_>>();
+    while !pass_indexes_remaining.is_empty() {
+        let mut currently_in_use = FxHashSet::<TypeId>::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;

+ 33 - 15
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<S: State> {
+pub struct RealDom<S: State + Send> {
     pub tree: Tree<Node<S>>,
     /// a map from element id to real node id
     node_id_mapping: Vec<Option<RealNodeId>>,
@@ -34,15 +33,29 @@ pub struct RealDom<S: State> {
     stack: Vec<RealNodeId>,
     templates: FxHashMap<String, Vec<RealNodeId>>,
     root_initialized: bool,
+    pub(crate) passes: Box<[TypeErasedPass<S>]>,
 }
 
-impl<S: State> Default for RealDom<S> {
+impl<S: State + Send + Debug> Debug for RealDom<S> {
+    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<S: State + Send> Default for RealDom<S> {
     fn default() -> Self {
         Self::new()
     }
 }
 
-impl<S: State> RealDom<S> {
+impl<S: State + Send> RealDom<S> {
     pub fn new() -> RealDom<S> {
         let mut root = Node::new(NodeType::Element {
             tag: "Root".to_string(),
@@ -55,6 +68,8 @@ impl<S: State> RealDom<S> {
         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<S: State> RealDom<S> {
             stack: vec![root_id],
             templates: FxHashMap::default(),
             root_initialized: false,
+            passes,
         }
     }
 
@@ -346,9 +362,9 @@ impl<S: State> RealDom<S> {
         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<S: State> RealDom<S> {
         nodes_updated: DirtyNodeStates,
         ctx: SendAnyMap,
     ) -> FxDashSet<RealNodeId> {
-        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<S: State> RealDom<S> {
     }
 }
 
-impl<S: State> Deref for RealDom<S> {
+impl<S: State + Send> Deref for RealDom<S> {
     type Target = Tree<Node<S>>;
 
     fn deref(&self) -> &Self::Target {
@@ -423,13 +441,13 @@ impl<S: State> Deref for RealDom<S> {
     }
 }
 
-impl<S: State> DerefMut for RealDom<S> {
+impl<S: State + Send> DerefMut for RealDom<S> {
     fn deref_mut(&mut self) -> &mut Self::Target {
         &mut self.tree
     }
 }
 
-impl<S: State> Index<ElementId> for RealDom<S> {
+impl<S: State + Send> Index<ElementId> for RealDom<S> {
     type Output = Node<S>;
 
     fn index(&self, id: ElementId) -> &Self::Output {
@@ -437,7 +455,7 @@ impl<S: State> Index<ElementId> for RealDom<S> {
     }
 }
 
-impl<S: State> Index<RealNodeId> for RealDom<S> {
+impl<S: State + Send> Index<RealNodeId> for RealDom<S> {
     type Output = Node<S>;
 
     fn index(&self, idx: RealNodeId) -> &Self::Output {
@@ -445,13 +463,13 @@ impl<S: State> Index<RealNodeId> for RealDom<S> {
     }
 }
 
-impl<S: State> IndexMut<ElementId> for RealDom<S> {
+impl<S: State + Send> IndexMut<ElementId> for RealDom<S> {
     fn index_mut(&mut self, id: ElementId) -> &mut Self::Output {
         self.tree.get_mut(self.element_to_node_id(id)).unwrap()
     }
 }
 
-impl<S: State> IndexMut<RealNodeId> for RealDom<S> {
+impl<S: State + Send> IndexMut<RealNodeId> for RealDom<S> {
     fn index_mut(&mut self, idx: RealNodeId) -> &mut Self::Output {
         self.tree.get_mut(idx).unwrap()
     }

+ 4 - 16
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<Node<Self>>];
-    #[doc(hidden)]
-    const MASKS: &'static [NodeMask];
-
-    #[doc(hidden)]
-    fn update<T: TreeView<Node<Self>>>(
-        dirty: DirtyNodeStates,
-        tree: &mut T,
-        ctx: SendAnyMap,
-    ) -> FxDashSet<RealNodeId> {
-        let passes = Self::PASSES.iter().collect();
-        resolve_passes(tree, dirty, passes, ctx)
-    }
+    fn create_passes() -> Box<[TypeErasedPass<Self>]>;
 }
 
 impl ChildDepState for () {

+ 14 - 0
packages/native-core/src/tree.rs

@@ -121,6 +121,19 @@ pub trait TreeView<T>: Sized {
         }
     }
 
+    fn node_parent_children_mut(
+        &mut self,
+        id: NodeId,
+    ) -> Option<(&mut T, Option<&mut T>, Option<Self::IteratorMut<'_>>)> {
+        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<NodeId>;
 
     fn height(&self, id: NodeId) -> Option<u16>;
@@ -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));

+ 24 - 8
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<S: State>(&mut self, mutations: &Mutations, rdom: &RealDom<S>) -> bool {
+    pub fn prune<S: State + Send>(&mut self, mutations: &Mutations, rdom: &RealDom<S>) -> bool {
         let mut changed = false;
         let ids_removed: Vec<_> = mutations
             .edits
@@ -124,7 +131,7 @@ impl PersistantElementIter {
     }
 
     /// get the next element
-    pub fn next<S: State>(&mut self, rdom: &RealDom<S>) -> ElementProduced {
+    pub fn next<S: State + Send>(&mut self, rdom: &RealDom<S>) -> 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<S: State>(&mut self, rdom: &RealDom<S>) -> ElementProduced {
+    pub fn prev<S: State + Send>(&mut self, rdom: &RealDom<S>) -> ElementProduced {
         // recursively add the last child element to the stack
-        fn push_back<S: State>(
+        fn push_back<S: State + Send>(
             stack: &mut smallvec::SmallVec<[(RealNodeId, NodePosition); 5]>,
             new_node: RealNodeId,
             rdom: &RealDom<S>,
@@ -228,10 +235,19 @@ impl PersistantElementIter {
 
 #[derive(Default, Clone, Debug)]
 struct Empty {}
-impl State for Empty {
-    const PASSES: &'static [crate::AnyPass<crate::node::Node<Self>>] = &[];
+impl AnyMapLike for Empty {
+    fn get<T: std::any::Any>(&self) -> Option<&T> {
+        None
+    }
 
-    const MASKS: &'static [crate::NodeMask] = &[];
+    fn get_mut<T: std::any::Any>(&mut self) -> Option<&mut T> {
+        None
+    }
+}
+impl State for Empty {
+    fn create_passes() -> Box<[TypeErasedPass<Self>]> {
+        Box::new([])
+    }
 }
 
 #[test]