Browse Source

work on seperating tree struture from realdom

Evan Almloff 2 years ago
parent
commit
078b8ba833

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

@@ -20,6 +20,7 @@ smallvec = "1.6"
 rustc-hash = "1.1.0"
 anymap = "0.12.1"
 slab = "0.4"
+parking_lot = "0.12.1"
 
 [dev-dependencies]
-rand = "0.8.5"
+rand = "0.8.5"

+ 4 - 41
packages/native-core/src/lib.rs

@@ -1,54 +1,17 @@
-use std::cmp::Ordering;
-
-use dioxus_core::ElementId;
+use tree::NodeId;
 
 pub mod layout_attributes;
+pub mod node;
 pub mod node_ref;
 pub mod real_dom;
 pub mod state;
 #[doc(hidden)]
 pub mod traversable;
+pub mod tree;
 pub mod utils;
 
 /// A id for a node that lives in the real dom.
-#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
-pub enum RealNodeId {
-    ElementId(ElementId),
-    UnaccessableId(usize),
-}
-
-impl RealNodeId {
-    pub fn as_element_id(&self) -> ElementId {
-        match self {
-            RealNodeId::ElementId(id) => *id,
-            RealNodeId::UnaccessableId(_) => panic!("Expected element id"),
-        }
-    }
-
-    pub fn as_unaccessable_id(&self) -> usize {
-        match self {
-            RealNodeId::ElementId(_) => panic!("Expected unaccessable id"),
-            RealNodeId::UnaccessableId(id) => *id,
-        }
-    }
-}
-
-impl Ord for RealNodeId {
-    fn cmp(&self, other: &Self) -> Ordering {
-        self.partial_cmp(other).unwrap()
-    }
-}
-
-impl PartialOrd for RealNodeId {
-    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
-        match (self, other) {
-            (Self::ElementId(a), Self::ElementId(b)) => a.0.partial_cmp(&b.0),
-            (Self::UnaccessableId(a), Self::UnaccessableId(b)) => a.partial_cmp(b),
-            (Self::ElementId(_), Self::UnaccessableId(_)) => Some(Ordering::Greater),
-            (Self::UnaccessableId(_), Self::ElementId(_)) => Some(Ordering::Less),
-        }
-    }
-}
+type RealNodeId = NodeId;
 
 /// Used in derived state macros
 #[derive(Eq, PartialEq)]

+ 101 - 0
packages/native-core/src/node.rs

@@ -0,0 +1,101 @@
+use crate::{state::State, tree::NodeId, RealNodeId};
+use dioxus_core::ElementId;
+use rustc_hash::{FxHashMap, FxHashSet};
+
+/// The node is stored client side and stores only basic data about the node.
+#[derive(Debug, Clone)]
+pub struct Node<S: State> {
+    /// The transformed state of the node.
+    pub state: S,
+    /// The raw data for the node
+    pub node_data: NodeData,
+}
+
+#[derive(Debug, Clone)]
+pub struct NodeData {
+    /// The id of the node in the vdom.
+    pub element_id: Option<ElementId>,
+    /// Additional inforation specific to the node type
+    pub node_type: NodeType,
+    /// The number of parents before the root node. The root node has height 1.
+    pub height: u16,
+}
+
+/// A type of node with data specific to the node type. The types are a subset of the [VNode] types.
+#[derive(Debug, Clone)]
+pub enum NodeType {
+    Text {
+        text: String,
+    },
+    Element {
+        tag: String,
+        namespace: Option<&'static str>,
+        attributes: FxHashMap<OwnedAttributeDiscription, OwnedAttributeValue>,
+        listeners: FxHashSet<String>,
+    },
+    Placeholder,
+}
+
+impl<S: State> Node<S> {
+    pub(crate) fn new(node_type: NodeType) -> Self {
+        Node {
+            state: S::default(),
+            node_data: NodeData {
+                element_id: None,
+                node_type,
+                height: 0,
+            },
+        }
+    }
+
+    /// link a child node
+    fn add_child(&mut self, child: RealNodeId) {
+        if let NodeType::Element { children, .. } = &mut self.node_data.node_type {
+            children.push(child);
+        }
+    }
+
+    /// remove a child node
+    fn remove_child(&mut self, child: RealNodeId) {
+        if let NodeType::Element { children, .. } = &mut self.node_data.node_type {
+            children.retain(|c| c != &child);
+        }
+    }
+
+    /// link the parent node
+    fn set_parent(&mut self, parent: RealNodeId) {
+        self.node_data.parent = Some(parent);
+    }
+
+    /// get the mounted id of the node
+    pub fn mounted_id(&self) -> Option<ElementId> {
+        self.node_data.element_id
+    }
+}
+
+#[derive(Debug, Clone, Hash, PartialEq, Eq)]
+pub struct OwnedAttributeDiscription {
+    pub name: String,
+    pub namespace: Option<String>,
+    pub volatile: bool,
+}
+
+/// An attribute on a DOM node, such as `id="my-thing"` or
+/// `href="https://example.com"`.
+#[derive(Clone, Copy, Debug)]
+pub struct OwnedAttributeView<'a> {
+    /// The discription of the attribute.
+    pub attribute: &'a OwnedAttributeDiscription,
+
+    /// The value of the attribute.
+    pub value: &'a OwnedAttributeValue,
+}
+
+#[derive(Clone, Debug)]
+pub enum OwnedAttributeValue {
+    Text(String),
+    Float(f32),
+    Int(i32),
+    Bool(bool),
+    None,
+}

+ 5 - 4
packages/native-core/src/node_ref.rs

@@ -1,7 +1,8 @@
+use dioxus_core::ElementId;
+
 use crate::{
-    real_dom::{NodeData, NodeType, OwnedAttributeView},
+    node::{NodeData, NodeType, OwnedAttributeView},
     state::union_ordered_iter,
-    RealNodeId,
 };
 
 /// A view into a [VNode] with limited access.
@@ -21,8 +22,8 @@ impl<'a> NodeView<'a> {
     }
 
     /// Get the id of the node
-    pub fn id(&self) -> RealNodeId {
-        self.inner.id.unwrap()
+    pub fn id(&self) -> Option<ElementId> {
+        self.inner.element_id
     }
 
     /// Get the tag of the node if the tag is enabled in the mask

+ 13 - 128
packages/native-core/src/real_dom.rs

@@ -1,12 +1,14 @@
 use anymap::AnyMap;
-use dioxus_core::{AttributeDiscription, ElementId, Mutations, OwnedAttributeValue, VNode};
+use dioxus_core::{ElementId, Mutations, VNode};
 use rustc_hash::{FxHashMap, FxHashSet};
 use slab::Slab;
 use std::ops::{Index, IndexMut};
 
+use crate::node::{Node, NodeType};
 use crate::node_ref::{AttributeMask, NodeMask};
 use crate::state::State;
 use crate::traversable::Traversable;
+use crate::tree::{NodeId, Tree, TreeLike, TreeView};
 use crate::RealNodeId;
 
 /// A Dom that can sync with the VirtualDom mutations intended for use in lazy renderers.
@@ -14,14 +16,10 @@ use crate::RealNodeId;
 /// 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> {
-    root: usize,
-    nodes: Vec<Option<Box<Node<S>>>>,
-    // some nodes do not have an ElementId immediately, those node are stored here
-    internal_nodes: Slab<Box<Node<S>>>,
+    tree: Tree<Node<S>>,
+    /// a map from element id to real node id
+    node_id_mapping: Vec<RealNodeId>,
     nodes_listening: FxHashMap<&'static str, FxHashSet<RealNodeId>>,
-    last: Option<RealNodeId>,
-    // any nodes that have children queued to be added in the form (parent, children remaining)
-    parents_queued: Vec<(RealNodeId, u32)>,
 }
 
 impl<S: State> Default for RealDom<S> {
@@ -39,23 +37,15 @@ impl<S: State> RealDom<S> {
             listeners: FxHashSet::default(),
             children: Vec::new(),
         });
