Explorar o código

WIP: use shipyard ecs

Evan Almloff %!s(int64=2) %!d(string=hai) anos
pai
achega
b91e010ac7

+ 2 - 0
packages/native-core-macro/.gitignore

@@ -0,0 +1,2 @@
+/target
+Cargo.lock

+ 26 - 0
packages/native-core-macro/Cargo.toml

@@ -0,0 +1,26 @@
+[package]
+name = "dioxus-native-core-macro"
+version = "0.3.0"
+edition = "2021"
+description = "Build natively rendered apps with Dioxus"
+license = "MIT/Apache-2.0"
+repository = "https://github.com/DioxusLabs/dioxus/"
+homepage = "https://dioxuslabs.com"
+documentation = "https://dioxuslabs.com"
+keywords = ["dom", "ui", "gui", "react"]
+
+
+[lib]
+proc-macro = true
+
+# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
+[dependencies]
+syn = { version = "1.0.11", features = ["extra-traits", "full"] }
+quote = "1.0"
+
+[dev-dependencies]
+smallvec = "1.6"
+rustc-hash = "1.1.0"
+anymap = "0.12.1"
+dioxus = { path = "../dioxus" }
+dioxus-native-core = { path = "../native-core" }

+ 43 - 0
packages/native-core-macro/README.md

