From 078b8ba833213b27e8626ffe6b0f94cdbc16faa1 Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Thu, 24 Nov 2022 10:56:44 -0600 Subject: [PATCH] work on seperating tree struture from realdom --- packages/native-core/Cargo.toml | 3 +- packages/native-core/src/lib.rs | 45 +- packages/native-core/src/node.rs | 101 +++ packages/native-core/src/node_ref.rs | 9 +- packages/native-core/src/real_dom.rs | 141 +---- packages/native-core/src/state.rs | 3 +- packages/native-core/src/traversable.rs | 102 ---- packages/native-core/src/tree.rs | 781 ++++++++++++++++++++++++ packages/native-core/src/utils.rs | 428 +++++++------ 9 files changed, 1119 insertions(+), 494 deletions(-) create mode 100644 packages/native-core/src/node.rs delete mode 100644 packages/native-core/src/traversable.rs create mode 100644 packages/native-core/src/tree.rs diff --git a/packages/native-core/Cargo.toml b/packages/native-core/Cargo.toml index 76270671a..09c08bc61 100644 --- a/packages/native-core/Cargo.toml +++ b/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" \ No newline at end of file diff --git a/packages/native-core/src/lib.rs b/packages/native-core/src/lib.rs index bf24096a3..bdd7e24be 100644 --- a/packages/native-core/src/lib.rs +++ b/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 { - 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)] diff --git a/packages/native-core/src/node.rs b/packages/native-core/src/node.rs new file mode 100644 index 000000000..5d6285071 --- /dev/null +++ b/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 { + /// 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, + /// 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, + listeners: FxHashSet, + }, + Placeholder, +} + +impl Node { + 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 { + self.node_data.element_id + } +} + +#[derive(Debug, Clone, Hash, PartialEq, Eq)] +pub struct OwnedAttributeDiscription { + pub name: String, + pub namespace: Option, + 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, +} diff --git a/packages/native-core/src/node_ref.rs b/packages/native-core/src/node_ref.rs index edbcfa696..671d85663 100644 --- a/packages/native-core/src/node_ref.rs +++ b/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 { + self.inner.element_id } /// Get the tag of the node if the tag is enabled in the mask diff --git a/packages/native-core/src/real_dom.rs b/packages/native-core/src/real_dom.rs index 20a055778..53547de68 100644 --- a/packages/native-core/src/real_dom.rs +++ b/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 { - root: usize, - nodes: Vec>>>, - // some nodes do not have an ElementId immediately, those node are stored here - internal_nodes: Slab>>, + tree: Tree>, + /// a map from element id to real node id + node_id_mapping: Vec, nodes_listening: FxHashMap<&'static str, FxHashSet>, - last: Option, - // any nodes that have children queued to be added in the form (parent, children remaining) - parents_queued: Vec<(RealNodeId, u32)>, } impl Default for RealDom { @@ -39,23 +37,15 @@ impl RealDom { 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) -> RealNodeId { - if let Some(id) = id { - RealNodeId::ElementId(ElementId(id as usize)) - } else { - self.last.unwrap() } } @@ -68,7 +58,7 @@ impl RealDom { 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 IndexMut for RealDom { } } -/// The node is stored client side and stores only basic data about the node. -#[derive(Debug, Clone)] -pub struct Node { - /// 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, - /// The parent id of the node. - pub parent: Option, - /// 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, - listeners: FxHashSet, - children: Vec, - }, - Placeholder, -} - -impl Node { - 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 Traversable for RealDom { type Id = RealNodeId; type Node = Node; @@ -869,33 +784,3 @@ impl Traversable for RealDom { 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, - pub volatile: bool, -} - -impl PartialEq 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, -} diff --git a/packages/native-core/src/state.rs b/packages/native-core/src/state.rs index 60f8187e3..d858a2a78 100644 --- a/packages/native-core/src/state.rs +++ b/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; diff --git a/packages/native-core/src/traversable.rs b/packages/native-core/src/traversable.rs deleted file mode 100644 index e51295124..000000000 --- a/packages/native-core/src/traversable.rs +++ /dev/null @@ -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; - - 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; - - fn map &N, FMut: Fn(&mut Self::Node) -> &mut N>( - &mut self, - f: F, - f_mut: FMut, - ) -> Map - 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(&::Node) -> &N, - FMut: Fn(&mut ::Node) -> &mut N, -> { - f: F, - f_mut: FMut, - tree: &'a mut T, -} - -impl< - 'a, - T: Traversable, - N, - F: Fn(&::Node) -> &N, - FMut: Fn(&mut ::Node) -> &mut N, - > Traversable for Map<'a, T, N, F, FMut> -{ - type Id = ::Id; - type Node = N; - - fn height(&self, id: Self::Id) -> Option { - 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.tree.parent(id) - } -} diff --git a/packages/native-core/src/tree.rs b/packages/native-core/src/tree.rs new file mode 100644 index 000000000..76769ee54 --- /dev/null +++ b/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 { + value: T, + parent: Option, + children: Vec, +} + +#[derive(Debug)] +pub struct Tree { + nodes: Slab>, + root: NodeId, +} + +pub trait TreeView: Sized { + type Iterator<'a>: Iterator + where + T: 'a, + Self: 'a; + type IteratorMut<'a>: Iterator + 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>; + + fn children_mut<'a>(&'a mut self, id: NodeId) -> Option>; + + 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; + + fn map &T2, FMut: Fn(&mut T) -> &mut T2>( + &mut self, + map: F, + map_mut: FMut, + ) -> TreeMap { + 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: TreeView { + fn new(root: T) -> Self; + + fn add_child(&mut self, parent: NodeId, value: T) -> NodeId; + + fn remove(&mut self, id: NodeId) -> Option; + + 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> { + tree: &'a Tr, + children_ids: &'a [NodeId], + index: usize, + node_type: PhantomData, +} + +impl<'a, T: 'a, Tr: TreeView> Iterator for ChildNodeIterator<'a, T, Tr> { + type Item = &'a T; + + fn next(&mut self) -> Option { + self.children_ids.get(self.index).map(|id| { + self.index += 1; + self.tree.get_unchecked(*id) + }) + } +} + +pub struct ChildNodeIteratorMut<'a, T, Tr: TreeView + 'a> { + tree: *mut Tr, + children_ids: &'a [NodeId], + index: usize, + node_type: PhantomData, +} + +unsafe impl<'a, T, Tr: TreeView + 'a> Sync for ChildNodeIteratorMut<'a, T, Tr> {} + +impl<'a, T, Tr: TreeView> ChildNodeIteratorMut<'a, T, Tr> { + fn tree_mut(&mut self) -> &'a mut Tr { + unsafe { &mut *self.tree } + } +} + +impl<'a, T: 'a, Tr: TreeView> Iterator for ChildNodeIteratorMut<'a, T, Tr> { + type Item = &'a mut T; + + fn next(&mut self) -> Option { + 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 TreeView for Tree { + type Iterator<'a> = ChildNodeIterator<'a, T, Tree> where T: 'a; + type IteratorMut<'a> = ChildNodeIteratorMut<'a, T, Tree> 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.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> { + 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 { + 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 TreeLike for Tree { + 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 { + 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, + F: Fn(&T1) -> &T2, + FMut: Fn(&mut T1) -> &mut T2, +{ + tree: &'a mut Tr, + map: F, + map_mut: FMut, + in_node_type: PhantomData, + out_node_type: PhantomData, +} + +impl<'a, T1, T2, Tr, F, FMut> TreeMap<'a, T1, T2, Tr, F, FMut> +where + Tr: TreeView, + 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 for TreeMap<'a, T1, T2, Tr, F, FMut> +where + Tr: TreeView, + 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.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> { + 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 { + 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> { + tree: Arc>, + node_locks: Arc>>, + node_type: PhantomData, +} + +impl<'a, T, Tr: TreeView> 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 { + let mut locks = self.node_locks.read(); + locks.get(id.0).map(|lock| lock.is_locked()) + } +} + +unsafe impl<'a, T, Tr: TreeView> Send for SharedView<'a, T, Tr> {} +unsafe impl<'a, T, Tr: TreeView> Sync for SharedView<'a, T, Tr> {} +impl<'a, T, Tr: TreeView> 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> 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(&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> TreeView 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.with_node(id, |t| t.children(id)) + } + + fn children_mut<'b>(&'b mut self, id: NodeId) -> Option> { + 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 { + 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; + }); +} diff --git a/packages/native-core/src/utils.rs b/packages/native-core/src/utils.rs index aa61807a4..0a5e7ebf1 100644 --- a/packages/native-core/src/utils.rs +++ b/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(&mut self, mutations: &Mutations, rdom: &RealDom) -> 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(&mut self, mutations: &Mutations, rdom: &RealDom) -> 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(&mut self, rdom: &RealDom) -> 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(&mut self, rdom: &RealDom) -> 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(&mut self, rdom: &RealDom) -> ElementProduced { - // recursively add the last child element to the stack - fn push_back( - stack: &mut smallvec::SmallVec<[(RealNodeId, NodePosition); 5]>, - new_node: RealNodeId, - rdom: &RealDom, - ) -> 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(&mut self, rdom: &RealDom) -> ElementProduced { +// // recursively add the last child element to the stack +// fn push_back( +// stack: &mut smallvec::SmallVec<[(RealNodeId, NodePosition); 5]>, +// new_node: RealNodeId, +// rdom: &RealDom, +// ) -> 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 +// } +// }