-        root.node_data.id = Some(RealNodeId::ElementId(ElementId(0)));
+        root.node_data.element_id = Some(ElementId(0));
+        let tree = Tree::new(root);
+        let root_id = tree.root();
+        tree.get_mut(root_id).unwrap().node_data.id = root_id;
 
         RealDom {
-            root: 0,
-            nodes: vec![Some(Box::new(root))],
-            internal_nodes: Slab::new(),
+            tree,
+            node_id_mapping: Vec::new(),
             nodes_listening: FxHashMap::default(),
-            last: None,
-            parents_queued: Vec::new(),
-        }
-    }
-
-    pub fn resolve_maybe_id(&self, id: Option<u64>) -> RealNodeId {
-        if let Some(id) = id {
-            RealNodeId::ElementId(ElementId(id as usize))
-        } else {
-            self.last.unwrap()
         }
     }
 
@@ -68,7 +58,7 @@ impl<S: State> RealDom<S> {
         nodes_updated.push((RealNodeId::ElementId(ElementId(0)), NodeMask::ALL));
         for mutations in mutations_vec {
             for e in mutations.edits {
-                use dioxus_core::DomEdit::*;
+                use dioxus_core::Mutation::*;
                 match e {
                     AppendChildren { root, children } => {
                         let target = self.resolve_maybe_id(root);
@@ -751,81 +741,6 @@ impl<S: State> IndexMut<RealNodeId> for RealDom<S> {
     }
 }
 
-/// The node is stored client side and stores only basic data about the node.
-#[derive(Debug, Clone)]
-pub struct Node<S: State> {
-    /// The transformed state of the node.
-    pub state: S,
-    /// The raw data for the node
-    pub node_data: NodeData,
-}
-
-#[derive(Debug, Clone)]
-pub struct NodeData {
-    /// The id of the node this node was created from.
-    pub id: Option<RealNodeId>,
-    /// The parent id of the node.
-    pub parent: Option<RealNodeId>,
-    /// Additional inforation specific to the node type
-    pub node_type: NodeType,
-    /// The number of parents before the root node. The root node has height 1.
-    pub height: u16,
-}
-
-/// A type of node with data specific to the node type. The types are a subset of the [VNode] types.
-#[derive(Debug, Clone)]
-pub enum NodeType {
-    Text {
-        text: String,
-    },
-    Element {
-        tag: String,
-        namespace: Option<&'static str>,
-        attributes: FxHashMap<OwnedAttributeDiscription, OwnedAttributeValue>,
-        listeners: FxHashSet<String>,
-        children: Vec<RealNodeId>,
-    },
-    Placeholder,
-}
-
-impl<S: State> Node<S> {
-    fn new(node_type: NodeType) -> Self {
-        Node {
-            state: S::default(),
-            node_data: NodeData {
-                id: None,
-                parent: None,
-                node_type,
-                height: 0,
-            },
-        }
-    }
-
-    /// link a child node
-    fn add_child(&mut self, child: RealNodeId) {
-        if let NodeType::Element { children, .. } = &mut self.node_data.node_type {
-            children.push(child);
-        }
-    }
-
-    /// remove a child node
-    fn remove_child(&mut self, child: RealNodeId) {
-        if let NodeType::Element { children, .. } = &mut self.node_data.node_type {
-            children.retain(|c| c != &child);
-        }
-    }
-
-    /// link the parent node
-    fn set_parent(&mut self, parent: RealNodeId) {
-        self.node_data.parent = Some(parent);
-    }
-
-    /// get the mounted id of the node
-    pub fn mounted_id(&self) -> RealNodeId {
-        self.node_data.id.unwrap()
-    }
-}
-
 impl<T: State> Traversable for RealDom<T> {
     type Id = RealNodeId;
     type Node = Node<T>;
@@ -869,33 +784,3 @@ impl<T: State> Traversable for RealDom<T> {
         self.get(id).and_then(|n| n.node_data.parent)
     }
 }
-
-#[derive(Debug, Clone, Hash, PartialEq, Eq)]
-pub struct OwnedAttributeDiscription {
-    pub name: String,
-    pub namespace: Option<String>,
-    pub volatile: bool,
-}
-
-impl PartialEq<AttributeDiscription> for OwnedAttributeDiscription {
-    fn eq(&self, other: &AttributeDiscription) -> bool {
-        self.name == other.name
-            && match (&self.namespace, other.namespace) {
-                (Some(a), Some(b)) => a == b,
-                (None, None) => true,
-                _ => false,
-            }
-            && self.volatile == other.volatile
-    }
-}
-
-/// An attribute on a DOM node, such as `id="my-thing"` or
-/// `href="https://example.com"`.
-#[derive(Clone, Debug)]
-pub struct OwnedAttributeView<'a> {
-    /// The discription of the attribute.
-    pub attribute: &'a OwnedAttributeDiscription,
-
-    /// The value of the attribute.
-    pub value: &'a OwnedAttributeValue,
-}

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

@@ -1,8 +1,7 @@
 use std::{cmp::Ordering, fmt::Debug};
 
+use crate::node::NodeData;
 use crate::node_ref::{NodeMask, NodeView};
-use crate::real_dom::NodeData;
-use crate::traversable::Traversable;
 use crate::RealNodeId;
 use anymap::AnyMap;
 use rustc_hash::FxHashSet;

+ 0 - 102
packages/native-core/src/traversable.rs

@@ -1,102 +0,0 @@
-/// This is a interface for a tree with the ability to jump to a specific node
-pub trait Traversable {
-    type Id: Copy;
-    type Node;
-
-    fn height(&self, id: Self::Id) -> Option<u16>;
-
-    fn get(&self, id: Self::Id) -> Option<&Self::Node>;
-    fn get_mut(&mut self, id: Self::Id) -> Option<&mut Self::Node>;
-
-    fn children(&self, node: Self::Id) -> &[Self::Id];
-    fn parent(&self, node: Self::Id) -> Option<Self::Id>;
-
-    fn map<N, F: Fn(&Self::Node) -> &N, FMut: Fn(&mut Self::Node) -> &mut N>(
-        &mut self,
-        f: F,
-        f_mut: FMut,
-    ) -> Map<Self, N, F, FMut>
-    where
-        Self: Sized,
-    {
-        Map {
-            tree: self,
-            f,
-            f_mut,
-        }
-    }
-
-    // this is safe because no node will have itself as it's parent
-    fn get_node_parent_mut(
-        &mut self,
-        id: Self::Id,
-    ) -> (Option<&mut Self::Node>, Option<&mut Self::Node>) {
-        let node = self.get_mut(id).map(|n| n as *mut _);
-        let parent = self
-            .parent(id)
-            .and_then(|n| self.get_mut(n))
-            .map(|n| n as *mut _);
-        unsafe { (node.map(|n| &mut *n), parent.map(|n| &mut *n)) }
-    }
-
-    // this is safe because no node will have itself as a child
-    fn get_node_children_mut(
-        &mut self,
-        id: Self::Id,
-    ) -> (Option<&mut Self::Node>, Vec<&mut Self::Node>) {
-        let node = self.get_mut(id).map(|n| n as *mut _);
-        let mut children = Vec::new();
-        let children_indexes = self.children(id).to_vec();
-        for id in children_indexes {
-            if let Some(n) = self.get_mut(id) {
-                children.push(unsafe { &mut *(n as *mut _) });
-            }
-        }
-        unsafe { (node.map(|n| &mut *n), children) }
-    }
-}
-
-/// Maps one type of tree to another. Similar to [std::iter::Map].
-pub struct Map<
-    'a,
-    T: Traversable,
-    N,
-    F: Fn(&<T as Traversable>::Node) -> &N,
-    FMut: Fn(&mut <T as Traversable>::Node) -> &mut N,
-> {
-    f: F,
-    f_mut: FMut,
-    tree: &'a mut T,
-}
-
-impl<
-        'a,
-        T: Traversable,
-        N,
-        F: Fn(&<T as Traversable>::Node) -> &N,
-        FMut: Fn(&mut <T as Traversable>::Node) -> &mut N,
-    > Traversable for Map<'a, T, N, F, FMut>
-{
-    type Id = <T as Traversable>::Id;
-    type Node = N;
-
-    fn height(&self, id: Self::Id) -> Option<u16> {
-        self.tree.height(id)
-    }
-
-    fn get(&self, id: Self::Id) -> Option<&Self::Node> {
-        self.tree.get(id).map(&self.f)
-    }
-
-    fn get_mut(&mut self, id: Self::Id) -> Option<&mut Self::Node> {
-        self.tree.get_mut(id).map(&self.f_mut)
-    }
-
-    fn children(&self, id: Self::Id) -> &[Self::Id] {
-        self.tree.children(id)
-    }
-
-    fn parent(&self, id: Self::Id) -> Option<Self::Id> {
-        self.tree.parent(id)
-    }
-}

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

@@ -0,0 +1,781 @@
+use core::panic;
+use parking_lot::lock_api::RawMutex as _;
+use parking_lot::{RawMutex, RwLock};
+use slab::Slab;
+use std::cell::UnsafeCell;
+use std::collections::VecDeque;
+use std::marker::PhantomData;
+use std::sync::Arc;
+
+#[derive(PartialEq, Eq, Clone, Copy, Debug, PartialOrd, Ord)]
+pub struct NodeId(pub usize);
+
+#[derive(PartialEq, Eq, Clone, Debug)]
+pub struct Node<T> {
+    value: T,
+    parent: Option<NodeId>,
+    children: Vec<NodeId>,
+}
+
+#[derive(Debug)]
+pub struct Tree<T> {
+    nodes: Slab<Node<T>>,
+    root: NodeId,
+}
+
+pub trait TreeView<T>: Sized {
+    type Iterator<'a>: Iterator<Item = &'a T>
+    where
+        T: 'a,
+        Self: 'a;
+    type IteratorMut<'a>: Iterator<Item = &'a mut T>
+    where
+        T: 'a,
+        Self: 'a;
+
+    fn root(&self) -> NodeId;
+
+    fn get(&self, id: NodeId) -> Option<&T>;
+
+    fn get_unchecked(&self, id: NodeId) -> &T {
+        unsafe { self.get(id).unwrap_unchecked() }
+    }
+
+    fn get_mut(&mut self, id: NodeId) -> Option<&mut T>;
+
+    fn get_mut_unchecked(&mut self, id: NodeId) -> &mut T {
+        unsafe { self.get_mut(id).unwrap_unchecked() }
+    }
+
+    fn children<'a>(&'a self, id: NodeId) -> Option<Self::Iterator<'a>>;
+
+    fn children_mut<'a>(&'a mut self, id: NodeId) -> Option<Self::IteratorMut<'a>>;
+
+    fn parent_child_mut<'a>(
+        &'a mut self,
+        id: NodeId,
+    ) -> Option<(&'a mut T, Self::IteratorMut<'a>)> {
+        let mut_ptr: *mut Self = self;
+        unsafe {
+            // Safety: No node has itself as a child.
+            (*mut_ptr).get_mut(id).and_then(|parent| {
+                (*mut_ptr)
+                    .children_mut(id)
+                    .map(|children| (parent, children))
+            })
+        }
+    }
+
+    fn children_ids<'a>(&'a self, id: NodeId) -> Option<&'a [NodeId]>;
+
+    fn parent(&self, id: NodeId) -> Option<&T>;
+
+    fn parent_mut(&mut self, id: NodeId) -> Option<&mut T>;
+
+    fn node_parent_mut(&mut self, id: NodeId) -> Option<(&mut T, &mut T)> {
+        let mut_ptr: *mut Self = self;
+        unsafe {
+            // Safety: No node has itself as a parent.
+            (*mut_ptr)
+                .get_mut(id)
+                .and_then(|parent| (*mut_ptr).parent_mut(id).map(|children| (parent, children)))
+        }
+    }
+
+    fn parent_id(&self, id: NodeId) -> Option<NodeId>;
+
+    fn map<T2, F: Fn(&T) -> &T2, FMut: Fn(&mut T) -> &mut T2>(
+        &mut self,
+        map: F,
+        map_mut: FMut,
+    ) -> TreeMap<T, T2, Self, F, FMut> {
+        TreeMap::new(self, map, map_mut)
+    }
+
+    fn size(&self) -> usize;
+
+    fn traverse_depth_first(&self, mut f: impl FnMut(&T)) {
+        let mut stack = vec![self.root()];
+        while let Some(id) = stack.pop() {
+            if let Some(node) = self.get(id) {
+                f(node);
+                if let Some(children) = self.children_ids(id) {
+                    stack.extend(children.iter().copied().rev());
+                }
+            }
+        }
+    }
+
+    fn traverse_depth_first_mut(&mut self, mut f: impl FnMut(&mut T)) {
+        let mut stack = vec![self.root()];
+        while let Some(id) = stack.pop() {
+            if let Some(node) = self.get_mut(id) {
+                f(node);
+                if let Some(children) = self.children_ids(id) {
+                    stack.extend(children.iter().copied().rev());
+                }
+            }
+        }
+    }
+
+    fn traverse_breadth_first(&self, mut f: impl FnMut(&T)) {
+        let mut queue = VecDeque::new();
+        queue.push_back(self.root());
+        while let Some(id) = queue.pop_front() {
+            if let Some(node) = self.get(id) {
+                f(node);
+                if let Some(children) = self.children_ids(id) {
+                    for id in children {
+                        queue.push_back(*id);
+                    }
+                }
+            }
+        }
+    }
+
+    fn traverse_breadth_first_mut(&mut self, mut f: impl FnMut(&mut T)) {
+        let mut queue = VecDeque::new();
+        queue.push_back(self.root());
+        while let Some(id) = queue.pop_front() {
+            if let Some(node) = self.get_mut(id) {
+                f(node);
+                if let Some(children) = self.children_ids(id) {
+                    for id in children {
+                        queue.push_back(*id);
+                    }
+                }
+            }
+        }
+    }
+}
+
+pub trait TreeLike<T>: TreeView<T> {
+    fn new(root: T) -> Self;
+
+    fn add_child(&mut self, parent: NodeId, value: T) -> NodeId;
+
+    fn remove(&mut self, id: NodeId) -> Option<T>;
+
+    fn replace(&mut self, id: NodeId, value: T);
+
+    fn insert_before(&mut self, id: NodeId, value: T) -> NodeId;
+
+    fn insert_after(&mut self, id: NodeId, value: T) -> NodeId;
+}
+
+pub struct ChildNodeIterator<'a, T, Tr: TreeView<T>> {
+    tree: &'a Tr,
+    children_ids: &'a [NodeId],
+    index: usize,
+    node_type: PhantomData<T>,
+}
+
+impl<'a, T: 'a, Tr: TreeView<T>> Iterator for ChildNodeIterator<'a, T, Tr> {
+    type Item = &'a T;
+
+    fn next(&mut self) -> Option<Self::Item> {
+        self.children_ids.get(self.index).map(|id| {
+            self.index += 1;
+            self.tree.get_unchecked(*id)
+        })
+    }
+}
+
+pub struct ChildNodeIteratorMut<'a, T, Tr: TreeView<T> + 'a> {
+    tree: *mut Tr,
+    children_ids: &'a [NodeId],
+    index: usize,
+    node_type: PhantomData<T>,
+}
+
+unsafe impl<'a, T, Tr: TreeView<T> + 'a> Sync for ChildNodeIteratorMut<'a, T, Tr> {}
+
+impl<'a, T, Tr: TreeView<T>> ChildNodeIteratorMut<'a, T, Tr> {
+    fn tree_mut(&mut self) -> &'a mut Tr {
+        unsafe { &mut *self.tree }
+    }
+}
+
+impl<'a, T: 'a, Tr: TreeView<T>> Iterator for ChildNodeIteratorMut<'a, T, Tr> {
+    type Item = &'a mut T;
+
+    fn next(&mut self) -> Option<Self::Item> {
+        let owned = self.children_ids.get(self.index).copied();
+        match owned {
+            Some(id) => {
+                self.index += 1;
+
+                Some(self.tree_mut().get_mut_unchecked(id))
+            }
+            None => None,
+        }
+    }
+}
+
+impl<T> TreeView<T> for Tree<T> {
+    type Iterator<'a> = ChildNodeIterator<'a, T, Tree<T>> where T: 'a;
+    type IteratorMut<'a> = ChildNodeIteratorMut<'a, T, Tree<T>> where T: 'a;
+
+    fn root(&self) -> NodeId {
+        self.root
+    }
+
+    fn get(&self, id: NodeId) -> Option<&T> {
+        self.nodes.get(id.0).map(|node| &node.value)
+    }
+
+    fn get_mut(&mut self, id: NodeId) -> Option<&mut T> {
+        self.nodes.get_mut(id.0).map(|node| &mut node.value)
+    }
+
+    fn children<'a>(&'a self, id: NodeId) -> Option<Self::Iterator<'a>> {
+        self.children_ids(id).map(|children_ids| ChildNodeIterator {
+            tree: self,
+            children_ids,
+            index: 0,
+            node_type: PhantomData,
+        })
+    }
+
+    fn children_mut<'a>(&'a mut self, id: NodeId) -> Option<Self::IteratorMut<'a>> {
+        let raw_ptr = self as *mut Self;
+        unsafe {
+            // Safety: No node will appear as a child twice
+            self.children_ids(id)
+                .map(|children_ids| ChildNodeIteratorMut {
+                    tree: &mut *raw_ptr,
+                    children_ids,
+                    index: 0,
+                    node_type: PhantomData,
+                })
+        }
+    }
+
+    fn children_ids<'a>(&'a self, id: NodeId) -> Option<&'a [NodeId]> {
+        self.nodes.get(id.0).map(|node| node.children.as_slice())
+    }
+
+    fn parent(&self, id: NodeId) -> Option<&T> {
+        self.nodes
+            .get(id.0)
+            .and_then(|node| node.parent.map(|id| self.nodes.get(id.0).unwrap()))
+            .map(|node| &node.value)
+    }
+
+    fn parent_mut(&mut self, id: NodeId) -> Option<&mut T> {
+        let self_ptr = self as *mut Self;
+        unsafe {
+            // Safety: No node has itself as a parent.
+            self.nodes
+                .get_mut(id.0)
+                .and_then(move |node| {
+                    node.parent
+                        .map(move |id| (*self_ptr).nodes.get_mut(id.0).unwrap())
+                })
+                .map(|node| &mut node.value)
+        }
+    }
+
+    fn parent_id(&self, id: NodeId) -> Option<NodeId> {
+        self.nodes.get(id.0).and_then(|node| node.parent)
+    }
+
+    fn get_unchecked(&self, id: NodeId) -> &T {
+        unsafe { &self.nodes.get_unchecked(id.0).value }
+    }
+
+    fn get_mut_unchecked(&mut self, id: NodeId) -> &mut T {
+        unsafe { &mut self.nodes.get_unchecked_mut(id.0).value }
+    }
+
+    fn size(&self) -> usize {
+        self.nodes.len()
+    }
+}
+
+impl<T> TreeLike<T> for Tree<T> {
+    fn new(root: T) -> Self {
+        let mut nodes = Slab::default();
+        let root = NodeId(nodes.insert(Node {
+            value: root,
+            parent: None,
+            children: Vec::new(),
+        }));
+        Self { nodes, root }
+    }
+
+    fn add_child(&mut self, parent: NodeId, value: T) -> NodeId {
+        let node = Node {
+            value,
+            parent: Some(parent),
+            children: Vec::new(),
+        };
+        let id = self.nodes.insert(node);
+        self.nodes
+            .get_mut(parent.0)
+            .unwrap()
+            .children
+            .push(NodeId(id));
+        NodeId(id)
+    }
+
+    fn remove(&mut self, id: NodeId) -> Option<T> {
+        self.nodes.try_remove(id.0).map(|node| {
+            if let Some(parent) = node.parent {
+                self.nodes
+                    .get_mut(parent.0)
+                    .unwrap()
+                    .children
+                    .retain(|child| child != &id);
+            }
+            node.value
+        })
+    }
+
+    fn replace(&mut self, id: NodeId, value: T) {
+        let old = self
+            .nodes
+            .get_mut(id.0)
+            .expect("tried to replace a node that doesn't exist");
+        old.value = value;
+    }
+
+    fn insert_before(&mut self, id: NodeId, value: T) -> NodeId {
+        let node = self.nodes.get(id.0).unwrap();
+        let parent_id = node.parent.expect("tried to insert before root");
+        let new = Node {
+            value,
+            parent: Some(parent_id),
+            children: Vec::new(),
+        };
+        let new_id = NodeId(self.nodes.insert(new));
+        let parent = self.nodes.get_mut(parent_id.0).unwrap();
+        let index = parent
+            .children
+            .iter()
+            .position(|child| child == &id)
+            .unwrap();
+        parent.children.insert(index, new_id);
+        new_id
+    }
+
+    fn insert_after(&mut self, id: NodeId, value: T) -> NodeId {
+        let node = self.nodes.get(id.0).unwrap();
+        let parent_id = node.parent.expect("tried to insert before root");
+        let new = Node {
+            value,
+            parent: Some(parent_id),
+            children: Vec::new(),
+        };
+        let new_id = NodeId(self.nodes.insert(new));
+        let parent = self.nodes.get_mut(parent_id.0).unwrap();
+        let index = parent
+            .children
+            .iter()
+            .position(|child| child == &id)
+            .unwrap();
+        parent.children.insert(index + 1, new_id);
+        new_id
+    }
+}
+
+pub struct TreeMap<'a, T1, T2, Tr, F, FMut>
+where
+    Tr: TreeView<T1>,
+    F: Fn(&T1) -> &T2,
+    FMut: Fn(&mut T1) -> &mut T2,
+{
+    tree: &'a mut Tr,
+    map: F,
+    map_mut: FMut,
+    in_node_type: PhantomData<T1>,
+    out_node_type: PhantomData<T2>,
+}
+
+impl<'a, T1, T2, Tr, F, FMut> TreeMap<'a, T1, T2, Tr, F, FMut>
+where
+    Tr: TreeView<T1>,
+    F: Fn(&T1) -> &T2,
+    FMut: Fn(&mut T1) -> &mut T2,
+{
+    pub fn new(tree: &'a mut Tr, map: F, map_mut: FMut) -> Self {
+        TreeMap {
+            tree,
+            map,
+            map_mut,
+            in_node_type: PhantomData,
+            out_node_type: PhantomData,
+        }
+    }
+}
+
+impl<'a, T1, T2, Tr, F, FMut> TreeView<T2> for TreeMap<'a, T1, T2, Tr, F, FMut>
+where
+    Tr: TreeView<T1>,
+    F: Fn(&T1) -> &T2,
+    FMut: Fn(&mut T1) -> &mut T2,
+{
+    type Iterator<'b> = ChildNodeIterator<'b, T2, TreeMap<'a, T1, T2, Tr, F, FMut>>
+    where
+        T2: 'b,
+        Self:'b;
+    type IteratorMut<'b> = ChildNodeIteratorMut<'b, T2, TreeMap<'a, T1, T2, Tr, F, FMut>>
+    where
+        T2: 'b,
+        Self:'b;
+
+    fn root(&self) -> NodeId {
+        self.tree.root()
+    }
+
+    fn get(&self, id: NodeId) -> Option<&T2> {
+        self.tree.get(id).map(|node| (self.map)(node))
+    }
+
+    fn get_mut(&mut self, id: NodeId) -> Option<&mut T2> {
+        self.tree.get_mut(id).map(|node| (self.map_mut)(node))
+    }
+
+    fn children<'b>(&'b self, id: NodeId) -> Option<Self::Iterator<'b>> {
+        self.children_ids(id).map(|children_ids| ChildNodeIterator {
+            tree: self,
+            children_ids,
+            index: 0,
+            node_type: PhantomData,
+        })
+    }
+
+    fn children_mut<'b>(&'b mut self, id: NodeId) -> Option<Self::IteratorMut<'b>> {
+        let raw_ptr = self as *mut Self;
+        unsafe {
+            // Safety: No node can be a child twice.
+            self.children_ids(id)
+                .map(|children_ids| ChildNodeIteratorMut {
+                    tree: &mut *raw_ptr,
+                    children_ids,
+                    index: 0,
+                    node_type: PhantomData,
+                })
+        }
+    }
+
+    fn children_ids<'b>(&'b self, id: NodeId) -> Option<&'b [NodeId]> {
+        self.tree.children_ids(id)
+    }
+
+    fn parent(&self, id: NodeId) -> Option<&T2> {
+        self.tree.parent(id).map(|node| (self.map)(node))
+    }
+
+    fn parent_mut(&mut self, id: NodeId) -> Option<&mut T2> {
+        self.tree.parent_mut(id).map(|node| (self.map_mut)(node))
+    }
+
+    fn parent_id(&self, id: NodeId) -> Option<NodeId> {
+        self.tree.parent_id(id)
+    }
+
+    fn get_unchecked(&self, id: NodeId) -> &T2 {
+        (self.map)(self.tree.get_unchecked(id))
+    }
+
+    fn get_mut_unchecked(&mut self, id: NodeId) -> &mut T2 {
+        (self.map_mut)(self.tree.get_mut_unchecked(id))
+    }
+
+    fn size(&self) -> usize {
+        self.tree.size()
+    }
+}
+
+/// A view into a tree that can be shared between multiple threads. Nodes are locked invividually.
+pub struct SharedView<'a, T, Tr: TreeView<T>> {
+    tree: Arc<UnsafeCell<&'a mut Tr>>,
+    node_locks: Arc<RwLock<Vec<RawMutex>>>,
+    node_type: PhantomData<T>,
+}
+
+impl<'a, T, Tr: TreeView<T>> SharedView<'a, T, Tr> {
+    /// Checks if a node is currently locked. Returns None if the node does not exist.
+    pub fn check_lock(&self, id: NodeId) -> Option<bool> {
+        let mut locks = self.node_locks.read();
+        locks.get(id.0).map(|lock| lock.is_locked())
+    }
+}
+
+unsafe impl<'a, T, Tr: TreeView<T>> Send for SharedView<'a, T, Tr> {}
+unsafe impl<'a, T, Tr: TreeView<T>> Sync for SharedView<'a, T, Tr> {}
+impl<'a, T, Tr: TreeView<T>> Clone for SharedView<'a, T, Tr> {
+    fn clone(&self) -> Self {
+        Self {
+            tree: self.tree.clone(),
+            node_locks: self.node_locks.clone(),
+            node_type: PhantomData,
+        }
+    }
+}
+
+impl<'a, T, Tr: TreeView<T>> SharedView<'a, T, Tr> {
+    pub fn new(tree: &'a mut Tr) -> Self {
+        let tree = Arc::new(UnsafeCell::new(tree));
+        let mut node_locks = Vec::new();
+        for _ in 0..unsafe { (*tree.get()).size() } {
+            node_locks.push(RawMutex::INIT);
+        }
+        Self {
+            tree,
+            node_locks: Arc::new(RwLock::new(node_locks)),
+            node_type: PhantomData,
+        }
+    }
+
+    fn lock_node(&self, node: NodeId) {
+        let read = self.node_locks.read();
+        let lock = read.get(node.0);
+        match lock {
+            Some(lock) => lock.lock(),
+            None => {
+                drop(read);
+                let mut write = self.node_locks.write();
+                write.resize_with(node.0 + 1, || RawMutex::INIT);
+                unsafe { write.get_unchecked(node.0).lock() }
+            }
+        }
+    }
+
+    fn unlock_node(&self, node: NodeId) {
+        let read = self.node_locks.read();
+        let lock = read.get(node.0);
+        match lock {
+            Some(lock) => unsafe { lock.unlock() },
+            None => {
+                panic!("unlocking node that was not locked")
+            }
+        }
+    }
+
+    fn with_node<R>(&self, node_id: NodeId, f: impl FnOnce(&'a mut Tr) -> R) -> R {
+        self.lock_node(node_id);
+        let tree = unsafe { &mut *self.tree.get() };
+        let r = f(tree);
+        self.unlock_node(node_id);
+        r
+    }
+}
+
+impl<'a, T, Tr: TreeView<T>> TreeView<T> for SharedView<'a, T, Tr> {
+    type Iterator<'b> = Tr::Iterator<'b> where T: 'b, Self: 'b;
+
+    type IteratorMut<'b>=Tr::IteratorMut<'b>
+    where
+        T: 'b,
+        Self: 'b;
+
+    fn root(&self) -> NodeId {
+        unsafe { (*self.tree.get()).root() }
+    }
+
+    fn get(&self, id: NodeId) -> Option<&T> {
+        self.with_node(id, |t| t.get(id))
+    }
+
+    fn get_mut(&mut self, id: NodeId) -> Option<&mut T> {
+        self.with_node(id, |t| t.get_mut(id))
+    }
+
+    fn children<'b>(&'b self, id: NodeId) -> Option<Self::Iterator<'b>> {
+        self.with_node(id, |t| t.children(id))
+    }
+
+    fn children_mut<'b>(&'b mut self, id: NodeId) -> Option<Self::IteratorMut<'b>> {
+        self.with_node(id, |t| t.children_mut(id))
+    }
+
+    fn children_ids<'b>(&'b self, id: NodeId) -> Option<&'b [NodeId]> {
+        self.with_node(id, |t| t.children_ids(id))
+    }
+
+    fn parent(&self, id: NodeId) -> Option<&T> {
+        self.with_node(id, |t| t.get(id))
+    }
+
+    fn parent_mut(&mut self, id: NodeId) -> Option<&mut T> {
+        self.with_node(id, |t| t.parent_mut(id))
+    }
+
+    fn parent_id(&self, id: NodeId) -> Option<NodeId> {
+        self.with_node(id, |t| t.parent_id(id))
+    }
+
+    fn size(&self) -> usize {
+        unsafe { (*self.tree.get()).size() }
+    }
+}
+
+#[test]
+fn creation() {
+    let mut tree = Tree::new(1);
+    let parent = tree.root();
+    let child = tree.add_child(parent, 0);
+
+    println!("Tree: {:#?}", tree);
+    assert_eq!(tree.size(), 2);
+    assert_eq!(*tree.get(parent).unwrap(), 1);
+    assert_eq!(*tree.get(child).unwrap(), 0);
+    assert_eq!(tree.parent_id(parent), None);
+    assert_eq!(tree.parent_id(child).unwrap(), parent);
+    assert_eq!(tree.children_ids(parent).unwrap(), &[child]);
+}
+
+#[test]
+fn insertion() {
+    let mut tree = Tree::new(0);
+    let parent = tree.root();
+    let child = tree.add_child(parent, 2);
+    let before = tree.insert_before(child, 1);
+    let after = tree.insert_after(child, 3);
+
+    println!("Tree: {:#?}", tree);
+    assert_eq!(tree.size(), 4);
+    assert_eq!(*tree.get(parent).unwrap(), 0);
+    assert_eq!(*tree.get(before).unwrap(), 1);
+    assert_eq!(*tree.get(child).unwrap(), 2);
+    assert_eq!(*tree.get(after).unwrap(), 3);
+    assert_eq!(tree.parent_id(before).unwrap(), parent);
+    assert_eq!(tree.parent_id(child).unwrap(), parent);
+    assert_eq!(tree.parent_id(after).unwrap(), parent);
+    assert_eq!(tree.children_ids(parent).unwrap(), &[before, child, after]);
+}
+
+#[test]
+fn deletion() {
+    let mut tree = Tree::new(0);
+    let parent = tree.root();
+    let child = tree.add_child(parent, 2);
+    let before = tree.insert_before(child, 1);
+    let after = tree.insert_after(child, 3);
+
+    println!("Tree: {:#?}", tree);
+    assert_eq!(tree.size(), 4);
+    assert_eq!(*tree.get(parent).unwrap(), 0);
+    assert_eq!(*tree.get(before).unwrap(), 1);
+    assert_eq!(*tree.get(child).unwrap(), 2);
+    assert_eq!(*tree.get(after).unwrap(), 3);
+    assert_eq!(tree.parent_id(before).unwrap(), parent);
+    assert_eq!(tree.parent_id(child).unwrap(), parent);
+    assert_eq!(tree.parent_id(after).unwrap(), parent);
+    assert_eq!(tree.children_ids(parent).unwrap(), &[before, child, after]);
+
+    tree.remove(child);
+
+    println!("Tree: {:#?}", tree);
+    assert_eq!(tree.size(), 3);
+    assert_eq!(*tree.get(parent).unwrap(), 0);
+    assert_eq!(*tree.get(before).unwrap(), 1);
+    assert_eq!(tree.get(child), None);
+    assert_eq!(*tree.get(after).unwrap(), 3);
+    assert_eq!(tree.parent_id(before).unwrap(), parent);
+    assert_eq!(tree.parent_id(after).unwrap(), parent);
+    assert_eq!(tree.children_ids(parent).unwrap(), &[before, after]);
+
+    tree.remove(before);
+
+    println!("Tree: {:#?}", tree);
+    assert_eq!(tree.size(), 2);
+    assert_eq!(*tree.get(parent).unwrap(), 0);
+    assert_eq!(tree.get(before), None);
+    assert_eq!(*tree.get(after).unwrap(), 3);
+    assert_eq!(tree.parent_id(after).unwrap(), parent);
+    assert_eq!(tree.children_ids(parent).unwrap(), &[after]);
+
+    tree.remove(after);
+
+    println!("Tree: {:#?}", tree);
+    assert_eq!(tree.size(), 1);
+    assert_eq!(*tree.get(parent).unwrap(), 0);
+    assert_eq!(tree.get(after), None);
+    assert_eq!(tree.children_ids(parent).unwrap(), &[]);
+}
+
+#[test]
+fn shared_view() {
+    use std::thread;
+    let mut tree = Tree::new(1);
+    let parent = tree.root();
+    let child = tree.add_child(parent, 0);
+
+    let shared = SharedView::new(&mut tree);
+
+    thread::scope(|s| {
+        let (mut shared1, mut shared2, mut shared3) =
+            (shared.clone(), shared.clone(), shared.clone());
+        s.spawn(move || {
+            assert_eq!(*shared1.get_mut(parent).unwrap(), 1);
+            assert_eq!(*shared1.get_mut(child).unwrap(), 0);
+        });
+        s.spawn(move || {
+            assert_eq!(*shared2.get_mut(child).unwrap(), 0);
+            assert_eq!(*shared2.get_mut(parent).unwrap(), 1);
+        });
+        s.spawn(move || {
+            assert_eq!(*shared3.get_mut(parent).unwrap(), 1);
+            assert_eq!(*shared3.get_mut(child).unwrap(), 0);
+        });
+    });
+}
+
+#[test]
+fn map() {
+    #[derive(Debug, PartialEq)]
+    struct Value {
+        value: i32,
+    }
+    impl Value {
+        fn new(value: i32) -> Self {
+            Self { value }
+        }
+    }
+    let mut tree = Tree::new(Value::new(1));
+    let parent = tree.root();
+    let child = tree.add_child(parent, Value::new(0));
+
+    let mut mapped = tree.map(|x| &x.value, |x| &mut x.value);
+
+    *mapped.get_mut(child).unwrap() = 1;
+    *mapped.get_mut(parent).unwrap() = 2;
+
+    assert_eq!(*tree.get(parent).unwrap(), Value::new(2));
+    assert_eq!(*tree.get(child).unwrap(), Value::new(1));
+}
+
+#[test]
+fn traverse_depth_first() {
+    let mut tree = Tree::new(0);
+    let parent = tree.root();
+    let child1 = tree.add_child(parent, 1);
+    tree.add_child(child1, 2);
+    let child2 = tree.add_child(parent, 3);
+    tree.add_child(child2, 4);
+
+    let mut node_count = 0;
+    tree.traverse_depth_first(move |node| {
+        assert_eq!(*node, node_count);
+        node_count += 1;
+    });
+}
+
+#[test]
+fn traverse_breadth_first() {
+    let mut tree = Tree::new(0);
+    let parent = tree.root();
+    let child1 = tree.add_child(parent, 1);
+    tree.add_child(child1, 3);
+    let child2 = tree.add_child(parent, 2);
+    tree.add_child(child2, 4);
+
+    let mut node_count = 0;
+    tree.traverse_breadth_first(move |node| {
+        assert_eq!(*node, node_count);
+        node_count += 1;
+    });
+}