@@ -0,0 +1,43 @@
+# Dioxus Native Core Macro
+
+[![Crates.io][crates-badge]][crates-url]
+[![MIT licensed][mit-badge]][mit-url]
+[![Build Status][actions-badge]][actions-url]
+[![Discord chat][discord-badge]][discord-url]
+
+[crates-badge]: https://img.shields.io/crates/v/dioxus-native-core-macro.svg
+[crates-url]: https://crates.io/crates/dioxus-native-core-macro
+
+[mit-badge]: https://img.shields.io/badge/license-MIT-blue.svg
+[mit-url]: https://github.com/dioxuslabs/dioxus/blob/master/LICENSE
+
+[actions-badge]: https://github.com/dioxuslabs/dioxus/actions/workflows/main.yml/badge.svg
+[actions-url]: https://github.com/dioxuslabs/dioxus/actions?query=workflow%3ACI+branch%3Amaster
+
+[discord-badge]: https://img.shields.io/discord/899851952891002890.svg?logo=discord&style=flat-square
+[discord-url]: https://discord.gg/XgGxMSkvUM
+
+[Website](https://dioxuslabs.com) |
+[Guides](https://dioxuslabs.com/docs/0.3/guide/en/) |
+[API Docs](https://docs.rs/dioxus-native-core-macro/latest/dioxus_native_core_macro) |
+[Chat](https://discord.gg/XgGxMSkvUM)
+
+
+## Overview
+
+`dioxus-native-core-macro` provides a handful of macros used by native-core for native renderers like TUI, Blitz, and Freya to derive their state.
+
+
+## Contributing
+
+- Report issues on our [issue tracker](https://github.com/dioxuslabs/dioxus/issues).
+- Join the discord and ask questions!
+
+## License
+This project is licensed under the [MIT license].
+
+[mit license]: https://github.com/DioxusLabs/dioxus/blob/master/LICENSE-MIT
+
+Unless you explicitly state otherwise, any contribution intentionally submitted
+for inclusion in Dioxus by you shall be licensed as MIT without any additional
+terms or conditions.

+ 22 - 0
packages/native-core-macro/src/lib.rs

@@ -0,0 +1,22 @@
+extern crate proc_macro;
+
+mod sorted_slice;
+
+use proc_macro::TokenStream;
+use quote::{quote, ToTokens, __private::Span};
+use sorted_slice::StrSlice;
+use syn::parenthesized;
+use syn::parse::ParseBuffer;
+use syn::punctuated::Punctuated;
+use syn::{
+    self,
+    parse::{Parse, ParseStream, Result},
+    parse_macro_input, parse_quote, Error, Field, Ident, Token, Type,
+};
+
+/// A helper attribute for deriving `State` for a struct.
+#[proc_macro_attribute]
+pub fn my_attribute(_: TokenStream, input: TokenStream) -> TokenStream {
+    let impl_block: syn::ItemImpl = syn::parse(input).unwrap();
+    quote!(#impl_block).into()
+}

+ 3 - 1
packages/native-core/Cargo.toml

@@ -28,6 +28,8 @@ hashbrown = { version = "0.13.2", features = ["raw"] }
 lightningcss = "1.0.0-alpha.39"
 
 rayon = "1.6.1"
+shipyard = "0.6.2"
+
 
 [dev-dependencies]
 rand = "0.8.5"
@@ -37,4 +39,4 @@ dioxus-native-core = { path = ".", features = ["dioxus"] }
 
 [features]
 default = []
-dioxus = ["dioxus-core"]
+dioxus = ["dioxus-core"]

+ 17 - 9
packages/native-core/src/dioxus.rs

@@ -1,5 +1,6 @@
 use dioxus_core::{BorrowedAttributeValue, ElementId, Mutations, TemplateNode};
 use rustc_hash::{FxHashMap, FxHashSet};
+use shipyard::Component;
 
 use crate::{
     node::{
@@ -11,6 +12,9 @@ use crate::{
     NodeId, NodeMut, RealDom,
 };
 
+#[derive(Component)]
+struct ElementIdComponent(ElementId);
+
 pub struct DioxusState {
     templates: FxHashMap<String, Vec<NodeId>>,
     stack: Vec<NodeId>,
@@ -19,10 +23,9 @@ pub struct DioxusState {
 
 impl DioxusState {
     pub fn create(rdom: &mut RealDom) -> Self {
-        rdom.insert_slab::<ElementId>();
         let root_id = rdom.root_id();
         let mut root = rdom.get_mut(root_id).unwrap();
-        root.insert(ElementId(0));
+        root.insert(ElementIdComponent(ElementId(0)));
         Self {
             templates: FxHashMap::default(),
             stack: vec![root_id],
@@ -40,7 +43,7 @@ impl DioxusState {
 
     fn set_element_id(&mut self, mut node: NodeMut, element_id: ElementId) {
         let node_id = node.id();
-        node.insert(element_id);
+        node.insert(ElementIdComponent(element_id));
         if self.node_id_mapping.len() <= element_id.0 {
             self.node_id_mapping.resize(element_id.0 + 1, None);
         }
@@ -104,9 +107,11 @@ impl DioxusState {
                     let node = rdom.get_mut(node_id).unwrap();
                     self.set_element_id(node, id);
                     let mut node = rdom.get_mut(node_id).unwrap();
-                    if let NodeTypeMut::Text(text) = node.node_type_mut() {
-                        *text = value.to_string();
+                    let node_type_mut = node.node_type_mut();
+                    if let NodeTypeMut::Text(mut text) = node_type_mut {
+                        *text.text_mut() = value.to_string();
                     } else {
+                        drop(node_type_mut);
                         node.set_type(NodeType::Text(TextNode {
                             text: value.to_string(),
                             listeners: FxHashSet::default(),
@@ -161,7 +166,8 @@ impl DioxusState {
                 } => {
                     let node_id = self.element_to_node_id(id);
                     let mut node = rdom.get_mut(node_id).unwrap();
-                    if let NodeTypeMut::Element(element) = &mut node.node_type_mut() {
+                    let mut node_type_mut = node.node_type_mut();
+                    if let NodeTypeMut::Element(element) = &mut node_type_mut {
                         if let BorrowedAttributeValue::None = &value {
                             element.remove_attributes(&OwnedAttributeDiscription {
                                 name: name.to_string(),
@@ -181,8 +187,9 @@ impl DioxusState {
                 SetText { value, id } => {
                     let node_id = self.element_to_node_id(id);
                     let mut node = rdom.get_mut(node_id).unwrap();
-                    if let NodeTypeMut::Text(text) = node.node_type_mut() {
-                        *text = value.to_string();
+                    let node_type_mut = node.node_type_mut();
+                    if let NodeTypeMut::Text(mut text) = node_type_mut {
+                        *text.text_mut() = value.to_string();
                     }
                 }
                 NewEventListener { name, id } => {
@@ -260,7 +267,8 @@ fn create_template_node(rdom: &mut RealDom, node: &TemplateNode) -> NodeId {
 
 pub trait NodeImmutableDioxusExt<V: FromAnyValue + Send + Sync>: NodeImmutable<V> {
     fn mounted_id(&self) -> Option<ElementId> {
-        self.get().copied()
+        let id = self.get::<ElementIdComponent>();
+        id.map(|id| id.0)
     }
 }
 

+ 2 - 2
packages/native-core/src/lib.rs

@@ -6,7 +6,6 @@ pub use passes::AnyMapLike;
 pub use passes::{Dependancy, State, TypeErasedPass};
 pub use real_dom::{NodeMut, NodeRef, RealDom};
 use rustc_hash::FxHasher;
-pub use tree::NodeId;
 
 #[cfg(feature = "dioxus")]
 pub mod dioxus;
@@ -18,13 +17,14 @@ mod passes;
 pub mod real_dom;
 pub mod tree;
 pub mod utils;
+pub use shipyard::EntityId as NodeId;
 
 pub mod prelude {
     pub use crate::node::{ElementNode, FromAnyValue, NodeType, OwnedAttributeView, TextNode};
     pub use crate::node_ref::{AttributeMaskBuilder, NodeMaskBuilder, NodeView};
     pub use crate::passes::{Dependancy, State};
     pub use crate::real_dom::{NodeImmutable, NodeMut, NodeRef, RealDom};
-    pub use crate::tree::NodeId;
+    pub use crate::NodeId;
     pub use crate::SendAnyMap;
 }
 

+ 2 - 1
packages/native-core/src/node.rs

@@ -1,4 +1,5 @@
 use rustc_hash::{FxHashMap, FxHashSet};
+use shipyard::Component;
 use std::{any::Any, fmt::Debug};
 
 #[derive(Debug, Clone, Default)]
@@ -25,7 +26,7 @@ impl TextNode {
 }
 
 /// A type of node with data specific to the node type. The types are a subset of the [VNode] types.
-#[derive(Debug, Clone)]
+#[derive(Debug, Clone, Component)]
 pub enum NodeType<V: FromAnyValue = ()> {
     Text(TextNode),
     Element(ElementNode<V>),

+ 152 - 203
packages/native-core/src/passes.rs

@@ -1,17 +1,15 @@
 use anymap::AnyMap;
-use core::panic;
 use parking_lot::RwLock;
 use rustc_hash::{FxHashMap, FxHashSet};
+use shipyard::{Component, IntoBorrow, Unique, View, WorkloadSystem};
 use std::any::{Any, TypeId};
 use std::collections::BTreeMap;
 use std::marker::PhantomData;
 use std::sync::Arc;
 
-use crate::node::{FromAnyValue, NodeType};
+use crate::node::FromAnyValue;
 use crate::node_ref::{NodeMaskBuilder, NodeView};
-use crate::real_dom::RealDom;
-use crate::tree::{SlabEntry, Tree, TreeStateView};
-use crate::{FxDashSet, SendAnyMap};
+use crate::SendAnyMap;
 use crate::{NodeId, NodeMask};
 
 #[derive(Default)]
@@ -21,7 +19,7 @@ struct DirtyNodes {
 
 impl DirtyNodes {
     pub fn add_node(&mut self, node_id: NodeId) {
-        let node_id = node_id.0;
+        let node_id = node_id.uindex();
         let index = node_id / 64;
         let bit = node_id % 64;
         let encoded = 1 << bit;
@@ -37,17 +35,17 @@ impl DirtyNodes {
         self.passes_dirty.iter().all(|dirty| *dirty == 0)
     }
 
-    pub fn pop(&mut self) -> Option<NodeId> {
+    pub fn pop(&mut self) -> Option<usize> {
         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))
+        Some((index * 64) + node_id as usize)
     }
 }
 
-#[derive(Clone)]
+#[derive(Clone, Unique)]
 pub struct DirtyNodeStates {
     dirty: Arc<FxHashMap<TypeId, RwLock<BTreeMap<u16, DirtyNodes>>>>,
 }
@@ -76,7 +74,7 @@ impl DirtyNodeStates {
         }
     }
 
-    fn pop_front(&self, pass_id: TypeId) -> Option<(u16, NodeId)> {
+    fn pop_front(&self, pass_id: TypeId) -> Option<(u16, usize)> {
         let mut values = self.dirty.get(&pass_id)?.write();
         let mut value = values.first_entry()?;
         let height = *value.key();
@@ -89,7 +87,7 @@ impl DirtyNodeStates {
         Some((height, id))
     }
 
-    fn pop_back(&self, pass_id: TypeId) -> Option<(u16, NodeId)> {
+    fn pop_back(&self, pass_id: TypeId) -> Option<(u16, usize)> {
         let mut values = self.dirty.get(&pass_id)?.write();
         let mut value = values.last_entry()?;
         let height = *value.key();
@@ -110,6 +108,7 @@ pub trait State<V: FromAnyValue + Send + Sync = ()>: Any + Send + Sync {
     type ChildDependencies: Dependancy;
     /// This is a tuple of (T: Pass, ..) of states read from the node required to run this pass
     type NodeDependencies: Dependancy;
+    type CombinedDependencies: Dependancy;
     /// This is a mask of what aspects of the node are required to run this pass
     const NODE_MASK: NodeMaskBuilder<'static>;
 
@@ -131,47 +130,43 @@ pub trait State<V: FromAnyValue + Send + Sync = ()>: Any + Send + Sync {
         children: Option<Vec<<Self::ChildDependencies as Dependancy>::ElementBorrowed<'a>>>,
         context: &SendAnyMap,
     ) -> Self;
+}
 
-    fn validate() {
-        // this type should not be a node dependency
-        for type_id in Self::node_type_ids().iter().copied() {
-            if type_id == TypeId::of::<Self>() {
-                panic!("The current type cannot be a node dependency");
-            }
-        }
-        // this type cannot be both a parent and child dependency
-        assert!(
-            !(Self::parent_type_ids()
-                .iter()
-                .any(|type_id| *type_id == TypeId::of::<Self>())
-                && Self::child_type_ids()
-                    .iter()
-                    .any(|type_id| *type_id == TypeId::of::<Self>())),
-            "The current type cannot be a parent and child dependency"
-        );
-        // no states have the same type id
-        if Self::child_type_ids()
-            .iter()
-            .collect::<FxHashSet<_>>()
-            .len()
-            != Self::child_type_ids().len()
-            || Self::parent_type_ids()
-                .iter()
-                .collect::<FxHashSet<_>>()
-                .len()
-                != Self::parent_type_ids().len()
-            || Self::node_type_ids().iter().collect::<FxHashSet<_>>().len()
-                != Self::node_type_ids().len()
-        {
-            panic!("all states must have unique type ids");
-        }
-    }
+pub trait AnyState<V: FromAnyValue + Send + Sync = ()>: State<V> {
+    fn workload_system() -> WorkloadSystem;
+    //  Box::new(
+    //     move |node_id: NodeId, tree: &mut TreeStateView, context: &SendAnyMap| {
+    //         debug_assert!(!Self::NodeDependencies::type_ids()
+    //             .iter()
+    //             .any(|id| *id == TypeId::of::<Self>()));
+    //         // get all of the states from the tree view
+    //         // Safety: No node has itself as a parent or child.
+    //         let myself: SlabEntry<'static, Self> = unsafe {
+    //             std::mem::transmute(tree.get_slab_mut::<Self>().unwrap().entry(node_id))
+    //         };
+    //         let node_data = tree.get_single::<NodeType<V>>(node_id).unwrap();
+    //         let node = tree.get::<Self::NodeDependencies>(node_id).unwrap();
+    //         let children = tree.children::<Self::ChildDependencies>(node_id);
+    //         let parent = tree.parent::<Self::ParentDependencies>(node_id);
+
+    //         let view = NodeView::new(node_id, node_data, &node_mask);
+    //         if myself.value.is_none() {
+    //             *myself.value = Some(Self::create(view, node, parent, children, context));
+    //             true
+    //         } else {
+    //             myself
+    //                 .value
+    //                 .as_mut()
+    //                 .unwrap()
+    //                 .update(view, node, parent, children, context)
+    //         }
+    //     },
+    // ) as PassCallback
 
     fn to_type_erased() -> TypeErasedPass<V>
     where
         Self: Sized,
     {
-        Self::validate();
         let node_mask = Self::NODE_MASK.build();
         TypeErasedPass {
             this_type_id: TypeId::of::<Self>(),
@@ -181,35 +176,7 @@ pub trait State<V: FromAnyValue + Send + Sync = ()>: Any + Send + Sync {
             dependants: FxHashSet::default(),
             mask: node_mask.clone(),
             pass_direction: Self::pass_direction(),
-            pass: Box::new(
-                move |node_id: NodeId, tree: &mut TreeStateView, context: &SendAnyMap| {
-                    debug_assert!(!Self::NodeDependencies::type_ids()
-                        .iter()
-                        .any(|id| *id == TypeId::of::<Self>()));
-                    // get all of the states from the tree view
-                    // Safety: No node has itself as a parent or child.
-                    let myself: SlabEntry<'static, Self> = unsafe {
-                        std::mem::transmute(tree.get_slab_mut::<Self>().unwrap().entry(node_id))
-                    };
-                    let node_data = tree.get_single::<NodeType<V>>(node_id).unwrap();
-                    let node = tree.get::<Self::NodeDependencies>(node_id).unwrap();
-                    let children = tree.children::<Self::ChildDependencies>(node_id);
-                    let parent = tree.parent::<Self::ParentDependencies>(node_id);
-
-                    let view = NodeView::new(node_id, node_data, &node_mask);
-                    if myself.value.is_none() {
-                        *myself.value = Some(Self::create(view, node, parent, children, context));
-                        true
-                    } else {
-                        myself
-                            .value
-                            .as_mut()
-                            .unwrap()
-                            .update(view, node, parent, children, context)
-                    }
-                },
-            ) as PassCallback,
-            create: Box::new(|tree: &mut Tree| tree.insert_slab::<Self>()) as CreatePassCallback,
+            workload: Some(Self::workload_system()),
             phantom: PhantomData,
         }
     }
@@ -257,58 +224,57 @@ pub struct TypeErasedPass<V: FromAnyValue + Send = ()> {
     pub(crate) combined_dependancy_type_ids: FxHashSet<TypeId>,
     pub(crate) dependants: FxHashSet<TypeId>,
     pub(crate) mask: NodeMask,
-    pass: PassCallback,
-    pub(crate) create: CreatePassCallback,
+    pub(crate) workload: Option<WorkloadSystem>,
     pub(crate) pass_direction: PassDirection,
     phantom: PhantomData<V>,
 }
 
-impl<V: FromAnyValue + Send> TypeErasedPass<V> {
-    fn resolve(
-        &self,
-        mut tree: TreeStateView,
-        dirty: &DirtyNodeStates,
-        nodes_updated: &FxDashSet<NodeId>,
-        ctx: &SendAnyMap,
-    ) {
-        match self.pass_direction {
-            PassDirection::ParentToChild => {
-                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.insert(*dependant, *id, height + 1);
-                            }
-                        }
-                    }
-                }
-            }
-            PassDirection::ChildToParent => {
-                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.insert(*dependant, id, height - 1);
-                            }
-                        }
-                    }
-                }
-            }
-            PassDirection::AnyOrder => {
-                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.insert(*dependant, id, height);
-                        }
-                    }
-                }
-            }
-        }
-    }
-}
+// impl<V: FromAnyValue + Send> TypeErasedPass<V> {
+//     fn resolve(
+//         &self,
+//         mut tree: TreeStateView,
+//         dirty: &DirtyNodeStates,
+//         nodes_updated: &FxDashSet<NodeId>,
+//         ctx: &SendAnyMap,
+//     ) {
+//         match self.pass_direction {
+//             PassDirection::ParentToChild => {
+//                 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.insert(*dependant, *id, height + 1);
+//                             }
+//                         }
+//                     }
+//                 }
+//             }
+//             PassDirection::ChildToParent => {
+//                 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.insert(*dependant, id, height - 1);
+//                             }
+//                         }
+//                     }
+//                 }
+//             }
+//             PassDirection::AnyOrder => {
+//                 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.insert(*dependant, id, height);
+//                         }
+//                     }
+//                 }
+//             }
+//         }
+//     }
+// }
 
 #[derive(Debug)]
 pub enum PassDirection {
@@ -317,9 +283,6 @@ pub enum PassDirection {
     AnyOrder,
 }
 
-type PassCallback = Box<dyn Fn(NodeId, &mut TreeStateView, &SendAnyMap) -> bool + Send + Sync>;
-type CreatePassCallback = Box<dyn Fn(&mut Tree) + Send + Sync>;
-
 pub trait AnyMapLike<'a> {
     fn get<T: Any + Sync + Send>(self) -> Option<&'a T>;
 }
@@ -337,25 +300,17 @@ impl<'a> AnyMapLike<'a> for &'a SendAnyMap {
 }
 
 pub trait Dependancy {
-    type ElementBorrowed<'a>
-    where
-        Self: 'a;
+    type ElementBorrowed<'a>: IntoBorrow;
 
-    fn borrow_elements_from<'a, T: AnyMapLike<'a> + Copy>(
-        map: T,
-    ) -> Option<Self::ElementBorrowed<'a>>;
-    fn type_ids() -> Box<[TypeId]>;
+    fn type_ids() -> Box<[TypeId]> {
+        Box::new([])
+    }
 }
 
 macro_rules! impl_dependancy {
     ($($t:ident),*) => {
-        impl< $($t: Any + Send + Sync),* > Dependancy for ($($t,)*) {
-            type ElementBorrowed<'a> = ($(&'a $t,)*) where Self: 'a;
-
-            #[allow(unused_variables, clippy::unused_unit, non_snake_case)]
-            fn borrow_elements_from<'a, T: AnyMapLike<'a> + Copy>(map: T) -> Option<Self::ElementBorrowed<'a>> {
-                Some(($(map.get::<$t>()?,)*))
-            }
+        impl< $($t: Send + Sync + Component),* > Dependancy for ($($t,)*) {
+            type ElementBorrowed<'a> = ($(View<'a, $t>,)*);
 
             fn type_ids() -> Box<[TypeId]> {
                 Box::new([$(TypeId::of::<$t>()),*])
@@ -375,66 +330,60 @@ 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);
-
-pub fn resolve_passes<V: FromAnyValue + Send + Sync>(
-    dom: &mut RealDom<V>,
-    dirty_nodes: DirtyNodeStates,
-    ctx: SendAnyMap,
-    parallel: bool,
-) -> FxDashSet<NodeId> {
-    let passes = &dom.dirty_nodes.passes;
-    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);
-    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();
-        let dynamically_borrowed_tree = dom.tree.dynamically_borrowed();
-        rayon::in_place_scope(|s| {
-            let mut i = 0;
-            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.combined_dependancy_type_ids.iter().all(|d| {
-                    (resolved_passes.contains(d) || *d == pass_id) && !currently_in_use.contains(d)
-                }) {
-                    pass_indexes_remaining.remove(i);
-                    resolving.push(pass_id);
-                    currently_in_use.insert(pass.this_type_id);
-                    let tree_view = dynamically_borrowed_tree.view(
-                        pass.combined_dependancy_type_ids
-                            .iter()
-                            .filter(|id| **id != pass.this_type_id)
-                            .copied()
-                            .chain(std::iter::once(TypeId::of::<NodeType<V>>())),
-                        [pass.this_type_id],
-                    );
-                    let dirty_nodes = dirty_nodes.clone();
-                    let nodes_updated = nodes_updated.clone();
-                    let ctx = ctx.clone();
-                    if parallel {
-                        s.spawn(move |_| {
-                            pass.resolve(tree_view, &dirty_nodes, &nodes_updated, &ctx);
-                        });
-                    } else {
-                        pass.resolve(tree_view, &dirty_nodes, &nodes_updated, &ctx);
-                    }
-                } else {
-                    i += 1;
-                }
-            }
-        });
-        resolved_passes.extend(resolving.iter().copied());
-        resolving.clear()
-    }
-    std::sync::Arc::try_unwrap(nodes_updated).unwrap()
-}
+
+// pub fn resolve_passes<V: FromAnyValue + Send + Sync>(
+//     dom: &mut RealDom<V>,
+//     dirty_nodes: DirtyNodeStates,
+//     ctx: SendAnyMap,
+//     parallel: bool,
+// ) -> FxDashSet<NodeId> {
+//     let passes = &dom.dirty_nodes.passes;
+//     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);
+//     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();
+//         let dynamically_borrowed_tree = dom.tree.dynamically_borrowed();
+//         rayon::in_place_scope(|s| {
+//             let mut i = 0;
+//             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.combined_dependancy_type_ids.iter().all(|d| {
+//                     (resolved_passes.contains(d) || *d == pass_id) && !currently_in_use.contains(d)
+//                 }) {
+//                     pass_indexes_remaining.remove(i);
+//                     resolving.push(pass_id);
+//                     currently_in_use.insert(pass.this_type_id);
+//                     let tree_view = dynamically_borrowed_tree.view(
+//                         pass.combined_dependancy_type_ids
+//                             .iter()
+//                             .filter(|id| **id != pass.this_type_id)
+//                             .copied()
+//                             .chain(std::iter::once(TypeId::of::<NodeType<V>>())),
+//                         [pass.this_type_id],
+//                     );
+//                     let dirty_nodes = dirty_nodes.clone();
+//                     let nodes_updated = nodes_updated.clone();
+//                     let ctx = ctx.clone();
+//                     if parallel {
+//                         s.spawn(move |_| {
+//                             pass.resolve(tree_view, &dirty_nodes, &nodes_updated, &ctx);
+//                         });
+//                     } else {
+//                         pass.resolve(tree_view, &dirty_nodes, &nodes_updated, &ctx);
+//                     }
+//                 } else {
+//                     i += 1;
+//                 }
+//             }
+//         });
+//         resolved_passes.extend(resolving.iter().copied());
+//         resolving.clear()
+//     }
+//     std::sync::Arc::try_unwrap(nodes_updated).unwrap()
+// }

+ 219 - 79
packages/native-core/src/real_dom.rs

@@ -1,6 +1,13 @@
 use rustc_hash::{FxHashMap, FxHashSet};
-use std::any::{Any, TypeId};
+use shipyard::error::GetStorage;
+use shipyard::track::Untracked;
+use shipyard::{
+    Component, Get, IntoBorrow, ScheduledWorkload, System, Unique, View, ViewMut, Workload,
+    WorkloadSystem,
+};
+use std::any::TypeId;
 use std::collections::VecDeque;
+use std::ops::{Deref, DerefMut};
 use std::sync::{Arc, RwLock};
 
 use crate::node::{
@@ -8,11 +15,18 @@ use crate::node::{
 };
 use crate::node_ref::{NodeMask, NodeMaskBuilder};
 use crate::node_watcher::NodeWatcher;
-use crate::passes::{resolve_passes, DirtyNodeStates, TypeErasedPass};
+use crate::passes::{DirtyNodeStates, TypeErasedPass};
 use crate::prelude::AttributeMaskBuilder;
-use crate::tree::{NodeId, Tree};
+use crate::tree::Tree;
+use crate::NodeId;
 use crate::{FxDashSet, SendAnyMap};
 
+#[derive(Unique)]
+struct SendAnyMapWrapper(SendAnyMap);
+
+#[derive(Unique, Default)]
+struct DirtyNodes(FxDashSet<NodeId>);
+
 pub(crate) struct NodesDirty<V: FromAnyValue + Send + Sync> {
     passes_updated: FxHashMap<NodeId, FxHashSet<TypeId>>,
     nodes_updated: FxHashMap<NodeId, NodeMask>,
@@ -66,16 +80,19 @@ pub struct RealDom<V: FromAnyValue + Send + Sync = ()> {
     nodes_listening: FxHashMap<String, FxHashSet<NodeId>>,
     pub(crate) dirty_nodes: NodesDirty<V>,
     node_watchers: NodeWatchers<V>,
+    workload: ScheduledWorkload,
     phantom: std::marker::PhantomData<V>,
 }
 
 impl<V: FromAnyValue + Send + Sync> RealDom<V> {
     pub fn new(mut passes: Box<[TypeErasedPass<V>]>) -> RealDom<V> {
         let mut tree = Tree::new();
-        tree.insert_slab::<NodeType<V>>();
-        for pass in passes.iter() {
-            (pass.create)(&mut tree);
+        let mut workload = Workload::new("Main Workload");
+        for pass in &mut *passes {
+            let system = pass.workload.take().unwrap();
+            workload = workload.with_system(system);
         }
+        let (workload, _) = workload.build().unwrap();
         let root_id = tree.root();
         let root_node: NodeType<V> = NodeType::Element(ElementNode {
             tag: "Root".to_string(),
@@ -101,7 +118,6 @@ impl<V: FromAnyValue + Send + Sync> RealDom<V> {
         let mut passes_updated = FxHashMap::default();
         let mut nodes_updated = FxHashMap::default();
 
-        let root_id = NodeId(0);
         passes_updated.insert(root_id, passes.iter().map(|x| x.this_type_id).collect());
         nodes_updated.insert(root_id, NodeMaskBuilder::ALL.build());
 
@@ -114,6 +130,7 @@ impl<V: FromAnyValue + Send + Sync> RealDom<V> {
                 passes,
             },
             node_watchers: Default::default(),
+            workload,
             phantom: std::marker::PhantomData,
         }
     }
@@ -152,12 +169,6 @@ impl<V: FromAnyValue + Send + Sync> RealDom<V> {
         }
     }
 
-    /// Return the number of nodes in the dom.
-    pub fn size(&self) -> usize {
-        // The dom has a root node, ignore it.
-        self.tree.size() - 1
-    }
-
     /// Returns the id of the root node.
     pub fn root_id(&self) -> NodeId {
         self.tree.root()
@@ -171,16 +182,21 @@ impl<V: FromAnyValue + Send + Sync> RealDom<V> {
         self.tree.contains(id).then(|| NodeMut::new(id, 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_state_mut_raw<T: Any + Send + Sync>(&mut self, id: NodeId) -> Option<&mut T> {
-        self.tree.get_mut(id)
+    fn borrow_raw<'a, B: IntoBorrow>(&'a self) -> Result<B, GetStorage>
+    where
+        B::Borrow: shipyard::Borrow<'a, View = B>,
+    {
+        self.tree.nodes.borrow()
+    }
+
+    fn borrow_node_type_mut(&self) -> Result<ViewMut<NodeType<V>>, GetStorage> {
+        self.tree.nodes.borrow()
     }
 
     /// 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,
-        parallel: bool,
     ) -> (FxDashSet<NodeId>, FxHashMap<NodeId, NodeMask>) {
         let passes = std::mem::take(&mut self.dirty_nodes.passes_updated);
         let nodes_updated = std::mem::take(&mut self.dirty_nodes.nodes_updated);
@@ -195,10 +211,17 @@ impl<V: FromAnyValue + Send + Sync> RealDom<V> {
             }
         }
 
-        (
-            resolve_passes(self, dirty_nodes, ctx, parallel),
-            nodes_updated,
-        )
+        let _ = self.tree.remove_unique::<DirtyNodeStates>();
+        let _ = self.tree.remove_unique::<SendAnyMapWrapper>();
+        self.tree.add_unique(dirty_nodes);
+        self.tree.add_unique(SendAnyMapWrapper(ctx));
+        self.tree.add_unique(DirtyNodes::default());
+
+        self.workload.run_with_world(&self.tree.nodes).unwrap();
+
+        let dirty = self.tree.remove_unique::<DirtyNodes>().unwrap();
+
+        (dirty.0, nodes_updated)
     }
 
     pub fn traverse_depth_first(&self, mut f: impl FnMut(NodeRef<V>)) {
@@ -221,7 +244,7 @@ impl<V: FromAnyValue + Send + Sync> RealDom<V> {
                 f(node);
                 if let Some(children) = self.tree.children_ids(id) {
                     for id in children {
-                        queue.push_back(*id);
+                        queue.push_back(id);
                     }
                 }
             }
@@ -258,32 +281,74 @@ impl<V: FromAnyValue + Send + Sync> RealDom<V> {
         }
     }
 
-    pub fn insert_slab<T: Any + Send + Sync>(&mut self) {
-        self.tree.insert_slab::<T>();
-    }
-
     pub fn add_node_watcher(&mut self, watcher: impl NodeWatcher<V> + 'static + Send + Sync) {
         self.node_watchers.write().unwrap().push(Box::new(watcher));
     }
 }
 
+pub struct ViewEntry<'a, V: Component + Send + Sync> {
+    view: View<'a, V>,
+    id: NodeId,
+}
+
+impl<'a, V: Component + Send + Sync> ViewEntry<'a, V> {
+    fn new(view: View<'a, V>, id: NodeId) -> Self {
+        Self { view, id }
+    }
+}
+
+impl<'a, V: Component + Send + Sync> Deref for ViewEntry<'a, V> {
+    type Target = V;
+
+    fn deref(&self) -> &Self::Target {
+        &self.view[self.id]
+    }
+}
+
+pub struct ViewEntryMut<'a, V: Component<Tracking = Untracked> + Send + Sync> {
+    view: ViewMut<'a, V, Untracked>,
+    id: NodeId,
+}
+
+impl<'a, V: Component<Tracking = Untracked> + Send + Sync> ViewEntryMut<'a, V> {
+    fn new(view: ViewMut<'a, V, Untracked>, id: NodeId) -> Self {
+        Self { view, id }
+    }
+}
+
+impl<'a, V: Component<Tracking = Untracked> + Send + Sync> Deref for ViewEntryMut<'a, V> {
+    type Target = V;
+
+    fn deref(&self) -> &Self::Target {
+        self.view.get(self.id).unwrap()
+    }
+}
+
+impl<'a, V: Component<Tracking = Untracked> + Send + Sync> DerefMut for ViewEntryMut<'a, V> {
+    fn deref_mut(&mut self) -> &mut Self::Target {
+        (&mut self.view).get(self.id).unwrap()
+    }
+}
+
 pub trait NodeImmutable<V: FromAnyValue + Send + Sync>: Sized {
     fn real_dom(&self) -> &RealDom<V>;
 
     fn id(&self) -> NodeId;
 
     #[inline]
-    fn node_type(&self) -> &NodeType<V> {
+    fn node_type(&self) -> ViewEntry<NodeType<V>> {
         self.get().unwrap()
     }
 
     #[inline]
-    fn get<T: Any + Sync + Send>(&self) -> Option<&T> {
-        self.real_dom().tree.get(self.id())
+    fn get<'a, T: Component + Sync + Send>(&'a self) -> Option<ViewEntry<'a, T>> {
+        // self.real_dom().tree.get(self.id())
+        let view: View<'a, T> = self.real_dom().borrow_raw().ok()?;
+        Some(ViewEntry::new(view, self.id()))
     }
 
     #[inline]
-    fn child_ids(&self) -> Option<&[NodeId]> {
+    fn child_ids(&self) -> Option<Vec<NodeId>> {
         self.real_dom().tree.children_ids(self.id())
     }
 
@@ -413,7 +478,9 @@ impl<'a, V: FromAnyValue + Send + Sync> NodeMut<'a, V> {
     }
 
     #[inline]
-    pub fn get_mut<T: Any + Sync + Send>(&mut self) -> Option<&mut T> {
+    pub fn get_mut<T: Component<Tracking = Untracked> + Sync + Send>(
+        &mut self,
+    ) -> Option<ViewEntryMut<T>> {
         // mark the node state as dirty
         self.dom
             .dirty_nodes
@@ -421,11 +488,12 @@ impl<'a, V: FromAnyValue + Send + Sync> NodeMut<'a, V> {
             .entry(self.id)
             .or_default()
             .insert(TypeId::of::<T>());
-        self.dom.tree.get_mut(self.id)
+        let view_mut: ViewMut<T> = self.dom.borrow_raw().ok()?;
+        Some(ViewEntryMut::new(view_mut, self.id))
     }
 
     #[inline]
-    pub fn insert<T: Any + Sync + Send>(&mut self, value: T) {
+    pub fn insert<T: Component + Sync + Send>(&mut self, value: T) {
         // mark the node state as dirty
         self.dom
             .dirty_nodes
@@ -493,17 +561,20 @@ impl<'a, V: FromAnyValue + Send + Sync> NodeMut<'a, V> {
     #[inline]
     pub fn remove(&mut self) {
         let id = self.id();
-        if let NodeType::Element(ElementNode { listeners, .. })
-        | NodeType::Text(TextNode { listeners, .. }) =
-            self.dom.get_state_mut_raw::<NodeType<V>>(id).unwrap()
         {
-            let listeners = std::mem::take(listeners);
-            for event in listeners {
-                self.dom
-                    .nodes_listening
-                    .get_mut(&event)
-                    .unwrap()
-                    .remove(&id);
+            let RealDom {
+                tree,
+                nodes_listening,
+                ..
+            } = &mut self.dom;
+            let mut view: ViewMut<NodeType<V>> = tree.nodes.borrow().unwrap();
+            if let NodeType::Element(ElementNode { listeners, .. })
+            | NodeType::Text(TextNode { listeners, .. }) = (&mut view).get(id).unwrap()
+            {
+                let listeners = std::mem::take(listeners);
+                for event in listeners {
+                    nodes_listening.get_mut(&event).unwrap().remove(&id);
+                }
             }
         }
         self.mark_removed();
@@ -539,22 +610,27 @@ impl<'a, V: FromAnyValue + Send + Sync> NodeMut<'a, V> {
     #[inline]
     pub fn add_event_listener(&mut self, event: &str) {
         let id = self.id();
-        let node_type: &mut NodeType<V> = self.dom.tree.get_mut(self.id).unwrap();
+        let RealDom {
+            tree,
+            dirty_nodes,
+            nodes_listening,
+            ..
+        } = &mut self.dom;
+        let mut view: ViewMut<NodeType<V>> = tree.nodes.borrow().unwrap();
+        let node_type: &mut NodeType<V> = (&mut view).get(self.id).unwrap();
         if let NodeType::Element(ElementNode { listeners, .. })
         | NodeType::Text(TextNode { listeners, .. }) = node_type
         {
-            self.dom
-                .dirty_nodes
-                .mark_dirty(self.id, NodeMaskBuilder::new().with_listeners().build());
+            dirty_nodes.mark_dirty(self.id, NodeMaskBuilder::new().with_listeners().build());
             listeners.insert(event.to_string());
-            match self.dom.nodes_listening.get_mut(event) {
+            match nodes_listening.get_mut(event) {
                 Some(hs) => {
                     hs.insert(id);
                 }
                 None => {
                     let mut hs = FxHashSet::default();
                     hs.insert(id);
-                    self.dom.nodes_listening.insert(event.to_string(), hs);
+                    nodes_listening.insert(event.to_string(), hs);
                 }
             }
         }
@@ -563,16 +639,21 @@ impl<'a, V: FromAnyValue + Send + Sync> NodeMut<'a, V> {
     #[inline]
     pub fn remove_event_listener(&mut self, event: &str) {
         let id = self.id();
-        let node_type: &mut NodeType<V> = self.dom.tree.get_mut(self.id).unwrap();
+        let RealDom {
+            tree,
+            dirty_nodes,
+            nodes_listening,
+            ..
+        } = &mut self.dom;
+        let mut view: ViewMut<NodeType<V>> = tree.nodes.borrow().unwrap();
+        let node_type: &mut NodeType<V> = (&mut view).get(self.id).unwrap();
         if let NodeType::Element(ElementNode { listeners, .. })
         | NodeType::Text(TextNode { listeners, .. }) = node_type
         {
-            self.dom
-                .dirty_nodes
-                .mark_dirty(self.id, NodeMaskBuilder::new().with_listeners().build());
+            dirty_nodes.mark_dirty(self.id, NodeMaskBuilder::new().with_listeners().build());
             listeners.remove(event);
 
-            self.dom.nodes_listening.get_mut(event).unwrap().remove(&id);
+            nodes_listening.get_mut(event).unwrap().remove(&id);
         }
     }
 
@@ -591,28 +672,32 @@ impl<'a, V: FromAnyValue + Send + Sync> NodeMut<'a, V> {
     }
 
     pub fn node_type_mut(&mut self) -> NodeTypeMut<'_, V> {
-        let Self { id, dom } = self;
+        let id = self.id();
         let RealDom {
-            dirty_nodes, tree, ..
-        } = dom;
-        let node_type = tree.get_mut(*id).unwrap();
-        match node_type {
-            NodeType::Element(element) => NodeTypeMut::Element(ElementNodeMut {
-                id: *id,
-                element,
+            tree, dirty_nodes, ..
+        } = &mut self.dom;
+        let view: ViewMut<NodeType<V>> = tree.nodes.borrow().unwrap();
+        let node_type = ViewEntryMut::new(view, id);
+        match &*node_type {
+            NodeType::Element(_) => NodeTypeMut::Element(ElementNodeMut {
+                id,
+                element: node_type,
+                dirty_nodes,
+            }),
+            NodeType::Text(_) => NodeTypeMut::Text(TextNodeMut {
+                id,
+                text: node_type,
                 dirty_nodes,
             }),
-            NodeType::Text(text) => {
-                dirty_nodes.mark_dirty(self.id, NodeMaskBuilder::new().with_text().build());
-
-                NodeTypeMut::Text(&mut text.text)
-            }
             NodeType::Placeholder => NodeTypeMut::Placeholder,
         }
     }
 
     pub fn set_type(&mut self, new: NodeType<V>) {
-        *self.dom.tree.get_mut::<NodeType<V>>(self.id).unwrap() = new;
+        {
+            let mut view: ViewMut<NodeType<V>> = self.dom.borrow_node_type_mut().unwrap();
+            *(&mut view).get(self.id).unwrap() = new;
+        }
         self.dom
             .dirty_nodes
             .mark_dirty(self.id, NodeMaskBuilder::ALL.build())
@@ -638,39 +723,94 @@ impl<'a, V: FromAnyValue + Send + Sync> NodeMut<'a, V> {
 
 pub enum NodeTypeMut<'a, V: FromAnyValue + Send + Sync = ()> {
     Element(ElementNodeMut<'a, V>),
-    Text(&'a mut String),
+    Text(TextNodeMut<'a, V>),
     Placeholder,
 }
 
+pub struct TextNodeMut<'a, V: FromAnyValue + Send + Sync = ()> {
+    id: NodeId,
+    text: ViewEntryMut<'a, NodeType<V>>,
+    dirty_nodes: &'a mut NodesDirty<V>,
+}
+
+impl<V: FromAnyValue + Send + Sync> TextNodeMut<'_, V> {
+    pub fn text(&self) -> &str {
+        match &*self.text {
+            NodeType::Text(text) => &text.text,
+            _ => unreachable!(),
+        }
+    }
+
+    pub fn text_mut(&mut self) -> &mut String {
+        self.dirty_nodes
+            .mark_dirty(self.id, NodeMaskBuilder::new().with_text().build());
+        match &mut *self.text {
+            NodeType::Text(text) => &mut text.text,
+            _ => unreachable!(),
+        }
+    }
+}
+
+impl<V: FromAnyValue + Send + Sync> Deref for TextNodeMut<'_, V> {
+    type Target = String;
+
+    fn deref(&self) -> &Self::Target {
+        match &*self.text {
+            NodeType::Text(text) => &text.text,
+            _ => unreachable!(),
+        }
+    }
+}
+
+impl<V: FromAnyValue + Send + Sync> DerefMut for TextNodeMut<'_, V> {
+    fn deref_mut(&mut self) -> &mut Self::Target {
+        self.text_mut()
+    }
+}
+
 pub struct ElementNodeMut<'a, V: FromAnyValue + Send + Sync = ()> {
     id: NodeId,
-    element: &'a mut ElementNode<V>,
+    element: ViewEntryMut<'a, NodeType<V>>,
     dirty_nodes: &'a mut NodesDirty<V>,
 }
 
 impl<V: FromAnyValue + Send + Sync> ElementNodeMut<'_, V> {
+    fn element(&self) -> &ElementNode<V> {
+        match &*self.element {
+            NodeType::Element(element) => element,
+            _ => unreachable!(),
+        }
+    }
+
+    fn element_mut(&mut self) -> &mut ElementNode<V> {
+        match &mut *self.element {
+            NodeType::Element(element) => element,
+            _ => unreachable!(),
+        }
+    }
+
     pub fn tag(&self) -> &str {
-        &self.element.tag
+        &self.element().tag
     }
 
     pub fn tag_mut(&mut self) -> &mut String {
         self.dirty_nodes
             .mark_dirty(self.id, NodeMaskBuilder::new().with_tag().build());
-        &mut self.element.tag
+        &mut self.element_mut().tag
     }
 
     pub fn namespace(&self) -> Option<&str> {
-        self.element.namespace.as_deref()
+        self.element().namespace.as_deref()
     }
 
     pub fn namespace_mut(&mut self) -> &mut Option<String> {
         self.dirty_nodes
             .mark_dirty(self.id, NodeMaskBuilder::new().with_namespace().build());
-        &mut self.element.namespace
+        &mut self.element_mut().namespace
     }
 
     pub fn attributes(&self) -> &FxHashMap<OwnedAttributeDiscription, OwnedAttributeValue<V>> {
-        &self.element.attributes
+        &self.element().attributes
     }
 
     pub fn set_attribute(
@@ -684,7 +824,7 @@ impl<V: FromAnyValue + Send + Sync> ElementNodeMut<'_, V> {
                 .with_attrs(AttributeMaskBuilder::Some(&[&name.name]))
                 .build(),
         );
-        self.element.attributes.insert(name, value)
+        self.element_mut().attributes.insert(name, value)
     }
 
     pub fn remove_attributes(
@@ -697,7 +837,7 @@ impl<V: FromAnyValue + Send + Sync> ElementNodeMut<'_, V> {
                 .with_attrs(AttributeMaskBuilder::Some(&[&name.name]))
                 .build(),
         );
-        self.element.attributes.remove(name)
+        self.element_mut().attributes.remove(name)
     }
 
     pub fn get_attribute_mut(
@@ -710,10 +850,10 @@ impl<V: FromAnyValue + Send + Sync> ElementNodeMut<'_, V> {
                 .with_attrs(AttributeMaskBuilder::Some(&[&name.name]))
                 .build(),
         );
-        self.element.attributes.get_mut(name)
+        self.element_mut().attributes.get_mut(name)
     }
 
     pub fn listeners(&self) -> &FxHashSet<String> {
-        &self.element.listeners
+        &self.element().listeners
     }
 }

+ 72 - 436
packages/native-core/src/tree.rs

@@ -1,16 +1,8 @@
-use parking_lot::{MappedRwLockReadGuard, RwLock, RwLockReadGuard, RwLockWriteGuard};
-use rustc_hash::{FxHashMap, FxHasher};
-use std::any::{Any, TypeId};
-use std::collections::VecDeque;
+use crate::NodeId;
+use shipyard::{Component, EntitiesView, EntityId, Get, Unique, View, ViewMut, World};
 use std::fmt::Debug;
-use std::hash::BuildHasherDefault;
 
-use crate::{AnyMapLike, Dependancy};
-
-#[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Debug, Hash)]
-pub struct NodeId(pub usize);
-
-#[derive(PartialEq, Eq, Clone, Debug)]
+#[derive(PartialEq, Eq, Clone, Debug, Component)]
 pub(crate) struct Node {
     parent: Option<NodeId>,
     children: Vec<NodeId>,
@@ -19,60 +11,55 @@ pub(crate) struct Node {
 
 #[derive(Debug)]
 pub(crate) struct Tree {
-    nodes: AnySlab,
+    pub(crate) nodes: World,
     root: NodeId,
 }
 
 impl Tree {
     pub fn new() -> Self {
-        let mut nodes = AnySlab::default();
-        let mut node = nodes.insert();
-        node.insert(Node {
+        let mut nodes = World::default();
+        let node = Node {
             parent: None,
             children: Vec::new(),
             height: 0,
-        });
-        let root = node.id();
+        };
+        let root = nodes.add_entity((node,));
         Self { nodes, root }
     }
 
-    pub(crate) fn insert_slab<T: Any + Send + Sync>(&mut self) {
-        self.nodes.get_or_insert_slab_mut::<T>();
-    }
-
-    fn node_slab(&self) -> &SlabStorage<Node> {
-        self.nodes.read_slab()
+    pub fn add_unique<T: Unique + Send + Sync>(&mut self, data: T) {
+        self.nodes.add_unique(data);
     }
 
-    pub fn get_node_data(&self, id: NodeId) -> &Node {
-        self.node_slab().get(id).unwrap()
+    pub fn remove_unique<T: Unique + Send + Sync>(
+        &mut self,
+    ) -> Result<T, shipyard::error::UniqueRemove> {
+        self.nodes.remove_unique::<T>()
     }
 
-    pub fn try_get_node_data(&self, id: NodeId) -> Option<&Node> {
-        self.node_slab().get(id)
+    fn node_data(&self) -> View<Node> {
+        self.nodes.borrow().unwrap()
     }
 
-    fn node_slab_mut(&mut self) -> &mut SlabStorage<Node> {
-        self.nodes.write_slab()
-    }
-
-    pub fn get_node_data_mut(&mut self, id: NodeId) -> &mut Node {
-        self.node_slab_mut().get_mut(id).unwrap()
+    fn node_data_mut(&self) -> ViewMut<Node> {
+        self.nodes.borrow().unwrap()
     }
 
     pub fn remove(&mut self, id: NodeId) {
         fn recurse(tree: &mut Tree, id: NodeId) {
-            let children = { tree.get_node_data(id).children.clone() };
-            for child in children {
-                recurse(tree, child);
+            let children = tree.children_ids(id);
+            if let Some(children) = children {
+                for child in children {
+                    recurse(tree, child);
+                }
             }
 
-            tree.nodes.remove(id);
+            tree.nodes.delete_entity(id);
         }
         {
-            let node_data_mut = self.node_slab_mut();
+            let mut node_data_mut = self.node_data_mut();
             if let Some(parent) = node_data_mut.get(id).unwrap().parent {
-                let parent = node_data_mut.get_mut(parent).unwrap();
+                let parent = (&mut node_data_mut).get(parent).unwrap();
                 parent.children.retain(|&child| child != id);
             }
         }
@@ -82,19 +69,20 @@ impl Tree {
 
     pub fn remove_single(&mut self, id: NodeId) {
         {
-            let node_data_mut = self.node_slab_mut();
+            let mut node_data_mut = self.node_data_mut();
             if let Some(parent) = node_data_mut.get(id).unwrap().parent {
-                let parent = node_data_mut.get_mut(parent).unwrap();
+                let parent = (&mut node_data_mut).get(parent).unwrap();
                 parent.children.retain(|&child| child != id);
             }
         }
 
-        self.nodes.remove(id);
+        self.nodes.delete_entity(id);
     }
 
     fn set_height(&mut self, node: NodeId, height: u16) {
         let children = {
-            let mut node = self.get_node_data_mut(node);
+            let mut node_data_mut = self.node_data_mut();
+            let mut node = (&mut node_data_mut).get(node).unwrap();
             node.height = height;
             node.children.clone()
         };
@@ -103,31 +91,33 @@ impl Tree {
         }
     }
 
-    pub fn create_node(&mut self) -> EntryBuilder<'_> {
-        let mut node = self.nodes.insert();
-        node.insert(Node {
+    pub fn create_node(&mut self) -> NodeBuilder<'_> {
+        let node = self.nodes.add_entity((Node {
             parent: None,
             children: Vec::new(),
             height: 0,
-        });
-        node
+        },));
+        NodeBuilder { tree: self, node }
     }
 
     pub fn add_child(&mut self, parent: NodeId, new: NodeId) {
-        let node_state = self.node_slab_mut();
-        node_state.get_mut(new).unwrap().parent = Some(parent);
-        let parent = node_state.get_mut(parent).unwrap();
-        parent.children.push(new);
-        let height = parent.height + 1;
+        let height;
+        {
+            let mut node_state = self.node_data_mut();
+            (&mut node_state).get(new).unwrap().parent = Some(parent);
+            let parent = (&mut node_state).get(parent).unwrap();
+            parent.children.push(new);
+            height = parent.height + 1;
+        }
         self.set_height(new, height);
     }
 
     pub fn replace(&mut self, old_id: NodeId, new_id: NodeId) {
         {
-            let node_state = self.node_slab_mut();
+            let mut node_state = self.node_data_mut();
             // update the parent's link to the child
             if let Some(parent_id) = node_state.get(old_id).unwrap().parent {
-                let parent = node_state.get_mut(parent_id).unwrap();
+                let parent = (&mut node_state).get(parent_id).unwrap();
                 for id in &mut parent.children {
                     if *id == old_id {
                         *id = new_id;
@@ -135,6 +125,7 @@ impl Tree {
                     }
                 }
                 let height = parent.height + 1;
+                drop(node_state);
                 self.set_height(new_id, height);
             }
         }
@@ -143,11 +134,11 @@ impl Tree {
     }
 
     pub fn insert_before(&mut self, old_id: NodeId, new_id: NodeId) {
-        let node_state = self.node_slab_mut();
+        let mut node_state = self.node_data_mut();
         let old_node = node_state.get(old_id).unwrap();
         let parent_id = old_node.parent.expect("tried to insert before root");
-        node_state.get_mut(new_id).unwrap().parent = Some(parent_id);
-        let parent = node_state.get_mut(parent_id).unwrap();
+        (&mut node_state).get(new_id).unwrap().parent = Some(parent_id);
+        let parent = (&mut node_state).get(parent_id).unwrap();
         let index = parent
             .children
             .iter()
@@ -155,15 +146,16 @@ impl Tree {
             .unwrap();
         parent.children.insert(index, new_id);
         let height = parent.height + 1;
+        drop(node_state);
         self.set_height(new_id, height);
     }
 
     pub fn insert_after(&mut self, old_id: NodeId, new_id: NodeId) {
-        let node_state = self.node_slab_mut();
+        let mut node_state = self.node_data_mut();
         let old_node = node_state.get(old_id).unwrap();
         let parent_id = old_node.parent.expect("tried to insert before root");
-        node_state.get_mut(new_id).unwrap().parent = Some(parent_id);
-        let parent = node_state.get_mut(parent_id).unwrap();
+        (&mut node_state).get(new_id).unwrap().parent = Some(parent_id);
+        let parent = (&mut node_state).get(parent_id).unwrap();
         let index = parent
             .children
             .iter()
@@ -171,35 +163,16 @@ impl Tree {
             .unwrap();
         parent.children.insert(index + 1, new_id);
         let height = parent.height + 1;
+        drop(node_state);
         self.set_height(new_id, height);
     }
 
-    pub fn size(&self) -> usize {
-        self.nodes.len()
-    }
-
-    pub fn dynamically_borrowed(&mut self) -> DynamicallyBorrowedTree<'_> {
-        DynamicallyBorrowedTree {
-            nodes: self.nodes.dynamically_borrowed(),
-        }
-    }
-
-    pub fn get<T: Any + Sync + Send>(&self, id: NodeId) -> Option<&T> {
-        self.nodes.try_read_slab().and_then(|slab| slab.get(id))
-    }
-
-    pub fn get_mut<T: Any + Sync + Send>(&mut self, id: NodeId) -> Option<&mut T> {
-        self.nodes
-            .try_write_slab()
-            .and_then(|slab| slab.get_mut(id))
-    }
-
-    pub fn insert<T: Any + Sync + Send>(&mut self, id: NodeId, value: T) {
-        self.nodes.get_or_insert_slab_mut().insert(id, value);
+    pub fn insert<T: Component + Sync + Send>(&mut self, id: NodeId, value: T) {
+        self.nodes.add_component(id, value);
     }
 
     pub fn contains(&self, id: NodeId) -> bool {
-        self.nodes.contains(id)
+        self.nodes.borrow::<EntitiesView>().unwrap().is_alive(id)
     }
 
     pub fn root(&self) -> NodeId {
@@ -207,128 +180,18 @@ impl Tree {
     }
 
     pub fn parent_id(&self, id: NodeId) -> Option<NodeId> {
-        self.try_get_node_data(id).and_then(|node| node.parent)
+        let node_data = self.node_data();
+        node_data.get(id).unwrap().parent
     }
 
-    pub fn children_ids(&self, id: NodeId) -> Option<&[NodeId]> {
-        self.try_get_node_data(id).map(|node| &*node.children)
+    pub fn children_ids(&self, id: NodeId) -> Option<Vec<NodeId>> {
+        let node_data = self.node_data();
+        node_data.get(id).map(|node| node.children.clone()).ok()
     }
 
     pub fn height(&self, id: NodeId) -> Option<u16> {
-        self.try_get_node_data(id).map(|node| node.height)
-    }
-}
-
-pub(crate) struct DynamicallyBorrowedTree<'a> {
-    nodes: DynamiclyBorrowedAnySlabView<'a>,
-}
-
-impl<'a> DynamicallyBorrowedTree<'a> {
-    pub fn view(
-        &self,
-        immutable: impl IntoIterator<Item = TypeId>,
-        mutable: impl IntoIterator<Item = TypeId>,
-    ) -> TreeStateView<'_, 'a> {
-        let nodes_data = self.node_slab();
-        let mut nodes = FxHashMap::default();
-        for id in immutable {
-            nodes.insert(id, MaybeRead::Read(self.nodes.get_slab(id).unwrap()));
-        }
-        for id in mutable {
-            nodes.insert(id, MaybeRead::Write(self.nodes.get_slab_mut(id).unwrap()));
-        }
-
-        TreeStateView { nodes_data, nodes }
-    }
-
-    fn node_slab(&self) -> MappedRwLockReadGuard<SlabStorage<Node>> {
-        RwLockReadGuard::map(self.nodes.get_slab(TypeId::of::<Node>()).unwrap(), |slab| {
-            slab.as_any().downcast_ref().unwrap()
-        })
-    }
-}
-
-enum MaybeRead<'a, 'b> {
-    Read(RwLockReadGuard<'a, &'b mut dyn AnySlabStorageImpl>),
-    Write(RwLockWriteGuard<'a, &'b mut dyn AnySlabStorageImpl>),
-}
-
-#[derive(Clone, Copy)]
-pub struct TreeStateViewEntry<'a, 'b> {
-    view: &'a TreeStateView<'a, 'b>,
-    id: NodeId,
-}
-
-impl<'a, 'b> AnyMapLike<'a> for TreeStateViewEntry<'a, 'b> {
-    fn get<T: Any + Sync + Send>(self) -> Option<&'a T> {
-        let slab = self.view.get_slab();
-        slab.and_then(|slab| slab.get(self.id))
-    }
-}
-
-pub struct TreeStateView<'a, 'b> {
-    nodes_data: MappedRwLockReadGuard<'a, SlabStorage<Node>>,
-    nodes: FxHashMap<TypeId, MaybeRead<'a, 'b>>,
-}
-
-impl<'a, 'b> TreeStateView<'a, 'b> {
-    pub fn get_slab<T: Any + Sync + Send>(&self) -> Option<&SlabStorage<T>> {
-        self.nodes
-            .get(&TypeId::of::<T>())
-            .and_then(|gaurd| match gaurd {
-                MaybeRead::Read(gaurd) => gaurd.as_any().downcast_ref::<SlabStorage<T>>(),
-                MaybeRead::Write(gaurd) => gaurd.as_any().downcast_ref::<SlabStorage<T>>(),
-            })
-    }
-
-    pub fn get_slab_mut<T: Any + Sync + Send>(&mut self) -> Option<&mut SlabStorage<T>> {
-        self.nodes
-            .get_mut(&TypeId::of::<T>())
-            .and_then(|gaurd| match gaurd {
-                MaybeRead::Read(_gaurd) => None,
-                MaybeRead::Write(gaurd) => gaurd.as_any_mut().downcast_mut::<SlabStorage<T>>(),
-            })
-    }
-
-    pub fn children_ids(&self, id: NodeId) -> Option<&[NodeId]> {
-        self.nodes_data.get(id).map(|node| &*node.children)
-    }
-
-    pub fn parent_id(&self, id: NodeId) -> Option<NodeId> {
-        self.nodes_data.get(id).and_then(|node| node.parent)
-    }
-
-    pub fn height(&self, id: NodeId) -> Option<u16> {
-        self.nodes_data.get(id).map(|n| n.height)
-    }
-
-    pub fn get<T: Dependancy>(&self, id: NodeId) -> Option<T::ElementBorrowed<'_>> {
-        T::borrow_elements_from(self.entry(id))
-    }
-
-    pub fn get_single<T: Any + Sync + Send>(&self, id: NodeId) -> Option<&T> {
-        self.get_slab().and_then(|slab| slab.get(id))
-    }
-
-    pub fn get_mut<T: Any + Sync + Send>(&mut self, id: NodeId) -> Option<&mut T> {
-        self.get_slab_mut().and_then(|slab| slab.get_mut(id))
-    }
-
-    pub fn entry(&self, id: NodeId) -> TreeStateViewEntry<'_, 'b> {
-        TreeStateViewEntry { view: self, id }
-    }
-
-    pub fn children<T: Dependancy>(&self, id: NodeId) -> Option<Vec<T::ElementBorrowed<'_>>> {
-        let ids = self.children_ids(id);
-        ids.and_then(|ids| {
-            ids.iter()
-                .map(|id| T::borrow_elements_from(self.entry(*id)))
-                .collect()
-        })
-    }
-
-    pub fn parent<T: Dependancy>(&self, id: NodeId) -> Option<T::ElementBorrowed<'_>> {
-        T::borrow_elements_from(self.entry(self.parent_id(id)?))
+        let node_data = self.node_data();
+        node_data.get(id).map(|node| node.height).ok()
     }
 }
 
@@ -464,244 +327,17 @@ fn deletion() {
     assert_eq!(tree.get::<i32>(after), None);
 }
 
-#[derive(Debug)]
-pub struct SlabStorage<T> {
-    data: Vec<Option<T>>,
-}
-
-impl<T> Default for SlabStorage<T> {
-    fn default() -> Self {
-        Self { data: Vec::new() }
-    }
+pub struct NodeBuilder<'a> {
+    tree: &'a mut Tree,
+    node: EntityId,
 }
 
-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;
-}
-
-impl<T> SlabStorage<T> {
-    fn get(&self, id: NodeId) -> Option<&T> {
-        self.data.get(id.0).and_then(|x| x.as_ref())
+impl<'a> NodeBuilder<'a> {
+    pub fn insert<T: Component + Send + Sync>(&mut self, component: T) {
+        self.tree.insert(self.node, component);
     }
 
-    fn get_mut(&mut self, id: NodeId) -> Option<&mut T> {
-        self.data.get_mut(id.0).and_then(|x| x.as_mut())
+    pub fn id(&self) -> EntityId {
+        self.node
     }
-
-    pub fn entry(&mut self, id: NodeId) -> SlabEntry<'_, T> {
-        let idx = id.0;
-        if idx >= self.data.len() {
-            self.data.resize_with(idx + 1, || None);
-        }
-        SlabEntry {
-            value: &mut self.data[idx],
-        }
-    }
-
-    fn insert(&mut self, id: NodeId, value: T) {
-        let idx = id.0;
-        if idx >= self.data.len() {
-            self.data.resize_with(idx + 1, || None);
-        }
-        self.data[idx] = Some(value);
-    }
-}
-
-pub struct SlabEntry<'a, T> {
-    pub value: &'a mut Option<T>,
-}
-
-impl<'a, T> SlabEntry<'a, T> {
-    pub fn or_insert_with<F: FnOnce() -> T>(self, f: F) -> &'a mut T {
-        self.value.get_or_insert_with(f)
-    }
-
-    pub fn or_insert(self, value: T) -> &'a mut T {
-        self.value.get_or_insert(value)
-    }
-
-    pub fn or_default(self) -> &'a mut T
-    where
-        T: Default,
-    {
-        self.value.get_or_insert_with(Default::default)
-    }
-}
-
-impl<T: 'static + Send + Sync> AnySlabStorageImpl for SlabStorage<T> {
-    fn remove(&mut self, id: NodeId) {
-        if let Some(entry) = self.data.get_mut(id.0) {
-            let _ = entry.take();
-        }
-    }
-
-    fn as_any(&self) -> &dyn Any {
-        self
-    }
-
-    fn as_any_mut(&mut self) -> &mut dyn Any {
-        self
-    }
-}
-
-pub(crate) struct DynamiclyBorrowedAnySlabView<'a> {
-    data: hashbrown::HashMap<
-        TypeId,
-        RwLock<&'a mut dyn AnySlabStorageImpl>,
-        BuildHasherDefault<FxHasher>,
-    >,
-}
-
-impl<'a> DynamiclyBorrowedAnySlabView<'a> {
-    fn get_slab<'b>(
-        &'b self,
-        type_id: TypeId,
-    ) -> Option<RwLockReadGuard<'b, &'a mut dyn AnySlabStorageImpl>> {
-        self.data.get(&type_id).map(|x| x.read())
-    }
-
-    fn get_slab_mut<'b>(
-        &'b self,
-        type_id: TypeId,
-    ) -> Option<RwLockWriteGuard<'b, &'a mut dyn AnySlabStorageImpl>> {
-        self.data.get(&type_id).map(|x| x.write())
-    }
-}
-
-pub(crate) struct AnySlab {
-    data: hashbrown::HashMap<TypeId, Box<dyn AnySlabStorageImpl>, BuildHasherDefault<FxHasher>>,
-    filled: Vec<bool>,
-    free: VecDeque<NodeId>,
-    len: usize,
-}
-
-impl Debug for AnySlab {
-    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
-        f.debug_struct("AnySlab")
-            .field("data", &self.data.keys().collect::<Vec<_>>())
-            .field("free", &self.free)
-            .field("len", &self.len)
-            .finish()
-    }
-}
-
-impl Default for AnySlab {
-    fn default() -> Self {
-        Self::new()
-    }
-}
-
-impl AnySlab {
-    fn new() -> Self {
-        Self {
-            data: Default::default(),
-            filled: Default::default(),
-            free: VecDeque::new(),
-            len: 0,
-        }
-    }
-
-    fn try_read_slab<T: Any + Sync + Send>(&self) -> Option<&SlabStorage<T>> {
-        self.data
-            .get(&TypeId::of::<T>())
-            .map(|x| x.as_any().downcast_ref().unwrap())
-    }
-
-    fn read_slab<T: Any + Sync + Send>(&self) -> &SlabStorage<T> {
-        self.try_read_slab().unwrap()
-    }
-
-    fn try_write_slab<T: Any + Sync + Send>(&mut self) -> Option<&mut SlabStorage<T>> {
-        self.data
-            .get_mut(&TypeId::of::<T>())
-            .map(|x| x.as_any_mut().downcast_mut().unwrap())
-    }
-
-    fn write_slab<T: Any + Sync + Send>(&mut self) -> &mut SlabStorage<T> {
-        self.try_write_slab().unwrap()
-    }
-
-    fn get_or_insert_slab_mut<T: Any + Send + Sync>(&mut self) -> &mut SlabStorage<T> {
-        self.data
-            .entry(TypeId::of::<T>())
-            .or_insert_with(|| Box::<SlabStorage<T>>::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)
-        };
-        EntryBuilder { id, inner: self }
-    }
-
-    fn remove(&mut self, id: NodeId) {
-        for slab in self.data.values_mut() {
-            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()
-    }
-
-    fn dynamically_borrowed(&mut self) -> DynamiclyBorrowedAnySlabView<'_> {
-        DynamiclyBorrowedAnySlabView {
-            data: self
-                .data
-                .iter_mut()
-                .map(|(k, v)| (*k, RwLock::new(&mut **v)))
-                .collect(),
-        }
-    }
-}
-
-pub(crate) struct EntryBuilder<'a> {
-    id: NodeId,
-    inner: &'a mut AnySlab,
-}
-
-impl EntryBuilder<'_> {
-    pub fn insert<T: Any + Send + Sync>(&mut self, value: T) {
-        self.inner
-            .get_or_insert_slab_mut::<T>()
-            .insert(self.id, value);
-    }
-
-    pub fn id(&self) -> NodeId {
-        self.id
-    }
-}
-
-#[test]
-fn remove() {
-    let mut slab = AnySlab::new();
-    let mut node1 = slab.insert();
-    node1.insert(0i32);
-    let node1_id = node1.id();
-    let mut node2 = slab.insert();
-    node2.insert(0i32);
-
-    assert_eq!(slab.len(), 2);
-
-    slab.remove(node1_id);
-
-    assert!(slab.read_slab::<i32>().get(node1_id).is_none());
-    assert_eq!(slab.len(), 1);
 }

+ 6 - 6
packages/native-core/src/utils/persistant_iterator.rs

@@ -73,7 +73,7 @@ pub struct PersistantElementIter {
 
 impl PersistantElementIter {
     pub fn create<V: FromAnyValue + Send + Sync>(rdom: &mut RealDom<V>) -> Self {
-        let inner = Arc::new(Mutex::new(smallvec::smallvec![NodeId(0)]));
+        let inner = Arc::new(Mutex::new(smallvec::smallvec![rdom.root_id()]));
 
         rdom.add_node_watcher(PersistantElementIterUpdater {
             stack: inner.clone(),
@@ -87,7 +87,7 @@ impl PersistantElementIter {
     pub fn next<V: FromAnyValue + Send + Sync>(&mut self, rdom: &RealDom<V>) -> ElementProduced {
         let mut stack = self.stack.lock().unwrap();
         if stack.is_empty() {
-            let id = NodeId(0);
+            let id = rdom.root_id();
             let new = id;
             stack.push(new);
             ElementProduced::Looped(id)
@@ -113,7 +113,7 @@ impl PersistantElementIter {
                     // otherwise, continue the loop and go to the parent
                 } else {
                     // if there is no parent, loop back to the root
-                    let new = NodeId(0);
+                    let new = rdom.root_id();
                     stack.clear();
                     stack.push(new);
                     return ElementProduced::Looped(new);
@@ -139,7 +139,7 @@ impl PersistantElementIter {
         }
         let mut stack = self.stack.lock().unwrap();
         if stack.is_empty() {
-            let id = NodeId(0);
+            let id = rdom.root_id();
             let last = push_back(&mut stack, rdom.get(id).unwrap());
             ElementProduced::Looped(last)
         } else if let Some(current) = stack.pop().and_then(|last| rdom.get(last)) {
@@ -154,13 +154,13 @@ impl PersistantElementIter {
                 ElementProduced::Progressed(*parent)
             } else {
                 // if there is no parent, loop back to the root
-                let id = NodeId(0);
+                let id = rdom.root_id();
                 let last = push_back(&mut stack, rdom.get(id).unwrap());
                 ElementProduced::Looped(last)
             }
         } else {
             // if there is no parent, loop back to the root
-            let id = NodeId(0);
+            let id = rdom.root_id();
             let last = push_back(&mut stack, rdom.get(id).unwrap());
             ElementProduced::Looped(last)
         }