work on seperating tree struture from realdom
This commit is contained in:
1 parent
0cfbfc88e2
commit
078b8ba833
9 files changed
+1118
-493
No files matched your search
@@ -20,6 +20,7 @@ smallvec = "1.6"
|
|||||||
rustc-hash = "1.1.0"
|
rustc-hash = "1.1.0"
|
||||||
anymap = "0.12.1"
|
anymap = "0.12.1"
|
||||||
slab = "0.4"
|
slab = "0.4"
|
||||||
|
parking_lot = "0.12.1"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
rand = "0.8.5"
|
rand = "0.8.5"
|
||||||
@@ -1,54 +1,17 @@
|
|||||||
use std::cmp::Ordering;
|
use tree::NodeId;
|
||||||
|
|
||||||
use dioxus_core::ElementId;
|
|
||||||
|
|
||||||
pub mod layout_attributes;
|
pub mod layout_attributes;
|
||||||
|
pub mod node;
|
||||||
pub mod node_ref;
|
pub mod node_ref;
|
||||||
pub mod real_dom;
|
pub mod real_dom;
|
||||||
pub mod state;
|
pub mod state;
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
pub mod traversable;
|
pub mod traversable;
|
||||||
|
pub mod tree;
|
||||||
pub mod utils;
|
pub mod utils;
|
||||||
|
|
||||||
/// A id for a node that lives in the real dom.
|
/// A id for a node that lives in the real dom.
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
type RealNodeId = NodeId;
|
||||||
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),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Used in derived state macros
|
/// Used in derived state macros
|
||||||
#[derive(Eq, PartialEq)]
|
#[derive(Eq, PartialEq)]
|
||||||
|
|||||||
@@ -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,
|
||||||
|
}
|
||||||
@@ -1,7 +1,8 @@
|
|||||||
|
use dioxus_core::ElementId;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
real_dom::{NodeData, NodeType, OwnedAttributeView},
|
node::{NodeData, NodeType, OwnedAttributeView},
|
||||||
state::union_ordered_iter,
|
state::union_ordered_iter,
|
||||||
RealNodeId,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/// A view into a [VNode] with limited access.
|
/// A view into a [VNode] with limited access.
|
||||||
@@ -21,8 +22,8 @@ impl<'a> NodeView<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Get the id of the node
|
/// Get the id of the node
|
||||||
pub fn id(&self) -> RealNodeId {
|
pub fn id(&self) -> Option<ElementId> {
|
||||||
self.inner.id.unwrap()
|
self.inner.element_id
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the tag of the node if the tag is enabled in the mask
|
/// Get the tag of the node if the tag is enabled in the mask
|
||||||
|
|||||||
@@ -1,12 +1,14 @@
|
|||||||
use anymap::AnyMap;
|
use anymap::AnyMap;
|
||||||
use dioxus_core::{AttributeDiscription, ElementId, Mutations, OwnedAttributeValue, VNode};
|
use dioxus_core::{ElementId, Mutations, VNode};
|
||||||
use rustc_hash::{FxHashMap, FxHashSet};
|
use rustc_hash::{FxHashMap, FxHashSet};
|
||||||
use slab::Slab;
|
use slab::Slab;
|
||||||
use std::ops::{Index, IndexMut};
|
use std::ops::{Index, IndexMut};
|
||||||
|
|
||||||
|
use crate::node::{Node, NodeType};
|
||||||
use crate::node_ref::{AttributeMask, NodeMask};
|
use crate::node_ref::{AttributeMask, NodeMask};
|
||||||
use crate::state::State;
|
use crate::state::State;
|
||||||
use crate::traversable::Traversable;
|
use crate::traversable::Traversable;
|
||||||
|
use crate::tree::{NodeId, Tree, TreeLike, TreeView};
|
||||||
use crate::RealNodeId;
|
use crate::RealNodeId;
|
||||||
|
|
||||||
/// A Dom that can sync with the VirtualDom mutations intended for use in lazy renderers.
|
/// 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.
|
/// 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)]
|
#[derive(Debug)]
|
||||||
pub struct RealDom<S: State> {
|
pub struct RealDom<S: State> {
|
||||||
root: usize,
|
tree: Tree<Node<S>>,
|
||||||
nodes: Vec<Option<Box<Node<S>>>>,
|
/// a map from element id to real node id
|
||||||
// some nodes do not have an ElementId immediately, those node are stored here
|
node_id_mapping: Vec<RealNodeId>,
|
||||||
internal_nodes: Slab<Box<Node<S>>>,
|
|
||||||
nodes_listening: FxHashMap<&'static str, FxHashSet<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> {
|
impl<S: State> Default for RealDom<S> {
|
||||||
@@ -39,23 +37,15 @@ impl<S: State> RealDom<S> {
|
|||||||
listeners: FxHashSet::default(),
|
listeners: FxHashSet::default(),
|
||||||
children: Vec::new(),
|
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 {
|
RealDom {
|
||||||
root: 0,
|
tree,
|
||||||
nodes: vec![Some(Box::new(root))],
|
node_id_mapping: Vec::new(),
|
||||||
internal_nodes: Slab::new(),
|
|
||||||
nodes_listening: FxHashMap::default(),
|
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));
|
nodes_updated.push((RealNodeId::ElementId(ElementId(0)), NodeMask::ALL));
|
||||||
for mutations in mutations_vec {
|
for mutations in mutations_vec {
|
||||||
for e in mutations.edits {
|
for e in mutations.edits {
|
||||||
use dioxus_core::DomEdit::*;
|
use dioxus_core::Mutation::*;
|
||||||
match e {
|
match e {
|
||||||
AppendChildren { root, children } => {
|
AppendChildren { root, children } => {
|
||||||
let target = self.resolve_maybe_id(root);
|
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> {
|
impl<T: State> Traversable for RealDom<T> {
|
||||||
type Id = RealNodeId;
|
type Id = RealNodeId;
|
||||||
type Node = Node<T>;
|
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)
|
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,8 +1,7 @@
|
|||||||
use std::{cmp::Ordering, fmt::Debug};
|
use std::{cmp::Ordering, fmt::Debug};
|
||||||
|
|
||||||
|
use crate::node::NodeData;
|
||||||
use crate::node_ref::{NodeMask, NodeView};
|
use crate::node_ref::{NodeMask, NodeView};
|
||||||
use crate::real_dom::NodeData;
|
|
||||||
use crate::traversable::Traversable;
|
|
||||||
use crate::RealNodeId;
|
use crate::RealNodeId;
|
||||||
use anymap::AnyMap;
|
use anymap::AnyMap;
|
||||||
use rustc_hash::FxHashSet;
|
use rustc_hash::FxHashSet;
|
||||||
|
|||||||
@@ -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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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
@@ -1,229 +1,225 @@
|
|||||||
use crate::{
|
// use crate::{real_dom::RealDom, state::State, RealNodeId};
|
||||||
real_dom::{NodeType, RealDom},
|
// use dioxus_core::{ElementId, Mutations};
|
||||||
state::State,
|
|
||||||
RealNodeId,
|
|
||||||
};
|
|
||||||
use dioxus_core::{DomEdit, ElementId, Mutations};
|
|
||||||
|
|
||||||
pub enum ElementProduced {
|
// pub enum ElementProduced {
|
||||||
/// The iterator produced an element by progressing to the next node in a depth first order.
|
// /// The iterator produced an element by progressing to the next node in a depth first order.
|
||||||
Progressed(RealNodeId),
|
// Progressed(RealNodeId),
|
||||||
/// The iterator reached the end of the tree and looped back to the root
|
// /// The iterator reached the end of the tree and looped back to the root
|
||||||
Looped(RealNodeId),
|
// Looped(RealNodeId),
|
||||||
}
|
// }
|
||||||
impl ElementProduced {
|
// impl ElementProduced {
|
||||||
pub fn id(&self) -> RealNodeId {
|
// pub fn id(&self) -> RealNodeId {
|
||||||
match self {
|
// match self {
|
||||||
ElementProduced::Progressed(id) => *id,
|
// ElementProduced::Progressed(id) => *id,
|
||||||
ElementProduced::Looped(id) => *id,
|
// ElementProduced::Looped(id) => *id,
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
#[derive(Debug)]
|
// #[derive(Debug)]
|
||||||
enum NodePosition {
|
// enum NodePosition {
|
||||||
AtNode,
|
// AtNode,
|
||||||
InChild(usize),
|
// InChild(usize),
|
||||||
}
|
// }
|
||||||
|
|
||||||
impl NodePosition {
|
// impl NodePosition {
|
||||||
fn map(&self, mut f: impl FnMut(usize) -> usize) -> Self {
|
// fn map(&self, mut f: impl FnMut(usize) -> usize) -> Self {
|
||||||
match self {
|
// match self {
|
||||||
Self::AtNode => Self::AtNode,
|
// Self::AtNode => Self::AtNode,
|
||||||
Self::InChild(i) => Self::InChild(f(*i)),
|
// Self::InChild(i) => Self::InChild(f(*i)),
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
fn get_or_insert(&mut self, child_idx: usize) -> usize {
|
// fn get_or_insert(&mut self, child_idx: usize) -> usize {
|
||||||
match self {
|
// match self {
|
||||||
Self::AtNode => {
|
// Self::AtNode => {
|
||||||
*self = Self::InChild(child_idx);
|
// *self = Self::InChild(child_idx);
|
||||||
child_idx
|
// child_idx
|
||||||
}
|
// }
|
||||||
Self::InChild(i) => *i,
|
// Self::InChild(i) => *i,
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
/// Focus systems need a iterator that can persist through changes in the [dioxus_core::VirtualDom].
|
// /// Focus systems need a iterator that can persist through changes in the [dioxus_core::VirtualDom].
|
||||||
/// This iterator traverses the tree depth first.
|
// /// 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`]).
|
// /// 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.
|
// /// The iterator loops around when it reaches the end or the beginning.
|
||||||
pub struct PersistantElementIter {
|
// pub struct PersistantElementIter {
|
||||||
// stack of elements and fragments
|
// // stack of elements and fragments
|
||||||
stack: smallvec::SmallVec<[(RealNodeId, NodePosition); 5]>,
|
// stack: smallvec::SmallVec<[(RealNodeId, NodePosition); 5]>,
|
||||||
}
|
// }
|
||||||
|
|
||||||
impl Default for PersistantElementIter {
|
// impl Default for PersistantElementIter {
|
||||||
fn default() -> Self {
|
// fn default() -> Self {
|
||||||
PersistantElementIter {
|
// PersistantElementIter {
|
||||||
stack: smallvec::smallvec![(RealNodeId::ElementId(ElementId(0)), NodePosition::AtNode)],
|
// stack: smallvec::smallvec![(RealNodeId::ElementId(ElementId(0)), NodePosition::AtNode)],
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
impl PersistantElementIter {
|
// impl PersistantElementIter {
|
||||||
pub fn new() -> Self {
|
// pub fn new() -> Self {
|
||||||
Self::default()
|
// Self::default()
|
||||||
}
|
// }
|
||||||
|
|
||||||
/// remove stale element refreneces
|
// /// remove stale element refreneces
|
||||||
/// returns true if the focused element is removed
|
// /// returns true if the focused element is removed
|
||||||
pub fn prune<S: State>(&mut self, mutations: &Mutations, rdom: &RealDom<S>) -> bool {
|
// pub fn prune<S: State>(&mut self, mutations: &Mutations, rdom: &RealDom<S>) -> bool {
|
||||||
let mut changed = false;
|
// let mut changed = false;
|
||||||
let ids_removed: Vec<_> = mutations
|
// let ids_removed: Vec<_> = mutations
|
||||||
.edits
|
// .edits
|
||||||
.iter()
|
// .iter()
|
||||||
.filter_map(|e| {
|
// .filter_map(|e| {
|
||||||
// nodes within templates will never be removed
|
// // nodes within templates will never be removed
|
||||||
if let DomEdit::Remove { root } = e {
|
// if let DomEdit::Remove { root } = e {
|
||||||
let id = rdom.resolve_maybe_id(*root);
|
// let id = rdom.resolve_maybe_id(*root);
|
||||||
Some(id)
|
// Some(id)
|
||||||
} else {
|
// } else {
|
||||||
None
|
// None
|
||||||
}
|
// }
|
||||||
})
|
// })
|
||||||
.collect();
|
// .collect();
|
||||||
// if any element is removed in the chain, remove it and its children from the stack
|
// // if any element is removed in the chain, remove it and its children from the stack
|
||||||
if let Some(r) = self
|
// if let Some(r) = self
|
||||||
.stack
|
// .stack
|
||||||
.iter()
|
// .iter()
|
||||||
.position(|(el_id, _)| ids_removed.iter().any(|id| el_id == id))
|
// .position(|(el_id, _)| ids_removed.iter().any(|id| el_id == id))
|
||||||
{
|
// {
|
||||||
self.stack.truncate(r);
|
// self.stack.truncate(r);
|
||||||
changed = true;
|
// changed = true;
|
||||||
}
|
// }
|
||||||
// if a child is removed or inserted before or at the current element, update the child index
|
// // 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() {
|
// for (el_id, child_idx) in self.stack.iter_mut() {
|
||||||
if let NodePosition::InChild(child_idx) = child_idx {
|
// if let NodePosition::InChild(child_idx) = child_idx {
|
||||||
if let NodeType::Element { children, .. } = &rdom[*el_id].node_data.node_type {
|
// if let NodeType::Element { children, .. } = &rdom[*el_id].node_data.node_type {
|
||||||
for m in &mutations.edits {
|
// for m in &mutations.edits {
|
||||||
match m {
|
// match m {
|
||||||
DomEdit::Remove { root } => {
|
// DomEdit::Remove { root } => {
|
||||||
let id = rdom.resolve_maybe_id(*root);
|
// let id = rdom.resolve_maybe_id(*root);
|
||||||
if children.iter().take(*child_idx + 1).any(|c| *c == id) {
|
// if children.iter().take(*child_idx + 1).any(|c| *c == id) {
|
||||||
*child_idx -= 1;
|
// *child_idx -= 1;
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
DomEdit::InsertBefore { root, nodes } => {
|
// DomEdit::InsertBefore { root, nodes } => {
|
||||||
let id = rdom.resolve_maybe_id(*root);
|
// let id = rdom.resolve_maybe_id(*root);
|
||||||
let n = nodes.len();
|
// let n = nodes.len();
|
||||||
if children.iter().take(*child_idx + 1).any(|c| *c == id) {
|
// if children.iter().take(*child_idx + 1).any(|c| *c == id) {
|
||||||
*child_idx += n as usize;
|
// *child_idx += n as usize;
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
DomEdit::InsertAfter { root, nodes } => {
|
// DomEdit::InsertAfter { root, nodes } => {
|
||||||
let id = rdom.resolve_maybe_id(*root);
|
// let id = rdom.resolve_maybe_id(*root);
|
||||||
let n = nodes.len();
|
// let n = nodes.len();
|
||||||
if children.iter().take(*child_idx).any(|c| *c == id) {
|
// if children.iter().take(*child_idx).any(|c| *c == id) {
|
||||||
*child_idx += n as usize;
|
// *child_idx += n as usize;
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
_ => (),
|
// _ => (),
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
changed
|
// changed
|
||||||
}
|
// }
|
||||||
|
|
||||||
/// get the next element
|
// /// get the next element
|
||||||
pub fn next<S: State>(&mut self, rdom: &RealDom<S>) -> ElementProduced {
|
// pub fn next<S: State>(&mut self, rdom: &RealDom<S>) -> ElementProduced {
|
||||||
if self.stack.is_empty() {
|
// if self.stack.is_empty() {
|
||||||
let id = RealNodeId::ElementId(ElementId(0));
|
// let id = RealNodeId::ElementId(ElementId(0));
|
||||||
let new = (id, NodePosition::AtNode);
|
// let new = (id, NodePosition::AtNode);
|
||||||
self.stack.push(new);
|
// self.stack.push(new);
|
||||||
ElementProduced::Looped(id)
|
// ElementProduced::Looped(id)
|
||||||
} else {
|
// } else {
|
||||||
let (last, o_child_idx) = self.stack.last_mut().unwrap();
|
// let (last, o_child_idx) = self.stack.last_mut().unwrap();
|
||||||
let node = &rdom[*last];
|
// let node = &rdom[*last];
|
||||||
match &node.node_data.node_type {
|
// match &node.node_data.node_type {
|
||||||
NodeType::Element { children, .. } => {
|
// NodeType::Element { children, .. } => {
|
||||||
*o_child_idx = o_child_idx.map(|i| i + 1);
|
// *o_child_idx = o_child_idx.map(|i| i + 1);
|
||||||
// if we have children, go to the next child
|
// // if we have children, go to the next child
|
||||||
let child_idx = o_child_idx.get_or_insert(0);
|
// let child_idx = o_child_idx.get_or_insert(0);
|
||||||
if child_idx >= children.len() {
|
// if child_idx >= children.len() {
|
||||||
self.pop();
|
// self.pop();
|
||||||
self.next(rdom)
|
// self.next(rdom)
|
||||||
} else {
|
// } else {
|
||||||
let id = children[child_idx];
|
// let id = children[child_idx];
|
||||||
if let NodeType::Element { .. } = &rdom[id].node_data.node_type {
|
// if let NodeType::Element { .. } = &rdom[id].node_data.node_type {
|
||||||
self.stack.push((id, NodePosition::AtNode));
|
// self.stack.push((id, NodePosition::AtNode));
|
||||||
}
|
// }
|
||||||
ElementProduced::Progressed(id)
|
// ElementProduced::Progressed(id)
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
NodeType::Text { .. } | NodeType::Placeholder { .. } => {
|
// NodeType::Text { .. } | NodeType::Placeholder { .. } => {
|
||||||
// we are at a leaf, so we are done
|
// // we are at a leaf, so we are done
|
||||||
ElementProduced::Progressed(self.pop())
|
// ElementProduced::Progressed(self.pop())
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
/// get the previous element
|
// /// get the previous element
|
||||||
pub fn prev<S: State>(&mut self, rdom: &RealDom<S>) -> ElementProduced {
|
// pub fn prev<S: State>(&mut self, rdom: &RealDom<S>) -> ElementProduced {
|
||||||
// recursively add the last child element to the stack
|
// // recursively add the last child element to the stack
|
||||||
fn push_back<S: State>(
|
// fn push_back<S: State>(
|
||||||
stack: &mut smallvec::SmallVec<[(RealNodeId, NodePosition); 5]>,
|
// stack: &mut smallvec::SmallVec<[(RealNodeId, NodePosition); 5]>,
|
||||||
new_node: RealNodeId,
|
// new_node: RealNodeId,
|
||||||
rdom: &RealDom<S>,
|
// rdom: &RealDom<S>,
|
||||||
) -> RealNodeId {
|
// ) -> RealNodeId {
|
||||||
match &rdom[new_node].node_data.node_type {
|
// match &rdom[new_node].node_data.node_type {
|
||||||
NodeType::Element { children, .. } => {
|
// NodeType::Element { children, .. } => {
|
||||||
if children.is_empty() {
|
// if children.is_empty() {
|
||||||
new_node
|
// new_node
|
||||||
} else {
|
// } else {
|
||||||
stack.push((new_node, NodePosition::InChild(children.len() - 1)));
|
// stack.push((new_node, NodePosition::InChild(children.len() - 1)));
|
||||||
push_back(stack, *children.last().unwrap(), rdom)
|
// push_back(stack, *children.last().unwrap(), rdom)
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
_ => new_node,
|
// _ => new_node,
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
if self.stack.is_empty() {
|
// if self.stack.is_empty() {
|
||||||
let new_node = RealNodeId::ElementId(ElementId(0));
|
// let new_node = RealNodeId::ElementId(ElementId(0));
|
||||||
ElementProduced::Looped(push_back(&mut self.stack, new_node, rdom))
|
// ElementProduced::Looped(push_back(&mut self.stack, new_node, rdom))
|
||||||
} else {
|
// } else {
|
||||||
let (last, o_child_idx) = self.stack.last_mut().unwrap();
|
// let (last, o_child_idx) = self.stack.last_mut().unwrap();
|
||||||
let node = &rdom[*last];
|
// let node = &rdom[*last];
|
||||||
match &node.node_data.node_type {
|
// match &node.node_data.node_type {
|
||||||
NodeType::Element { children, .. } => {
|
// NodeType::Element { children, .. } => {
|
||||||
// if we have children, go to the next child
|
// // if we have children, go to the next child
|
||||||
if let NodePosition::InChild(0) = o_child_idx {
|
// if let NodePosition::InChild(0) = o_child_idx {
|
||||||
ElementProduced::Progressed(self.pop())
|
// ElementProduced::Progressed(self.pop())
|
||||||
} else {
|
// } else {
|
||||||
*o_child_idx = o_child_idx.map(|i| i - 1);
|
// *o_child_idx = o_child_idx.map(|i| i - 1);
|
||||||
if let NodePosition::InChild(child_idx) = o_child_idx {
|
// if let NodePosition::InChild(child_idx) = o_child_idx {
|
||||||
if *child_idx >= children.len() || children.is_empty() {
|
// if *child_idx >= children.len() || children.is_empty() {
|
||||||
self.pop();
|
// self.pop();
|
||||||
self.prev(rdom)
|
// self.prev(rdom)
|
||||||
} else {
|
// } else {
|
||||||
let new_node = children[*child_idx];
|
// let new_node = children[*child_idx];
|
||||||
ElementProduced::Progressed(push_back(
|
// ElementProduced::Progressed(push_back(
|
||||||
&mut self.stack,
|
// &mut self.stack,
|
||||||
new_node,
|
// new_node,
|
||||||
rdom,
|
// rdom,
|
||||||
))
|
// ))
|
||||||
}
|
// }
|
||||||
} else {
|
// } else {
|
||||||
self.pop();
|
// self.pop();
|
||||||
self.prev(rdom)
|
// self.prev(rdom)
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
NodeType::Text { .. } | NodeType::Placeholder { .. } => {
|
// NodeType::Text { .. } | NodeType::Placeholder { .. } => {
|
||||||
// we are at a leaf, so we are done
|
// // we are at a leaf, so we are done
|
||||||
ElementProduced::Progressed(self.pop())
|
// ElementProduced::Progressed(self.pop())
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
fn pop(&mut self) -> RealNodeId {
|
// fn pop(&mut self) -> RealNodeId {
|
||||||
self.stack.pop().unwrap().0
|
// self.stack.pop().unwrap().0
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
Reference in new issue
Block a user