+ 212 - 216
packages/native-core/src/utils.rs

@@ -1,229 +1,225 @@
-use crate::{
-    real_dom::{NodeType, RealDom},
-    state::State,
-    RealNodeId,
-};
-use dioxus_core::{DomEdit, ElementId, Mutations};
+// use crate::{real_dom::RealDom, state::State, RealNodeId};
+// use dioxus_core::{ElementId, Mutations};
 
-pub enum ElementProduced {
-    /// The iterator produced an element by progressing to the next node in a depth first order.
-    Progressed(RealNodeId),
-    /// The iterator reached the end of the tree and looped back to the root
-    Looped(RealNodeId),
-}
-impl ElementProduced {
-    pub fn id(&self) -> RealNodeId {
-        match self {
-            ElementProduced::Progressed(id) => *id,
-            ElementProduced::Looped(id) => *id,
-        }
-    }
-}
+// pub enum ElementProduced {
+//     /// The iterator produced an element by progressing to the next node in a depth first order.
+//     Progressed(RealNodeId),
+//     /// The iterator reached the end of the tree and looped back to the root
+//     Looped(RealNodeId),
+// }
+// impl ElementProduced {
+//     pub fn id(&self) -> RealNodeId {
+//         match self {
+//             ElementProduced::Progressed(id) => *id,
+//             ElementProduced::Looped(id) => *id,
+//         }
+//     }
+// }
 
-#[derive(Debug)]
-enum NodePosition {
-    AtNode,
-    InChild(usize),
-}
+// #[derive(Debug)]
+// enum NodePosition {
+//     AtNode,
+//     InChild(usize),
+// }
 
-impl NodePosition {
-    fn map(&self, mut f: impl FnMut(usize) -> usize) -> Self {
-        match self {
-            Self::AtNode => Self::AtNode,
-            Self::InChild(i) => Self::InChild(f(*i)),
-        }
-    }
+// impl NodePosition {
+//     fn map(&self, mut f: impl FnMut(usize) -> usize) -> Self {
+//         match self {
+//             Self::AtNode => Self::AtNode,
+//             Self::InChild(i) => Self::InChild(f(*i)),
+//         }
+//     }
 
-    fn get_or_insert(&mut self, child_idx: usize) -> usize {
-        match self {
-            Self::AtNode => {
-                *self = Self::InChild(child_idx);
-                child_idx
-            }
-            Self::InChild(i) => *i,
-        }
-    }
-}
+//     fn get_or_insert(&mut self, child_idx: usize) -> usize {
+//         match self {
+//             Self::AtNode => {
+//                 *self = Self::InChild(child_idx);
+//                 child_idx
+//             }
+//             Self::InChild(i) => *i,
+//         }
+//     }
+// }
 
-/// Focus systems need a iterator that can persist through changes in the [dioxus_core::VirtualDom].
-/// This iterator traverses the tree depth first.
-/// Iterate through it with [PersistantElementIter::next] [PersistantElementIter::prev], and update it with [PersistantElementIter::prune] (with data from [`dioxus_core::prelude::VirtualDom::work_with_deadline`]).
-/// The iterator loops around when it reaches the end or the beginning.
-pub struct PersistantElementIter {
-    // stack of elements and fragments
-    stack: smallvec::SmallVec<[(RealNodeId, NodePosition); 5]>,
-}
+// /// Focus systems need a iterator that can persist through changes in the [dioxus_core::VirtualDom].
+// /// This iterator traverses the tree depth first.
+// /// Iterate through it with [PersistantElementIter::next] [PersistantElementIter::prev], and update it with [PersistantElementIter::prune] (with data from [`dioxus_core::prelude::VirtualDom::work_with_deadline`]).
+// /// The iterator loops around when it reaches the end or the beginning.
+// pub struct PersistantElementIter {
+//     // stack of elements and fragments
+//     stack: smallvec::SmallVec<[(RealNodeId, NodePosition); 5]>,
+// }
 
-impl Default for PersistantElementIter {
-    fn default() -> Self {
-        PersistantElementIter {
-            stack: smallvec::smallvec![(RealNodeId::ElementId(ElementId(0)), NodePosition::AtNode)],
-        }
-    }
-}
+// impl Default for PersistantElementIter {
+//     fn default() -> Self {
+//         PersistantElementIter {
+//             stack: smallvec::smallvec![(RealNodeId::ElementId(ElementId(0)), NodePosition::AtNode)],
+//         }
+//     }
+// }
 
-impl PersistantElementIter {
-    pub fn new() -> Self {
-        Self::default()
-    }
+// impl PersistantElementIter {
+//     pub fn new() -> Self {
+//         Self::default()
+//     }
 
-    /// 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 {
-        let mut changed = false;
-        let ids_removed: Vec<_> = mutations
-            .edits
-            .iter()
-            .filter_map(|e| {
-                // nodes within templates will never be removed
-                if let DomEdit::Remove { root } = e {
-                    let id = rdom.resolve_maybe_id(*root);
-                    Some(id)
-                } else {
-                    None
-                }
-            })
-            .collect();
-        // if any element is removed in the chain, remove it and its children from the stack
-        if let Some(r) = self
-            .stack
-            .iter()
-            .position(|(el_id, _)| ids_removed.iter().any(|id| el_id == id))
-        {
-            self.stack.truncate(r);
-            changed = true;
-        }
-        // if a child is removed or inserted before or at the current element, update the child index
-        for (el_id, child_idx) in self.stack.iter_mut() {
-            if let NodePosition::InChild(child_idx) = child_idx {
-                if let NodeType::Element { children, .. } = &rdom[*el_id].node_data.node_type {
-                    for m in &mutations.edits {
-                        match m {
-                            DomEdit::Remove { root } => {
-                                let id = rdom.resolve_maybe_id(*root);
-                                if children.iter().take(*child_idx + 1).any(|c| *c == id) {
-                                    *child_idx -= 1;
-                                }
-                            }
-                            DomEdit::InsertBefore { root, nodes } => {
-                                let id = rdom.resolve_maybe_id(*root);
-                                let n = nodes.len();
-                                if children.iter().take(*child_idx + 1).any(|c| *c == id) {
-                                    *child_idx += n as usize;
-                                }
-                            }
-                            DomEdit::InsertAfter { root, nodes } => {
-                                let id = rdom.resolve_maybe_id(*root);
-                                let n = nodes.len();
-                                if children.iter().take(*child_idx).any(|c| *c == id) {
-                                    *child_idx += n as usize;
-                                }
-                            }
-                            _ => (),
-                        }
-                    }
-                }
-            }
-        }
-        changed
-    }
+//     /// 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 {
+//         let mut changed = false;
+//         let ids_removed: Vec<_> = mutations
+//             .edits
+//             .iter()
+//             .filter_map(|e| {
+//                 // nodes within templates will never be removed
+//                 if let DomEdit::Remove { root } = e {
+//                     let id = rdom.resolve_maybe_id(*root);
+//                     Some(id)
+//                 } else {
+//                     None
+//                 }
+//             })
+//             .collect();
+//         // if any element is removed in the chain, remove it and its children from the stack
+//         if let Some(r) = self
+//             .stack
+//             .iter()
+//             .position(|(el_id, _)| ids_removed.iter().any(|id| el_id == id))
+//         {
+//             self.stack.truncate(r);
+//             changed = true;
+//         }
+//         // if a child is removed or inserted before or at the current element, update the child index
+//         for (el_id, child_idx) in self.stack.iter_mut() {
+//             if let NodePosition::InChild(child_idx) = child_idx {
+//                 if let NodeType::Element { children, .. } = &rdom[*el_id].node_data.node_type {
+//                     for m in &mutations.edits {
+//                         match m {
+//                             DomEdit::Remove { root } => {
+//                                 let id = rdom.resolve_maybe_id(*root);
+//                                 if children.iter().take(*child_idx + 1).any(|c| *c == id) {
+//                                     *child_idx -= 1;
+//                                 }
+//                             }
+//                             DomEdit::InsertBefore { root, nodes } => {
+//                                 let id = rdom.resolve_maybe_id(*root);
+//                                 let n = nodes.len();
+//                                 if children.iter().take(*child_idx + 1).any(|c| *c == id) {
+//                                     *child_idx += n as usize;
+//                                 }
+//                             }
+//                             DomEdit::InsertAfter { root, nodes } => {
+//                                 let id = rdom.resolve_maybe_id(*root);
+//                                 let n = nodes.len();
+//                                 if children.iter().take(*child_idx).any(|c| *c == id) {
+//                                     *child_idx += n as usize;
+//                                 }
+//                             }
+//                             _ => (),
+//                         }
+//                     }
+//                 }
+//             }
+//         }
+//         changed
+//     }
 
-    /// get the next element
-    pub fn next<S: State>(&mut self, rdom: &RealDom<S>) -> ElementProduced {
-        if self.stack.is_empty() {
-            let id = RealNodeId::ElementId(ElementId(0));
-            let new = (id, NodePosition::AtNode);
-            self.stack.push(new);
-            ElementProduced::Looped(id)
-        } else {
-            let (last, o_child_idx) = self.stack.last_mut().unwrap();
-            let node = &rdom[*last];
-            match &node.node_data.node_type {
-                NodeType::Element { children, .. } => {
-                    *o_child_idx = o_child_idx.map(|i| i + 1);
-                    // if we have children, go to the next child
-                    let child_idx = o_child_idx.get_or_insert(0);
-                    if child_idx >= children.len() {
-                        self.pop();
-                        self.next(rdom)
-                    } else {
-                        let id = children[child_idx];
-                        if let NodeType::Element { .. } = &rdom[id].node_data.node_type {
-                            self.stack.push((id, NodePosition::AtNode));
-                        }
-                        ElementProduced::Progressed(id)
-                    }
-                }
+//     /// get the next element
+//     pub fn next<S: State>(&mut self, rdom: &RealDom<S>) -> ElementProduced {
+//         if self.stack.is_empty() {
+//             let id = RealNodeId::ElementId(ElementId(0));
+//             let new = (id, NodePosition::AtNode);
+//             self.stack.push(new);
+//             ElementProduced::Looped(id)
+//         } else {
+//             let (last, o_child_idx) = self.stack.last_mut().unwrap();
+//             let node = &rdom[*last];
+//             match &node.node_data.node_type {
+//                 NodeType::Element { children, .. } => {
+//                     *o_child_idx = o_child_idx.map(|i| i + 1);
+//                     // if we have children, go to the next child
+//                     let child_idx = o_child_idx.get_or_insert(0);
+//                     if child_idx >= children.len() {
+//                         self.pop();
+//                         self.next(rdom)
+//                     } else {
+//                         let id = children[child_idx];
+//                         if let NodeType::Element { .. } = &rdom[id].node_data.node_type {
+//                             self.stack.push((id, NodePosition::AtNode));
+//                         }
+//                         ElementProduced::Progressed(id)
+//                     }
+//                 }
 
-                NodeType::Text { .. } | NodeType::Placeholder { .. } => {
-                    // we are at a leaf, so we are done
-                    ElementProduced::Progressed(self.pop())
-                }
-            }
-        }
-    }
+//                 NodeType::Text { .. } | NodeType::Placeholder { .. } => {
+//                     // we are at a leaf, so we are done
+//                     ElementProduced::Progressed(self.pop())
+//                 }
+//             }
+//         }
+//     }
 
-    /// get the previous element
-    pub fn prev<S: State>(&mut self, rdom: &RealDom<S>) -> ElementProduced {
-        // recursively add the last child element to the stack
-        fn push_back<S: State>(
-            stack: &mut smallvec::SmallVec<[(RealNodeId, NodePosition); 5]>,
-            new_node: RealNodeId,
-            rdom: &RealDom<S>,
-        ) -> RealNodeId {
-            match &rdom[new_node].node_data.node_type {
-                NodeType::Element { children, .. } => {
-                    if children.is_empty() {
-                        new_node
-                    } else {
-                        stack.push((new_node, NodePosition::InChild(children.len() - 1)));
-                        push_back(stack, *children.last().unwrap(), rdom)
-                    }
-                }
-                _ => new_node,
-            }
-        }
-        if self.stack.is_empty() {
-            let new_node = RealNodeId::ElementId(ElementId(0));
-            ElementProduced::Looped(push_back(&mut self.stack, new_node, rdom))
-        } else {
-            let (last, o_child_idx) = self.stack.last_mut().unwrap();
-            let node = &rdom[*last];
-            match &node.node_data.node_type {
-                NodeType::Element { children, .. } => {
-                    // if we have children, go to the next child
-                    if let NodePosition::InChild(0) = o_child_idx {
-                        ElementProduced::Progressed(self.pop())
-                    } else {
-                        *o_child_idx = o_child_idx.map(|i| i - 1);
-                        if let NodePosition::InChild(child_idx) = o_child_idx {
-                            if *child_idx >= children.len() || children.is_empty() {
-                                self.pop();
-                                self.prev(rdom)
-                            } else {
-                                let new_node = children[*child_idx];
-                                ElementProduced::Progressed(push_back(
-                                    &mut self.stack,
-                                    new_node,
-                                    rdom,
-                                ))
-                            }
-                        } else {
-                            self.pop();
-                            self.prev(rdom)
-                        }
-                    }
-                }
+//     /// get the previous element
+//     pub fn prev<S: State>(&mut self, rdom: &RealDom<S>) -> ElementProduced {
+//         // recursively add the last child element to the stack
+//         fn push_back<S: State>(
+//             stack: &mut smallvec::SmallVec<[(RealNodeId, NodePosition); 5]>,
+//             new_node: RealNodeId,
+//             rdom: &RealDom<S>,
+//         ) -> RealNodeId {
+//             match &rdom[new_node].node_data.node_type {
+//                 NodeType::Element { children, .. } => {
+//                     if children.is_empty() {
+//                         new_node
+//                     } else {
+//                         stack.push((new_node, NodePosition::InChild(children.len() - 1)));
+//                         push_back(stack, *children.last().unwrap(), rdom)
+//                     }
+//                 }
+//                 _ => new_node,
+//             }
+//         }
+//         if self.stack.is_empty() {
+//             let new_node = RealNodeId::ElementId(ElementId(0));
+//             ElementProduced::Looped(push_back(&mut self.stack, new_node, rdom))
+//         } else {
+//             let (last, o_child_idx) = self.stack.last_mut().unwrap();
+//             let node = &rdom[*last];
+//             match &node.node_data.node_type {
+//                 NodeType::Element { children, .. } => {
+//                     // if we have children, go to the next child
+//                     if let NodePosition::InChild(0) = o_child_idx {
+//                         ElementProduced::Progressed(self.pop())
+//                     } else {
+//                         *o_child_idx = o_child_idx.map(|i| i - 1);
+//                         if let NodePosition::InChild(child_idx) = o_child_idx {
+//                             if *child_idx >= children.len() || children.is_empty() {
+//                                 self.pop();
+//                                 self.prev(rdom)
+//                             } else {
+//                                 let new_node = children[*child_idx];
+//                                 ElementProduced::Progressed(push_back(
+//                                     &mut self.stack,
+//                                     new_node,
+//                                     rdom,
+//                                 ))
+//                             }
+//                         } else {
+//                             self.pop();
+//                             self.prev(rdom)
+//                         }
+//                     }
+//                 }
 
-                NodeType::Text { .. } | NodeType::Placeholder { .. } => {
-                    // we are at a leaf, so we are done
-                    ElementProduced::Progressed(self.pop())
-                }
-            }
-        }
-    }
+//                 NodeType::Text { .. } | NodeType::Placeholder { .. } => {
+//                     // we are at a leaf, so we are done
+//                     ElementProduced::Progressed(self.pop())
+//                 }
+//             }
+//         }
+//     }
 
-    fn pop(&mut self) -> RealNodeId {
-        self.stack.pop().unwrap().0
-    }
-}
+//     fn pop(&mut self) -> RealNodeId {
+//         self.stack.pop().unwrap().0
+//     }
+// }