From 69e7d55d2c1b62e1838858e763bd60c092c19b08 Mon Sep 17 00:00:00 2001 From: Ian Burns Date: Wed, 1 Feb 2017 19:23:58 -0600 Subject: [PATCH 01/26] add Ancestors and Children iterators --- src/lib.rs | 2 + src/tree/iterators.rs | 131 +++++++++++++++++++++++++++++++++++ src/{tree.rs => tree/mod.rs} | 28 ++++++++ 3 files changed, 161 insertions(+) create mode 100644 src/tree/iterators.rs rename src/{tree.rs => tree/mod.rs} (98%) diff --git a/src/lib.rs b/src/lib.rs index 2ac9eef..620a282 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -90,6 +90,8 @@ pub use node::NodeBuilder; pub use node::Node; pub use tree::TreeBuilder; pub use tree::Tree; +pub use tree::iterators::Ancestors; +pub use tree::iterators::Children; /// /// An identifier used to differentiate between `Node`s within a `Tree`. diff --git a/src/tree/iterators.rs b/src/tree/iterators.rs new file mode 100644 index 0000000..a2524c9 --- /dev/null +++ b/src/tree/iterators.rs @@ -0,0 +1,131 @@ +use super::Tree; +use super::Node; +use super::NodeId; +use super::IteratorNew; + + +pub struct Ancestors<'a, T: 'a> { + tree: &'a Tree, + node_id: Option, +} + +impl<'a, T> IteratorNew<'a, T, Ancestors<'a, T>> for Ancestors<'a, T> { + fn new(tree: &'a Tree, node_id: NodeId) -> Ancestors<'a, T> { + Ancestors { + tree: tree, + node_id: Some(node_id), + } + } +} + +impl<'a, T> Iterator for Ancestors<'a, T> { + type Item = &'a Node; + + fn next(&mut self) -> Option<&'a Node> { + if let Some(current_id) = self.node_id.clone() { + + if let Some(parent_id) = self.tree.get_unsafe(¤t_id).parent() { + + let parent = self.tree.get_unsafe(&parent_id); + + self.node_id = Some(parent_id.clone()); + + return Some(parent); + } else { + self.node_id = None; + } + } + None + } +} + +use std::slice::Iter; + +pub struct Children<'a, T: 'a> { + tree: &'a Tree, + child_ids: Iter<'a, NodeId>, +} + +impl<'a, T> IteratorNew<'a, T, Children<'a, T>> for Children<'a, T> { + fn new(tree: &'a Tree, node_id: NodeId) -> Children<'a, T> { + Children { + tree: tree, + child_ids: tree.get_unsafe(&node_id).children().as_slice().iter() + } + } +} + +impl<'a, T> Iterator for Children<'a, T> { + type Item = &'a Node; + + fn next(&mut self) -> Option<&'a Node> { + if let Some(ref next_child_id) = self.child_ids.next() { + return Some(self.tree.get_unsafe(next_child_id)); + } + None + } +} + +#[cfg(test)] +mod tests { + + use Tree; + use Node; + use InsertBehavior::*; + + #[test] + fn test_ancestors() { + + let mut tree = Tree::new(); + + let root_id = tree.insert(Node::new(0), AsRoot).unwrap(); + let node_1 = tree.insert(Node::new(1), UnderNode(&root_id)).unwrap(); + let node_2 = tree.insert(Node::new(2), UnderNode(&node_1)).unwrap(); + let node_3 = tree.insert(Node::new(3), UnderNode(&node_1)).unwrap(); + + let ancestors = tree.ancestors(&root_id).unwrap(); + assert_eq!(ancestors.count(), 0); + + let data = [0]; + for (index, node) in tree.ancestors(&node_1).unwrap().enumerate() { + assert_eq!(node.data(), &data[index]); + } + + let data = [1, 0]; + for (index, node) in tree.ancestors(&node_2).unwrap().enumerate() { + assert_eq!(node.data(), &data[index]); + } + + let data = [1, 0]; + for (index, node) in tree.ancestors(&node_3).unwrap().enumerate() { + assert_eq!(node.data(), &data[index]); + } + } + + #[test] + fn test_children() { + + let mut tree = Tree::new(); + + let root_id = tree.insert(Node::new(0), AsRoot).unwrap(); + let node_1 = tree.insert(Node::new(1), UnderNode(&root_id)).unwrap(); + let node_2 = tree.insert(Node::new(2), UnderNode(&node_1)).unwrap(); + let node_3 = tree.insert(Node::new(3), UnderNode(&node_1)).unwrap(); + + let data = [1]; + for (index, node) in tree.children(&root_id).unwrap().enumerate() { + assert_eq!(node.data(), &data[index]); + } + + let data = [2, 3]; + for (index, node) in tree.children(&node_1).unwrap().enumerate() { + assert_eq!(node.data(), &data[index]); + } + + let children = tree.children(&node_2).unwrap(); + assert_eq!(children.count(), 0); + + let children = tree.children(&node_3).unwrap(); + assert_eq!(children.count(), 0); + } +} \ No newline at end of file diff --git a/src/tree.rs b/src/tree/mod.rs similarity index 98% rename from src/tree.rs rename to src/tree/mod.rs index a3fbe74..d87181e 100644 --- a/src/tree.rs +++ b/src/tree/mod.rs @@ -1,3 +1,5 @@ +pub mod iterators; + use std::cmp::Ordering; use super::behaviors::RemoveBehavior; @@ -9,6 +11,8 @@ use super::Node; use super::NodeId; use super::MutableNode; use super::NodeIdError; +use self::iterators::Ancestors; +use self::iterators::Children; /// /// A `Tree` builder that provides more control over how a `Tree` is created. @@ -979,6 +983,26 @@ impl Tree { self.root.as_ref() } + pub fn ancestors(&self, node_id: &NodeId) -> Result, NodeIdError> { + let (is_valid, error) = self.is_valid_node_id(node_id); + if !is_valid { + return Err(error.expect( + "Tree::ancestors: Missing an error value but found an invalid NodeId.")); + } + + Ok(Ancestors::new(self, node_id.clone())) + } + + pub fn children(&self, node_id: &NodeId) -> Result, NodeIdError> { + let (is_valid, error) = self.is_valid_node_id(node_id); + if !is_valid { + return Err(error.expect( + "Tree::children: Missing an error value but found an invalid NodeId.")); + } + + Ok(Children::new(self, node_id.clone())) + } + // Nothing should make it past this function. // If there is a way for a NodeId to be invalid, it should be caught here. fn is_valid_node_id(&self, node_id: &NodeId) -> (bool, Option) { @@ -1134,6 +1158,10 @@ impl Tree { } } +trait IteratorNew<'a, T, I> { + fn new(tree: &'a Tree, node_id: NodeId) -> I; +} + #[cfg(test)] mod tree_builder_tests { use super::TreeBuilder; From c198c6a2971d7c6db4c3382434ae60008261e51a Mon Sep 17 00:00:00 2001 From: Ian Burns Date: Wed, 1 Feb 2017 21:50:42 -0600 Subject: [PATCH 02/26] add Id version of iterators. clean up a few use blocks --- src/behaviors.rs | 2 +- src/lib.rs | 2 + src/node.rs | 4 +- src/tree/iterators.rs | 117 +++++++++++++++++++++++++++++++++++++++--- src/tree/mod.rs | 32 ++++++++---- 5 files changed, 137 insertions(+), 20 deletions(-) diff --git a/src/behaviors.rs b/src/behaviors.rs index 12f0090..d166205 100644 --- a/src/behaviors.rs +++ b/src/behaviors.rs @@ -1,4 +1,4 @@ -use super::NodeId; +use NodeId; /// /// Describes the possible behaviors of the `Tree::remove_node` method. diff --git a/src/lib.rs b/src/lib.rs index 620a282..2481f5d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -91,7 +91,9 @@ pub use node::Node; pub use tree::TreeBuilder; pub use tree::Tree; pub use tree::iterators::Ancestors; +pub use tree::iterators::AncestorIds; pub use tree::iterators::Children; +pub use tree::iterators::ChildrenIds; /// /// An identifier used to differentiate between `Node`s within a `Tree`. diff --git a/src/node.rs b/src/node.rs index 9098405..3fbd832 100644 --- a/src/node.rs +++ b/src/node.rs @@ -1,5 +1,5 @@ -use super::NodeId; -use super::MutableNode; +use NodeId; +use MutableNode; /// /// A `Node` builder that provides more control over how a `Node` is created. diff --git a/src/tree/iterators.rs b/src/tree/iterators.rs index a2524c9..f79c49e 100644 --- a/src/tree/iterators.rs +++ b/src/tree/iterators.rs @@ -1,8 +1,9 @@ -use super::Tree; -use super::Node; -use super::NodeId; -use super::IteratorNew; +use std::slice::Iter; +use Tree; +use Node; +use NodeId; +use tree::IteratorNew; pub struct Ancestors<'a, T: 'a> { tree: &'a Tree, @@ -39,7 +40,35 @@ impl<'a, T> Iterator for Ancestors<'a, T> { } } -use std::slice::Iter; +pub struct AncestorIds<'a, T: 'a> { + tree: &'a Tree, + node_id: Option, +} + +impl<'a, T> IteratorNew<'a, T, AncestorIds<'a, T>> for AncestorIds<'a, T> { + fn new(tree: &'a Tree, node_id: NodeId) -> AncestorIds<'a, T> { + AncestorIds { + tree: tree, + node_id: Some(node_id), + } + } +} + +impl<'a, T> Iterator for AncestorIds<'a, T> { + type Item = &'a NodeId; + + fn next(&mut self) -> Option<&'a NodeId> { + if let Some(current_id) = self.node_id.clone() { + if let Some(parent_id) = self.tree.get_unsafe(¤t_id).parent() { + self.node_id = Some(parent_id.clone()); + return Some(parent_id); + } else { + self.node_id = None; + } + } + None + } +} pub struct Children<'a, T: 'a> { tree: &'a Tree, @@ -66,6 +95,26 @@ impl<'a, T> Iterator for Children<'a, T> { } } +pub struct ChildrenIds<'a> { + child_ids: Iter<'a, NodeId>, +} + +impl<'a, T> IteratorNew<'a, T, ChildrenIds<'a>> for ChildrenIds<'a> { + fn new(tree: &'a Tree, node_id: NodeId) -> ChildrenIds<'a> { + ChildrenIds { + child_ids: tree.get_unsafe(&node_id).children().as_slice().iter() + } + } +} + +impl<'a> Iterator for ChildrenIds<'a> { + type Item = &'a NodeId; + + fn next(&mut self) -> Option<&'a NodeId> { + self.child_ids.next() + } +} + #[cfg(test)] mod tests { @@ -102,6 +151,35 @@ mod tests { } } + #[test] + fn test_ancestor_ids() { + + let mut tree = Tree::new(); + + let root_id = tree.insert(Node::new(0), AsRoot).unwrap(); + let node_1 = tree.insert(Node::new(1), UnderNode(&root_id)).unwrap(); + let node_2 = tree.insert(Node::new(2), UnderNode(&node_1)).unwrap(); + let node_3 = tree.insert(Node::new(3), UnderNode(&node_1)).unwrap(); + + let ancestor_ids = tree.ancestor_ids(&root_id).unwrap(); + assert_eq!(ancestor_ids.count(), 0); + + let data = [0]; + for (index, node_id) in tree.ancestor_ids(&node_1).unwrap().enumerate() { + assert_eq!(tree.get(node_id).unwrap().data(), &data[index]); + } + + let data = [1, 0]; + for (index, node_id) in tree.ancestor_ids(&node_2).unwrap().enumerate() { + assert_eq!(tree.get(node_id).unwrap().data(), &data[index]); + } + + let data = [1, 0]; + for (index, node_id) in tree.ancestor_ids(&node_3).unwrap().enumerate() { + assert_eq!(tree.get(node_id).unwrap().data(), &data[index]); + } + } + #[test] fn test_children() { @@ -128,4 +206,31 @@ mod tests { let children = tree.children(&node_3).unwrap(); assert_eq!(children.count(), 0); } -} \ No newline at end of file + + #[test] + fn test_children_ids() { + + let mut tree = Tree::new(); + + let root_id = tree.insert(Node::new(0), AsRoot).unwrap(); + let node_1 = tree.insert(Node::new(1), UnderNode(&root_id)).unwrap(); + let node_2 = tree.insert(Node::new(2), UnderNode(&node_1)).unwrap(); + let node_3 = tree.insert(Node::new(3), UnderNode(&node_1)).unwrap(); + + let data = [1]; + for (index, node_id) in tree.children_ids(&root_id).unwrap().enumerate() { + assert_eq!(tree.get(node_id).unwrap().data(), &data[index]); + } + + let data = [2, 3]; + for (index, node_id) in tree.children_ids(&node_1).unwrap().enumerate() { + assert_eq!(tree.get(node_id).unwrap().data(), &data[index]); + } + + let children_ids = tree.children_ids(&node_2).unwrap(); + assert_eq!(children_ids.count(), 0); + + let children_ids = tree.children_ids(&node_3).unwrap(); + assert_eq!(children_ids.count(), 0); + } +} diff --git a/src/tree/mod.rs b/src/tree/mod.rs index d87181e..82f71a1 100644 --- a/src/tree/mod.rs +++ b/src/tree/mod.rs @@ -2,17 +2,7 @@ pub mod iterators; use std::cmp::Ordering; -use super::behaviors::RemoveBehavior; -use super::behaviors::MoveBehavior; -use super::behaviors::InsertBehavior; -use super::behaviors::SwapBehavior; -use super::snowflake::ProcessUniqueId; -use super::Node; -use super::NodeId; -use super::MutableNode; -use super::NodeIdError; -use self::iterators::Ancestors; -use self::iterators::Children; +use super::*; /// /// A `Tree` builder that provides more control over how a `Tree` is created. @@ -993,6 +983,16 @@ impl Tree { Ok(Ancestors::new(self, node_id.clone())) } + pub fn ancestor_ids(&self, node_id: &NodeId) -> Result, NodeIdError> { + let (is_valid, error) = self.is_valid_node_id(node_id); + if !is_valid { + return Err(error.expect( + "Tree::ancestor_ids: Missing an error value but found an invalid NodeId.")); + } + + Ok(AncestorIds::new(self, node_id.clone())) + } + pub fn children(&self, node_id: &NodeId) -> Result, NodeIdError> { let (is_valid, error) = self.is_valid_node_id(node_id); if !is_valid { @@ -1003,6 +1003,16 @@ impl Tree { Ok(Children::new(self, node_id.clone())) } + pub fn children_ids(&self, node_id: &NodeId) -> Result { + let (is_valid, error) = self.is_valid_node_id(node_id); + if !is_valid { + return Err(error.expect( + "Tree::children_ids: Missing an error value but found an invalid NodeId.")); + } + + Ok(ChildrenIds::new(self, node_id.clone())) + } + // Nothing should make it past this function. // If there is a way for a NodeId to be invalid, it should be caught here. fn is_valid_node_id(&self, node_id: &NodeId) -> (bool, Option) { From 4bc1c44ada35756b9b2b7da7fb4ba94f0e9859a8 Mon Sep 17 00:00:00 2001 From: Ian Burns Date: Wed, 1 Feb 2017 21:52:20 -0600 Subject: [PATCH 03/26] run cargo fmt --- src/tree/iterators.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/tree/iterators.rs b/src/tree/iterators.rs index f79c49e..cf682b7 100644 --- a/src/tree/iterators.rs +++ b/src/tree/iterators.rs @@ -79,7 +79,7 @@ impl<'a, T> IteratorNew<'a, T, Children<'a, T>> for Children<'a, T> { fn new(tree: &'a Tree, node_id: NodeId) -> Children<'a, T> { Children { tree: tree, - child_ids: tree.get_unsafe(&node_id).children().as_slice().iter() + child_ids: tree.get_unsafe(&node_id).children().as_slice().iter(), } } } @@ -101,9 +101,7 @@ pub struct ChildrenIds<'a> { impl<'a, T> IteratorNew<'a, T, ChildrenIds<'a>> for ChildrenIds<'a> { fn new(tree: &'a Tree, node_id: NodeId) -> ChildrenIds<'a> { - ChildrenIds { - child_ids: tree.get_unsafe(&node_id).children().as_slice().iter() - } + ChildrenIds { child_ids: tree.get_unsafe(&node_id).children().as_slice().iter() } } } From a2008f112bb2e9ff57a1cf6d02942dbe4022d3d1 Mon Sep 17 00:00:00 2001 From: Ian Burns Date: Wed, 1 Feb 2017 22:06:26 -0600 Subject: [PATCH 04/26] add some docs for Iterator structs --- src/tree/iterators.rs | 26 ++++++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/src/tree/iterators.rs b/src/tree/iterators.rs index cf682b7..635c5c1 100644 --- a/src/tree/iterators.rs +++ b/src/tree/iterators.rs @@ -5,6 +5,12 @@ use Node; use NodeId; use tree::IteratorNew; +/// +/// An Iterator over the ancestors of a `Node`. +/// +/// Iterates over the ancestor `Node`s of a given `Node` in the `Tree`. Each call to `next` will +/// return an immutable reference to the next `Node` up the `Tree`. +/// pub struct Ancestors<'a, T: 'a> { tree: &'a Tree, node_id: Option, @@ -40,6 +46,11 @@ impl<'a, T> Iterator for Ancestors<'a, T> { } } +/// +/// An Iterator over the ancestors of a `Node`. +/// +/// Iterates over `NodeId`s instead of over the `Node`s themselves. +/// pub struct AncestorIds<'a, T: 'a> { tree: &'a Tree, node_id: Option, @@ -70,6 +81,12 @@ impl<'a, T> Iterator for AncestorIds<'a, T> { } } +/// +/// An Iterator over the children of a `Node`. +/// +/// Iterates over the child `Node`s of a given `Node` in the `Tree`. Each call to `next` will +/// return an immutable reference to the next child `Node`. +/// pub struct Children<'a, T: 'a> { tree: &'a Tree, child_ids: Iter<'a, NodeId>, @@ -95,6 +112,11 @@ impl<'a, T> Iterator for Children<'a, T> { } } +/// +/// An Iterator over the children of a `Node`. +/// +/// Iterates over `NodeId`s instead of over the `Node`s themselves. +/// pub struct ChildrenIds<'a> { child_ids: Iter<'a, NodeId>, } @@ -122,7 +144,6 @@ mod tests { #[test] fn test_ancestors() { - let mut tree = Tree::new(); let root_id = tree.insert(Node::new(0), AsRoot).unwrap(); @@ -151,7 +172,6 @@ mod tests { #[test] fn test_ancestor_ids() { - let mut tree = Tree::new(); let root_id = tree.insert(Node::new(0), AsRoot).unwrap(); @@ -180,7 +200,6 @@ mod tests { #[test] fn test_children() { - let mut tree = Tree::new(); let root_id = tree.insert(Node::new(0), AsRoot).unwrap(); @@ -207,7 +226,6 @@ mod tests { #[test] fn test_children_ids() { - let mut tree = Tree::new(); let root_id = tree.insert(Node::new(0), AsRoot).unwrap(); From 3ebd6b2d6c547b9df347e3527a9a368e95fdd621 Mon Sep 17 00:00:00 2001 From: Ian Burns Date: Wed, 1 Feb 2017 22:14:44 -0600 Subject: [PATCH 05/26] fix bad use block --- src/tree/mod.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/tree/mod.rs b/src/tree/mod.rs index 82f71a1..629e0d9 100644 --- a/src/tree/mod.rs +++ b/src/tree/mod.rs @@ -3,6 +3,8 @@ pub mod iterators; use std::cmp::Ordering; use super::*; +use super::snowflake::ProcessUniqueId; +use super::MutableNode; /// /// A `Tree` builder that provides more control over how a `Tree` is created. From 20d97c4a044917b9e7218b0170c052a3be25af97 Mon Sep 17 00:00:00 2001 From: Ian Burns Date: Wed, 1 Feb 2017 22:40:13 -0600 Subject: [PATCH 06/26] add more docs --- src/tree/mod.rs | 78 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 78 insertions(+) diff --git a/src/tree/mod.rs b/src/tree/mod.rs index 629e0d9..e89a453 100644 --- a/src/tree/mod.rs +++ b/src/tree/mod.rs @@ -975,6 +975,26 @@ impl Tree { self.root.as_ref() } + /// + /// Returns an `Ancestors` iterator (or a `NodeIdError` if one occurred). + /// + /// Allows iteration over the ancestor `Node`s of a given `NodeId` directly instead of having + /// to call `tree.get(...)` with a `NodeId` each time. + /// + /// ``` + /// use id_tree::*; + /// use id_tree::InsertBehavior::*; + /// + /// let mut tree: Tree = Tree::new(); + /// let root_id = tree.insert(Node::new(0), AsRoot).unwrap(); + /// let node_1 = tree.insert(Node::new(1), UnderNode(&root_id)).unwrap(); + /// + /// let mut ancestors = tree.ancestors(&node_1).unwrap(); + /// + /// assert_eq!(ancestors.next().unwrap().data(), &0); + /// assert!(ancestors.next().is_none()); + /// ``` + /// pub fn ancestors(&self, node_id: &NodeId) -> Result, NodeIdError> { let (is_valid, error) = self.is_valid_node_id(node_id); if !is_valid { @@ -985,6 +1005,25 @@ impl Tree { Ok(Ancestors::new(self, node_id.clone())) } + /// + /// Returns an `AncestorIds` iterator (or a `NodeIdError` if one occurred). + /// + /// Allows iteration over the ancestor `NodeId`s of a given `NodeId`. + /// + /// ``` + /// use id_tree::*; + /// use id_tree::InsertBehavior::*; + /// + /// let mut tree: Tree = Tree::new(); + /// let root_id = tree.insert(Node::new(0), AsRoot).unwrap(); + /// let node_1 = tree.insert(Node::new(1), UnderNode(&root_id)).unwrap(); + /// + /// let mut ancestor_ids = tree.ancestor_ids(&node_1).unwrap(); + /// + /// assert_eq!(ancestor_ids.next().unwrap(), &root_id); + /// assert!(ancestor_ids.next().is_none()); + /// ``` + /// pub fn ancestor_ids(&self, node_id: &NodeId) -> Result, NodeIdError> { let (is_valid, error) = self.is_valid_node_id(node_id); if !is_valid { @@ -995,6 +1034,26 @@ impl Tree { Ok(AncestorIds::new(self, node_id.clone())) } + /// + /// Returns a `Children` iterator (or a `NodeIdError` if one occurred). + /// + /// Allows iteration over the child `Node`s of a given `NodeId` directly instead of having + /// to call `tree.get(...)` with a `NodeId` each time. + /// + /// ``` + /// use id_tree::*; + /// use id_tree::InsertBehavior::*; + /// + /// let mut tree: Tree = Tree::new(); + /// let root_id = tree.insert(Node::new(0), AsRoot).unwrap(); + /// tree.insert(Node::new(1), UnderNode(&root_id)).unwrap(); + /// + /// let mut children = tree.children(&root_id).unwrap(); + /// + /// assert_eq!(children.next().unwrap().data(), &1); + /// assert!(children.next().is_none()); + /// ``` + /// pub fn children(&self, node_id: &NodeId) -> Result, NodeIdError> { let (is_valid, error) = self.is_valid_node_id(node_id); if !is_valid { @@ -1005,6 +1064,25 @@ impl Tree { Ok(Children::new(self, node_id.clone())) } + /// + /// Returns a `ChildrenIds` iterator (or a `NodeIdError` if one occurred). + /// + /// Allows iteration over the child `NodeId`s of a given `NodeId`. + /// + /// ``` + /// use id_tree::*; + /// use id_tree::InsertBehavior::*; + /// + /// let mut tree: Tree = Tree::new(); + /// let root_id = tree.insert(Node::new(0), AsRoot).unwrap(); + /// let node_1 = tree.insert(Node::new(1), UnderNode(&root_id)).unwrap(); + /// + /// let mut children_ids = tree.children_ids(&root_id).unwrap(); + /// + /// assert_eq!(children_ids.next().unwrap(), &node_1); + /// assert!(children_ids.next().is_none()); + /// ``` + /// pub fn children_ids(&self, node_id: &NodeId) -> Result { let (is_valid, error) = self.is_valid_node_id(node_id); if !is_valid { From a28c680ce673c57f4311605d91e46899146d5f09 Mon Sep 17 00:00:00 2001 From: Ian Burns Date: Thu, 2 Feb 2017 14:09:01 -0600 Subject: [PATCH 07/26] WiP: add a few more tests --- tests/error_tests.rs | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/tests/error_tests.rs b/tests/error_tests.rs index 6b9272e..0eb5ae6 100644 --- a/tests/error_tests.rs +++ b/tests/error_tests.rs @@ -235,3 +235,35 @@ fn test_swap_sub_trees_of_different_trees() { let error = result.err().unwrap(); assert_eq!(error, NodeIdError::InvalidNodeIdForTree); } + +#[test] +fn test_ancestors_different_trees() { + let mut a = Tree::new(); + let b = Tree::::new(); + + let root_id = a.insert(Node::new(1), InsertBehavior::AsRoot).unwrap(); + + // note usage of `b` instead of `a` + let ancestors = b.ancestors(&root_id); + + assert!(ancestors.is_err()); + let error = ancestors.err().unwrap(); + assert_eq!(error, NodeIdError::InvalidNodeIdForTree); +} + +#[test] +fn test_ancestors_old_id() { + let mut a = Tree::new(); + + let root_id = a.insert(Node::new(1), InsertBehavior::AsRoot).unwrap(); + // `.clone()` required to get this error + let root_id_clone = root_id.clone(); + let _ = a.remove_node(root_id, RemoveBehavior::DropChildren).unwrap(); + + // note usage of cloned `NodeId` + let ancestors = a.ancestors(&root_id_clone); + + assert!(ancestors.is_err()); + let error = ancestors.err().unwrap(); + assert_eq!(error, NodeIdError::NodeIdNoLongerValid); +} From 06cc161ba83583ad0fd129d5fcf44101984ac0db Mon Sep 17 00:00:00 2001 From: Ian Burns Date: Thu, 2 Feb 2017 16:48:44 -0600 Subject: [PATCH 08/26] remove some extra spaces --- src/tree/iterators.rs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/tree/iterators.rs b/src/tree/iterators.rs index 635c5c1..164c843 100644 --- a/src/tree/iterators.rs +++ b/src/tree/iterators.rs @@ -30,13 +30,9 @@ impl<'a, T> Iterator for Ancestors<'a, T> { fn next(&mut self) -> Option<&'a Node> { if let Some(current_id) = self.node_id.clone() { - if let Some(parent_id) = self.tree.get_unsafe(¤t_id).parent() { - let parent = self.tree.get_unsafe(&parent_id); - self.node_id = Some(parent_id.clone()); - return Some(parent); } else { self.node_id = None; From c60c59e178ea7da5cd414ef4ae31e8a0e3db4320 Mon Sep 17 00:00:00 2001 From: Ian Burns Date: Thu, 9 Feb 2017 11:24:08 -0600 Subject: [PATCH 09/26] add PreOrderTraversal (still need docs for it) --- src/lib.rs | 1 + src/tree/iterators.rs | 75 +++++++++++++++++++++++++++++++++++++++++++ src/tree/mod.rs | 10 ++++++ 3 files changed, 86 insertions(+) diff --git a/src/lib.rs b/src/lib.rs index 2481f5d..470e631 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -94,6 +94,7 @@ pub use tree::iterators::Ancestors; pub use tree::iterators::AncestorIds; pub use tree::iterators::Children; pub use tree::iterators::ChildrenIds; +pub use tree::iterators::PreOrderTraversal; /// /// An identifier used to differentiate between `Node`s within a `Tree`. diff --git a/src/tree/iterators.rs b/src/tree/iterators.rs index 164c843..0faa005 100644 --- a/src/tree/iterators.rs +++ b/src/tree/iterators.rs @@ -131,6 +131,51 @@ impl<'a> Iterator for ChildrenIds<'a> { } } +pub struct PreOrderTraversal<'a, T: 'a> { + tree: &'a Tree, + node_id: Option, + future_data: Vec<&'a NodeId>, +} + +impl<'a, T> IteratorNew<'a, T, PreOrderTraversal<'a, T>> for PreOrderTraversal<'a, T> { + fn new(tree: &'a Tree, node_id: NodeId) -> PreOrderTraversal { + PreOrderTraversal { + tree: tree, + node_id: Some(node_id), + // over allocating, but all at once instead of re-sizing and re-allocating as we go + future_data: Vec::with_capacity(tree.nodes.capacity()), + } + } +} + +impl<'a, T> Iterator for PreOrderTraversal<'a, T> { + type Item = &'a Node; + + fn next(&mut self) -> Option<&'a Node> { + if let Some(node_id) = self.node_id.clone() { + + let node = self.tree.get_unsafe(&node_id); + + if !node.children().is_empty() { + let mut children_ids = node.children().iter(); + + // take the first child and set it as the next one to be processed + self.node_id = children_ids.next().cloned(); + + // reverse it because we will pop to get the next one later. + let mut new_ids: Vec<&NodeId> = children_ids.rev().collect(); + + self.future_data.append(&mut new_ids); + } else { + self.node_id = self.future_data.pop().cloned(); + } + + return Some(node); + } + None + } +} + #[cfg(test)] mod tests { @@ -245,4 +290,34 @@ mod tests { let children_ids = tree.children_ids(&node_3).unwrap(); assert_eq!(children_ids.count(), 0); } + + #[test] + fn test_post_order_traversal() { + let mut tree = Tree::new(); + + let root_id = tree.insert(Node::new(0), AsRoot).unwrap(); + let node_1 = tree.insert(Node::new(1), UnderNode(&root_id)).unwrap(); + let node_2 = tree.insert(Node::new(2), UnderNode(&node_1)).unwrap(); + let node_3 = tree.insert(Node::new(3), UnderNode(&node_1)).unwrap(); + + let data = [0, 1, 2, 3]; + for (index, node) in tree.pre_order_traversal(&root_id).unwrap().enumerate() { + assert_eq!(node.data(), &data[index]); + } + + let data = [1, 2, 3]; + for (index, node) in tree.pre_order_traversal(&node_1).unwrap().enumerate() { + assert_eq!(node.data(), &data[index]); + } + + let data = [2]; + for (index, node) in tree.pre_order_traversal(&node_2).unwrap().enumerate() { + assert_eq!(node.data(), &data[index]); + } + + let data = [3]; + for (index, node) in tree.pre_order_traversal(&node_3).unwrap().enumerate() { + assert_eq!(node.data(), &data[index]); + } + } } diff --git a/src/tree/mod.rs b/src/tree/mod.rs index e89a453..31723ac 100644 --- a/src/tree/mod.rs +++ b/src/tree/mod.rs @@ -1093,6 +1093,16 @@ impl Tree { Ok(ChildrenIds::new(self, node_id.clone())) } + pub fn pre_order_traversal(&self, node_id: &NodeId) -> Result, NodeIdError> { + let (is_valid, error) = self.is_valid_node_id(node_id); + if !is_valid { + return Err(error.expect( + "Tree::pre_order_traversal: Missing an error value but found an invalid NodeId.")); + } + + Ok(PreOrderTraversal::new(self, node_id.clone())) + } + // Nothing should make it past this function. // If there is a way for a NodeId to be invalid, it should be caught here. fn is_valid_node_id(&self, node_id: &NodeId) -> (bool, Option) { From 61d3b79fd8649e724a0792e1bf35d0418f5174a5 Mon Sep 17 00:00:00 2001 From: Ian Burns Date: Thu, 9 Feb 2017 12:39:14 -0600 Subject: [PATCH 10/26] add PostOrderTraversal (still need docs for it) --- src/lib.rs | 1 + src/tree/iterators.rs | 88 ++++++++++++++++++++++++++++++++++++++++--- src/tree/mod.rs | 16 +++++++- 3 files changed, 98 insertions(+), 7 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 470e631..fc0dcb5 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -95,6 +95,7 @@ pub use tree::iterators::AncestorIds; pub use tree::iterators::Children; pub use tree::iterators::ChildrenIds; pub use tree::iterators::PreOrderTraversal; +pub use tree::iterators::PostOrderTraversal; /// /// An identifier used to differentiate between `Node`s within a `Tree`. diff --git a/src/tree/iterators.rs b/src/tree/iterators.rs index 0faa005..7b0128d 100644 --- a/src/tree/iterators.rs +++ b/src/tree/iterators.rs @@ -176,6 +176,54 @@ impl<'a, T> Iterator for PreOrderTraversal<'a, T> { } } +pub struct PostOrderTraversal<'a, T: 'a> { + tree: &'a Tree, + index: usize, + data: Vec, +} + +impl<'a, T> PostOrderTraversal<'a, T> { + fn process_nodes<'b>(&mut self, starting_id: NodeId) { + let node = self.tree.get_unsafe(&starting_id); + + for child_id in node.children() { + self.process_nodes(child_id.clone()); + } + + self.data.push(starting_id); + } +} + +impl<'a, T> IteratorNew<'a, T, PostOrderTraversal<'a, T>> for PostOrderTraversal<'a, T> { + fn new(tree: &'a Tree, node_id: NodeId) -> PostOrderTraversal { + let mut traversal = PostOrderTraversal { + tree: tree, + index: 0, + // over allocating, but all at once instead of re-sizing and re-allocating as we go + data: Vec::with_capacity(tree.nodes.capacity()), + }; + + traversal.process_nodes(node_id); + traversal + } +} + +impl<'a, T> Iterator for PostOrderTraversal<'a, T> { + type Item = &'a Node; + + fn next(&mut self) -> Option<&'a Node> { + + let id = self.data.get(self.index); + self.index += 1; + + if let Some(node_id) = id { + return Some(self.tree.get_unsafe(node_id)); + } + + None + } +} + #[cfg(test)] mod tests { @@ -292,7 +340,7 @@ mod tests { } #[test] - fn test_post_order_traversal() { + fn test_pre_order_traversal() { let mut tree = Tree::new(); let root_id = tree.insert(Node::new(0), AsRoot).unwrap(); @@ -301,22 +349,52 @@ mod tests { let node_3 = tree.insert(Node::new(3), UnderNode(&node_1)).unwrap(); let data = [0, 1, 2, 3]; - for (index, node) in tree.pre_order_traversal(&root_id).unwrap().enumerate() { + for (index, node) in tree.traverse_pre_order(&root_id).unwrap().enumerate() { assert_eq!(node.data(), &data[index]); } let data = [1, 2, 3]; - for (index, node) in tree.pre_order_traversal(&node_1).unwrap().enumerate() { + for (index, node) in tree.traverse_pre_order(&node_1).unwrap().enumerate() { + assert_eq!(node.data(), &data[index]); + } + + let data = [2]; + for (index, node) in tree.traverse_pre_order(&node_2).unwrap().enumerate() { + assert_eq!(node.data(), &data[index]); + } + + let data = [3]; + for (index, node) in tree.traverse_pre_order(&node_3).unwrap().enumerate() { + assert_eq!(node.data(), &data[index]); + } + } + + #[test] + fn test_post_order_traversal() { + let mut tree = Tree::new(); + + let root_id = tree.insert(Node::new(0), AsRoot).unwrap(); + let node_1 = tree.insert(Node::new(1), UnderNode(&root_id)).unwrap(); + let node_2 = tree.insert(Node::new(2), UnderNode(&node_1)).unwrap(); + let node_3 = tree.insert(Node::new(3), UnderNode(&node_1)).unwrap(); + + let data = [2, 3, 1, 0]; + for (index, node) in tree.traverse_post_order(&root_id).unwrap().enumerate() { + assert_eq!(node.data(), &data[index]); + } + + let data = [2, 3, 1]; + for (index, node) in tree.traverse_post_order(&node_1).unwrap().enumerate() { assert_eq!(node.data(), &data[index]); } let data = [2]; - for (index, node) in tree.pre_order_traversal(&node_2).unwrap().enumerate() { + for (index, node) in tree.traverse_post_order(&node_2).unwrap().enumerate() { assert_eq!(node.data(), &data[index]); } let data = [3]; - for (index, node) in tree.pre_order_traversal(&node_3).unwrap().enumerate() { + for (index, node) in tree.traverse_post_order(&node_3).unwrap().enumerate() { assert_eq!(node.data(), &data[index]); } } diff --git a/src/tree/mod.rs b/src/tree/mod.rs index 31723ac..50ba185 100644 --- a/src/tree/mod.rs +++ b/src/tree/mod.rs @@ -1093,16 +1093,28 @@ impl Tree { Ok(ChildrenIds::new(self, node_id.clone())) } - pub fn pre_order_traversal(&self, node_id: &NodeId) -> Result, NodeIdError> { + pub fn traverse_pre_order(&self, node_id: &NodeId) + -> Result, NodeIdError> { let (is_valid, error) = self.is_valid_node_id(node_id); if !is_valid { return Err(error.expect( - "Tree::pre_order_traversal: Missing an error value but found an invalid NodeId.")); + "Tree::traverse_pre_order: Missing an error value but found an invalid NodeId.")); } Ok(PreOrderTraversal::new(self, node_id.clone())) } + pub fn traverse_post_order(&self, node_id: &NodeId) + -> Result, NodeIdError> { + let (is_valid, error) = self.is_valid_node_id(node_id); + if !is_valid { + return Err(error.expect( + "Tree::traverse_post_order: Missing an error value but found an invalid NodeId.")); + } + + Ok(PostOrderTraversal::new(self, node_id.clone())) + } + // Nothing should make it past this function. // If there is a way for a NodeId to be invalid, it should be caught here. fn is_valid_node_id(&self, node_id: &NodeId) -> (bool, Option) { From e543eb088d9ba92dd83ccfea1806e5d2d8a2b018 Mon Sep 17 00:00:00 2001 From: Ian Burns Date: Thu, 9 Feb 2017 12:41:01 -0600 Subject: [PATCH 11/26] fix formatting --- src/tree/mod.rs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/tree/mod.rs b/src/tree/mod.rs index 50ba185..778f963 100644 --- a/src/tree/mod.rs +++ b/src/tree/mod.rs @@ -1093,8 +1093,11 @@ impl Tree { Ok(ChildrenIds::new(self, node_id.clone())) } + #[cfg_attr(rustfmt, rustfmt_skip)] + // todo: remove this if https://github.com/rust-lang-nursery/rustfmt/issues/1260 is resolved pub fn traverse_pre_order(&self, node_id: &NodeId) - -> Result, NodeIdError> { + -> Result, NodeIdError> + { let (is_valid, error) = self.is_valid_node_id(node_id); if !is_valid { return Err(error.expect( @@ -1104,8 +1107,11 @@ impl Tree { Ok(PreOrderTraversal::new(self, node_id.clone())) } + #[cfg_attr(rustfmt, rustfmt_skip)] + // todo: remove this if https://github.com/rust-lang-nursery/rustfmt/issues/1260 is resolved pub fn traverse_post_order(&self, node_id: &NodeId) - -> Result, NodeIdError> { + -> Result, NodeIdError> + { let (is_valid, error) = self.is_valid_node_id(node_id); if !is_valid { return Err(error.expect( From 89768e782e6f230cef2278814e7137cd4e0b4f0c Mon Sep 17 00:00:00 2001 From: Ian Burns Date: Thu, 9 Feb 2017 13:18:50 -0600 Subject: [PATCH 12/26] update basic example. --- examples/basic.rs | 27 +++++++-------------------- 1 file changed, 7 insertions(+), 20 deletions(-) diff --git a/examples/basic.rs b/examples/basic.rs index 4fa74f3..9c1a338 100644 --- a/examples/basic.rs +++ b/examples/basic.rs @@ -21,30 +21,17 @@ fn main() { tree.insert(Node::new(4), UnderNode(&child_id)).unwrap(); println!("Post-order:"); - print_post_order(&tree, &root_id); - println!(); - - println!("Pre-order:"); - print_pre_order(&tree, &root_id); - println!(); -} - -fn print_pre_order(tree: &Tree, node_id: &NodeId) { - let node_ref = tree.get(node_id).unwrap(); - print!("{}, ", node_ref.data()); - - for child_id in node_ref.children() { - print_pre_order(tree, &child_id); + for node in tree.traverse_post_order(&root_id).unwrap() { + print!("{}, ", node.data()); } -} -fn print_post_order(tree: &Tree, node_id: &NodeId) { - let node_ref = tree.get(node_id).unwrap(); + println!(); + println!("Pre-order:"); - for child_id in node_ref.children() { - print_post_order(tree, &child_id); + for node in tree.traverse_pre_order(&root_id).unwrap() { + print!("{}, ", node.data()); } - print!("{}, ", node_ref.data()); + println!(); } From 42a68c16f8b0eb313056ff654b3ca0f27f65a7e1 Mon Sep 17 00:00:00 2001 From: Ian Date: Thu, 9 Feb 2017 23:51:45 -0600 Subject: [PATCH 13/26] add struct docs --- src/tree/iterators.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/tree/iterators.rs b/src/tree/iterators.rs index 7b0128d..c57b8c8 100644 --- a/src/tree/iterators.rs +++ b/src/tree/iterators.rs @@ -131,6 +131,12 @@ impl<'a> Iterator for ChildrenIds<'a> { } } +/// +/// An Iterator over the sub-tree relative to a given `Node`. +/// +/// Iterates over all of the `Node`s in the sub-tree of a given `Node` in the `Tree`. Each call to +/// `next` will return an immutable reference to the next `Node` in Pre-Order Traversal order. +/// pub struct PreOrderTraversal<'a, T: 'a> { tree: &'a Tree, node_id: Option, @@ -176,6 +182,12 @@ impl<'a, T> Iterator for PreOrderTraversal<'a, T> { } } +/// +/// An Iterator over the sub-tree relative to a given `Node`. +/// +/// Iterates over all of the `Node`s in the sub-tree of a given `Node` in the `Tree`. Each call to +/// `next` will return an immutable reference to the next `Node` in Post-Order Traversal order. +/// pub struct PostOrderTraversal<'a, T: 'a> { tree: &'a Tree, index: usize, From 5b31ea69504d465972ca5781f1acbe4c71ece5b4 Mon Sep 17 00:00:00 2001 From: Ian Date: Fri, 10 Feb 2017 00:58:55 -0600 Subject: [PATCH 14/26] add more docs. --- src/tree/mod.rs | 42 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/src/tree/mod.rs b/src/tree/mod.rs index 778f963..1b0a898 100644 --- a/src/tree/mod.rs +++ b/src/tree/mod.rs @@ -1093,6 +1093,27 @@ impl Tree { Ok(ChildrenIds::new(self, node_id.clone())) } + /// + /// Returns a `PreOrderTraversal` iterator (or a `NodeIdError` if one occurred). + /// + /// Allows iteration over all of the `Node`s in the sub-tree below a given `Node`. This + /// iterator will always include that sub-tree "root" specified by the `NodeId` given. + /// + /// ``` + /// use id_tree::*; + /// use id_tree::InsertBehavior::*; + /// + /// let mut tree: Tree = Tree::new(); + /// let root_id = tree.insert(Node::new(0), AsRoot).unwrap(); + /// let node_1 = tree.insert(Node::new(1), UnderNode(&root_id)).unwrap(); + /// + /// let mut nodes = tree.traverse_pre_order(&root_id).unwrap(); + /// + /// assert_eq!(nodes.next().unwrap().data(), &0); + /// assert_eq!(nodes.next().unwrap().data(), &1); + /// assert!(nodes.next().is_none()); + /// ``` + /// #[cfg_attr(rustfmt, rustfmt_skip)] // todo: remove this if https://github.com/rust-lang-nursery/rustfmt/issues/1260 is resolved pub fn traverse_pre_order(&self, node_id: &NodeId) @@ -1107,6 +1128,27 @@ impl Tree { Ok(PreOrderTraversal::new(self, node_id.clone())) } + /// + /// Returns a `PostOrderTraversal` iterator (or a `NodeIdError` if one occurred). + /// + /// Allows iteration over all of the `Node`s in the sub-tree below a given `Node`. This + /// iterator will always include that sub-tree "root" specified by the `NodeId` given. + /// + /// ``` + /// use id_tree::*; + /// use id_tree::InsertBehavior::*; + /// + /// let mut tree: Tree = Tree::new(); + /// let root_id = tree.insert(Node::new(0), AsRoot).unwrap(); + /// let node_1 = tree.insert(Node::new(1), UnderNode(&root_id)).unwrap(); + /// + /// let mut nodes = tree.traverse_post_order(&root_id).unwrap(); + /// + /// assert_eq!(nodes.next().unwrap().data(), &1); + /// assert_eq!(nodes.next().unwrap().data(), &0); + /// assert!(nodes.next().is_none()); + /// ``` + /// #[cfg_attr(rustfmt, rustfmt_skip)] // todo: remove this if https://github.com/rust-lang-nursery/rustfmt/issues/1260 is resolved pub fn traverse_post_order(&self, node_id: &NodeId) From 20a4a68459fd1b0d29ba544b64e76c02f9e8a2a3 Mon Sep 17 00:00:00 2001 From: Ian Burns Date: Fri, 10 Feb 2017 08:45:26 -0600 Subject: [PATCH 15/26] run cargo fmt --- src/tree/mod.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/tree/mod.rs b/src/tree/mod.rs index 1b0a898..de757ed 100644 --- a/src/tree/mod.rs +++ b/src/tree/mod.rs @@ -1093,7 +1093,6 @@ impl Tree { Ok(ChildrenIds::new(self, node_id.clone())) } - /// /// Returns a `PreOrderTraversal` iterator (or a `NodeIdError` if one occurred). /// /// Allows iteration over all of the `Node`s in the sub-tree below a given `Node`. This @@ -1128,7 +1127,6 @@ impl Tree { Ok(PreOrderTraversal::new(self, node_id.clone())) } - /// /// Returns a `PostOrderTraversal` iterator (or a `NodeIdError` if one occurred). /// /// Allows iteration over all of the `Node`s in the sub-tree below a given `Node`. This From c661f06d457a193aede488bbbb03ad53ac01b77e Mon Sep 17 00:00:00 2001 From: Ian Burns Date: Fri, 17 Feb 2017 10:23:49 -0600 Subject: [PATCH 16/26] add more iterator tests --- tests/error_tests.rs | 96 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 96 insertions(+) diff --git a/tests/error_tests.rs b/tests/error_tests.rs index 0eb5ae6..34a5525 100644 --- a/tests/error_tests.rs +++ b/tests/error_tests.rs @@ -267,3 +267,99 @@ fn test_ancestors_old_id() { let error = ancestors.err().unwrap(); assert_eq!(error, NodeIdError::NodeIdNoLongerValid); } + +#[test] +fn test_ancestor_ids_different_trees() { + let mut a = Tree::new(); + let b = Tree::::new(); + + let root_id = a.insert(Node::new(1), InsertBehavior::AsRoot).unwrap(); + + // note usage of `b` instead of `a` + let ancestors = b.ancestor_ids(&root_id); + + assert!(ancestors.is_err()); + let error = ancestors.err().unwrap(); + assert_eq!(error, NodeIdError::InvalidNodeIdForTree); +} + +#[test] +fn test_ancestor_ids_old_id() { + let mut a = Tree::new(); + + let root_id = a.insert(Node::new(1), InsertBehavior::AsRoot).unwrap(); + // `.clone()` required to get this error + let root_id_clone = root_id.clone(); + let _ = a.remove_node(root_id, RemoveBehavior::DropChildren).unwrap(); + + // note usage of cloned `NodeId` + let ancestors = a.ancestor_ids(&root_id_clone); + + assert!(ancestors.is_err()); + let error = ancestors.err().unwrap(); + assert_eq!(error, NodeIdError::NodeIdNoLongerValid); +} + +#[test] +fn test_children_different_trees() { + let mut a = Tree::new(); + let b = Tree::::new(); + + let root_id = a.insert(Node::new(1), InsertBehavior::AsRoot).unwrap(); + + // note usage of `b` instead of `a` + let ancestors = b.children(&root_id); + + assert!(ancestors.is_err()); + let error = ancestors.err().unwrap(); + assert_eq!(error, NodeIdError::InvalidNodeIdForTree); +} + +#[test] +fn test_children_old_id() { + let mut a = Tree::new(); + + let root_id = a.insert(Node::new(1), InsertBehavior::AsRoot).unwrap(); + // `.clone()` required to get this error + let root_id_clone = root_id.clone(); + let _ = a.remove_node(root_id, RemoveBehavior::DropChildren).unwrap(); + + // note usage of cloned `NodeId` + let ancestors = a.children(&root_id_clone); + + assert!(ancestors.is_err()); + let error = ancestors.err().unwrap(); + assert_eq!(error, NodeIdError::NodeIdNoLongerValid); +} + +#[test] +fn test_children_ids_different_trees() { + let mut a = Tree::new(); + let b = Tree::::new(); + + let root_id = a.insert(Node::new(1), InsertBehavior::AsRoot).unwrap(); + + // note usage of `b` instead of `a` + let ancestors = b.children_ids(&root_id); + + assert!(ancestors.is_err()); + let error = ancestors.err().unwrap(); + assert_eq!(error, NodeIdError::InvalidNodeIdForTree); +} + +#[test] +fn test_children_ids_old_id() { + let mut a = Tree::new(); + + let root_id = a.insert(Node::new(1), InsertBehavior::AsRoot).unwrap(); + // `.clone()` required to get this error + let root_id_clone = root_id.clone(); + let _ = a.remove_node(root_id, RemoveBehavior::DropChildren).unwrap(); + + // note usage of cloned `NodeId` + let ancestors = a.children_ids(&root_id_clone); + + assert!(ancestors.is_err()); + let error = ancestors.err().unwrap(); + assert_eq!(error, NodeIdError::NodeIdNoLongerValid); +} From a5eb1c64bbe346f8b786c72f39b96c7482f82507 Mon Sep 17 00:00:00 2001 From: Ian Burns Date: Sat, 18 Feb 2017 10:55:16 -0600 Subject: [PATCH 17/26] remove unnecessary lifetime --- src/tree/iterators.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tree/iterators.rs b/src/tree/iterators.rs index c57b8c8..1168110 100644 --- a/src/tree/iterators.rs +++ b/src/tree/iterators.rs @@ -195,7 +195,7 @@ pub struct PostOrderTraversal<'a, T: 'a> { } impl<'a, T> PostOrderTraversal<'a, T> { - fn process_nodes<'b>(&mut self, starting_id: NodeId) { + fn process_nodes(&mut self, starting_id: NodeId) { let node = self.tree.get_unsafe(&starting_id); for child_id in node.children() { From ce51cad775f427028ca1495f06480e26f26c45b9 Mon Sep 17 00:00:00 2001 From: Ian Burns Date: Sat, 18 Feb 2017 11:14:55 -0600 Subject: [PATCH 18/26] get rid of extra usize and bounds checking --- src/tree/iterators.rs | 35 +++++++++++++++++------------------ 1 file changed, 17 insertions(+), 18 deletions(-) diff --git a/src/tree/iterators.rs b/src/tree/iterators.rs index 1168110..1098bb4 100644 --- a/src/tree/iterators.rs +++ b/src/tree/iterators.rs @@ -1,4 +1,5 @@ use std::slice::Iter; +use std::vec::IntoIter; use Tree; use Node; @@ -190,33 +191,33 @@ impl<'a, T> Iterator for PreOrderTraversal<'a, T> { /// pub struct PostOrderTraversal<'a, T: 'a> { tree: &'a Tree, - index: usize, - data: Vec, + ids: IntoIter, } impl<'a, T> PostOrderTraversal<'a, T> { - fn process_nodes(&mut self, starting_id: NodeId) { - let node = self.tree.get_unsafe(&starting_id); + fn process_nodes(starting_id: NodeId, tree: &Tree, ids: &mut Vec) { + let node = tree.get_unsafe(&starting_id); for child_id in node.children() { - self.process_nodes(child_id.clone()); + PostOrderTraversal::process_nodes(child_id.clone(), tree, ids); } - self.data.push(starting_id); + ids.push(starting_id); } } impl<'a, T> IteratorNew<'a, T, PostOrderTraversal<'a, T>> for PostOrderTraversal<'a, T> { fn new(tree: &'a Tree, node_id: NodeId) -> PostOrderTraversal { - let mut traversal = PostOrderTraversal { - tree: tree, - index: 0, - // over allocating, but all at once instead of re-sizing and re-allocating as we go - data: Vec::with_capacity(tree.nodes.capacity()), - }; - traversal.process_nodes(node_id); - traversal + // over allocating, but all at once instead of re-sizing and re-allocating as we go + let mut ids = Vec::with_capacity(tree.nodes.capacity()); + + PostOrderTraversal::process_nodes(node_id, tree, &mut ids); + + PostOrderTraversal { + tree: tree, + ids: ids.into_iter(), + } } } @@ -224,11 +225,9 @@ impl<'a, T> Iterator for PostOrderTraversal<'a, T> { type Item = &'a Node; fn next(&mut self) -> Option<&'a Node> { + let id = self.ids.next(); - let id = self.data.get(self.index); - self.index += 1; - - if let Some(node_id) = id { + if let Some(ref node_id) = id { return Some(self.tree.get_unsafe(node_id)); } From 902a219eaa631ac63f7a19cc345df34d1b645fd8 Mon Sep 17 00:00:00 2001 From: Ian Date: Wed, 8 Mar 2017 00:23:32 -0600 Subject: [PATCH 19/26] update docs example --- src/lib.rs | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index fc0dcb5..38009f4 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -36,19 +36,11 @@ //! tree.insert(Node::new(3), UnderNode(&child_id)).unwrap(); //! tree.insert(Node::new(4), UnderNode(&child_id)).unwrap(); //! -//! println!("Pre-order:"); -//! print_pre_order(&tree, &root_id); -//! // results in the output "0, 1, 3, 4, 2, " -//! } -//! -//! fn print_pre_order(tree: &Tree, node_id: &NodeId) { -//! let node_ref = tree.get(node_id).unwrap(); -//! -//! print!("{}, ", node_ref.data()); -//! -//! for child_id in node_ref.children() { -//! print_pre_order(tree, &child_id); +//! println!("Post-order:"); +//! for node in tree.traverse_pre_order(&root_id).unwrap() { +//! print!("{}, ", node.data()); //! } +//! // results in the output "0, 1, 3, 4, 2, " //! } //! ``` //! From 6b3713e1972d6372cf0e1ff85bce688d3e5c8e87 Mon Sep 17 00:00:00 2001 From: Ian Date: Wed, 8 Mar 2017 00:27:04 -0600 Subject: [PATCH 20/26] version bump --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 543b289..c00e978 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "id_tree" -version = "1.0.2" +version = "1.1.0" authors = ["Ian Burns "] description = "A library for creating and modifying Tree structures." documentation = "https://docs.rs/id_tree" From c8b757027f12d8ea34c92f4ef335bca5baff5804 Mon Sep 17 00:00:00 2001 From: Ian Burns Date: Wed, 8 Mar 2017 19:41:20 -0600 Subject: [PATCH 21/26] add LevelOrderTraversal also, tweak testing to be more clear and precise --- src/lib.rs | 1 + src/tree/iterators.rs | 114 +++++++++++++++++++++++++++++++++++++++--- src/tree/mod.rs | 34 +++++++++++++ 3 files changed, 143 insertions(+), 6 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 38009f4..e032d3c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -88,6 +88,7 @@ pub use tree::iterators::Children; pub use tree::iterators::ChildrenIds; pub use tree::iterators::PreOrderTraversal; pub use tree::iterators::PostOrderTraversal; +pub use tree::iterators::LevelOrderTraversal; /// /// An identifier used to differentiate between `Node`s within a `Tree`. diff --git a/src/tree/iterators.rs b/src/tree/iterators.rs index 1098bb4..14d9f9f 100644 --- a/src/tree/iterators.rs +++ b/src/tree/iterators.rs @@ -1,5 +1,6 @@ use std::slice::Iter; use std::vec::IntoIter; +use std::collections::VecDeque; use Tree; use Node; @@ -235,6 +236,62 @@ impl<'a, T> Iterator for PostOrderTraversal<'a, T> { } } +/// +/// An Iterator over the sub-tree relative to a given `Node`. +/// +/// Iterates over all of the `Node`s in the sub-tree of a given `Node` in the `Tree`. Each call to +/// `next` will return an immutable reference to the next `Node` in Level-Order Traversal order. +/// +pub struct LevelOrderTraversal<'a, T: 'a> { + tree: &'a Tree, + data: VecDeque, +} + +impl<'a, T> LevelOrderTraversal<'a, T> { + fn process_nodes(&mut self, starting_id: NodeId) { + + self.data.push_back(starting_id.clone()); + let mut index: usize = 0; + + while let Some(node_id) = self.data.get(index).cloned() { + let node = self.tree.get_unsafe(&node_id); + + for child_id in node.children() { + self.data.push_back(child_id.clone()); + } + + index += 1; + } + } +} + +impl<'a, T> IteratorNew<'a, T, LevelOrderTraversal<'a, T>> for LevelOrderTraversal<'a, T> { + fn new(tree: &'a Tree, node_id: NodeId) -> LevelOrderTraversal { + let mut traversal = LevelOrderTraversal { + tree: tree, + // over allocating, but all at once instead of re-sizing and re-allocating as we go + data: VecDeque::with_capacity(tree.nodes.capacity()), + }; + + traversal.process_nodes(node_id); + traversal + } +} + +impl<'a, T> Iterator for LevelOrderTraversal<'a, T> { + type Item = &'a Node; + + fn next(&mut self) -> Option<&'a Node> { + let id = self.data.pop_front(); + + if let Some(ref node_id_ref) = id { + return Some(self.tree.get_unsafe(node_id_ref)); + } + + None + } +} + #[cfg(test)] mod tests { @@ -354,17 +411,22 @@ mod tests { fn test_pre_order_traversal() { let mut tree = Tree::new(); + // 0 + // / \ + // 1 2 + // / + // 3 let root_id = tree.insert(Node::new(0), AsRoot).unwrap(); let node_1 = tree.insert(Node::new(1), UnderNode(&root_id)).unwrap(); - let node_2 = tree.insert(Node::new(2), UnderNode(&node_1)).unwrap(); + let node_2 = tree.insert(Node::new(2), UnderNode(&root_id)).unwrap(); let node_3 = tree.insert(Node::new(3), UnderNode(&node_1)).unwrap(); - let data = [0, 1, 2, 3]; + let data = [0, 1, 3, 2]; for (index, node) in tree.traverse_pre_order(&root_id).unwrap().enumerate() { assert_eq!(node.data(), &data[index]); } - let data = [1, 2, 3]; + let data = [1, 3]; for (index, node) in tree.traverse_pre_order(&node_1).unwrap().enumerate() { assert_eq!(node.data(), &data[index]); } @@ -384,17 +446,22 @@ mod tests { fn test_post_order_traversal() { let mut tree = Tree::new(); + // 0 + // / \ + // 1 2 + // / + // 3 let root_id = tree.insert(Node::new(0), AsRoot).unwrap(); let node_1 = tree.insert(Node::new(1), UnderNode(&root_id)).unwrap(); - let node_2 = tree.insert(Node::new(2), UnderNode(&node_1)).unwrap(); + let node_2 = tree.insert(Node::new(2), UnderNode(&root_id)).unwrap(); let node_3 = tree.insert(Node::new(3), UnderNode(&node_1)).unwrap(); - let data = [2, 3, 1, 0]; + let data = [3, 1, 2, 0]; for (index, node) in tree.traverse_post_order(&root_id).unwrap().enumerate() { assert_eq!(node.data(), &data[index]); } - let data = [2, 3, 1]; + let data = [3, 1]; for (index, node) in tree.traverse_post_order(&node_1).unwrap().enumerate() { assert_eq!(node.data(), &data[index]); } @@ -409,4 +476,39 @@ mod tests { assert_eq!(node.data(), &data[index]); } } + + #[test] + fn test_level_order_traversal() { + let mut tree = Tree::new(); + + // 0 + // / \ + // 1 2 + // / + // 3 + let root_id = tree.insert(Node::new(0), AsRoot).unwrap(); + let node_1 = tree.insert(Node::new(1), UnderNode(&root_id)).unwrap(); + let node_2 = tree.insert(Node::new(2), UnderNode(&root_id)).unwrap(); + let node_3 = tree.insert(Node::new(3), UnderNode(&node_1)).unwrap(); + + let data = [0, 1, 2, 3]; + for (index, node) in tree.traverse_level_order(&root_id).unwrap().enumerate() { + assert_eq!(node.data(), &data[index]); + } + + let data = [1, 3]; + for (index, node) in tree.traverse_level_order(&node_1).unwrap().enumerate() { + assert_eq!(node.data(), &data[index]); + } + + let data = [2]; + for (index, node) in tree.traverse_level_order(&node_2).unwrap().enumerate() { + assert_eq!(node.data(), &data[index]); + } + + let data = [3]; + for (index, node) in tree.traverse_level_order(&node_3).unwrap().enumerate() { + assert_eq!(node.data(), &data[index]); + } + } } diff --git a/src/tree/mod.rs b/src/tree/mod.rs index de757ed..f861387 100644 --- a/src/tree/mod.rs +++ b/src/tree/mod.rs @@ -1161,6 +1161,40 @@ impl Tree { Ok(PostOrderTraversal::new(self, node_id.clone())) } + /// Returns a `LevelOrderTraversal` iterator (or a `NodeIdError` if one occurred). + /// + /// Allows iteration over all of the `Node`s in the sub-tree below a given `Node`. This + /// iterator will always include that sub-tree "root" specified by the `NodeId` given. + /// + /// ``` + /// use id_tree::*; + /// use id_tree::InsertBehavior::*; + /// + /// let mut tree: Tree = Tree::new(); + /// let root_id = tree.insert(Node::new(0), AsRoot).unwrap(); + /// let node_1 = tree.insert(Node::new(1), UnderNode(&root_id)).unwrap(); + /// + /// let mut nodes = tree.traverse_level_order(&root_id).unwrap(); + /// + /// assert_eq!(nodes.next().unwrap().data(), &0); + /// assert_eq!(nodes.next().unwrap().data(), &1); + /// assert!(nodes.next().is_none()); + /// ``` + /// + #[cfg_attr(rustfmt, rustfmt_skip)] + // todo: remove this if https://github.com/rust-lang-nursery/rustfmt/issues/1260 is resolved + pub fn traverse_level_order(&self, node_id: &NodeId) + -> Result, NodeIdError> + { + let (is_valid, error) = self.is_valid_node_id(node_id); + if !is_valid { + return Err(error.expect( + "Tree::traverse_level_order: Missing an error value but found an invalid NodeId.")); + } + + Ok(LevelOrderTraversal::new(self, node_id.clone())) + } + // Nothing should make it past this function. // If there is a way for a NodeId to be invalid, it should be caught here. fn is_valid_node_id(&self, node_id: &NodeId) -> (bool, Option) { From 7e913c988b205fcf5e038082b0a88ea60b6db063 Mon Sep 17 00:00:00 2001 From: Ian Burns Date: Wed, 8 Mar 2017 19:42:29 -0600 Subject: [PATCH 22/26] fix formatting --- src/tree/mod.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/tree/mod.rs b/src/tree/mod.rs index f861387..467a23b 100644 --- a/src/tree/mod.rs +++ b/src/tree/mod.rs @@ -1189,7 +1189,8 @@ impl Tree { let (is_valid, error) = self.is_valid_node_id(node_id); if !is_valid { return Err(error.expect( - "Tree::traverse_level_order: Missing an error value but found an invalid NodeId.")); + "Tree::traverse_level_order: Missing an error value but found an invalid NodeId.") + ); } Ok(LevelOrderTraversal::new(self, node_id.clone())) From 943a53c7d3b8cb7ad064903808cc8f3790990457 Mon Sep 17 00:00:00 2001 From: Ian Burns Date: Wed, 8 Mar 2017 19:56:46 -0600 Subject: [PATCH 23/26] switch to storing a vec_deque::IntoIter --- src/tree/iterators.rs | 31 +++++++++++++++++-------------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/src/tree/iterators.rs b/src/tree/iterators.rs index 14d9f9f..21571ac 100644 --- a/src/tree/iterators.rs +++ b/src/tree/iterators.rs @@ -1,6 +1,7 @@ use std::slice::Iter; use std::vec::IntoIter; use std::collections::VecDeque; +use std::collections::vec_deque; use Tree; use Node; @@ -244,20 +245,20 @@ impl<'a, T> Iterator for PostOrderTraversal<'a, T> { /// pub struct LevelOrderTraversal<'a, T: 'a> { tree: &'a Tree, - data: VecDeque, + data: vec_deque::IntoIter, } impl<'a, T> LevelOrderTraversal<'a, T> { - fn process_nodes(&mut self, starting_id: NodeId) { + fn process_nodes(starting_id: NodeId, tree: &Tree, ids: &mut VecDeque) { - self.data.push_back(starting_id.clone()); + ids.push_back(starting_id); let mut index: usize = 0; - while let Some(node_id) = self.data.get(index).cloned() { - let node = self.tree.get_unsafe(&node_id); + while let Some(node_id) = ids.get(index).cloned() { + let node = tree.get_unsafe(&node_id); for child_id in node.children() { - self.data.push_back(child_id.clone()); + ids.push_back(child_id.clone()); } index += 1; @@ -267,14 +268,16 @@ impl<'a, T> LevelOrderTraversal<'a, T> { impl<'a, T> IteratorNew<'a, T, LevelOrderTraversal<'a, T>> for LevelOrderTraversal<'a, T> { fn new(tree: &'a Tree, node_id: NodeId) -> LevelOrderTraversal { - let mut traversal = LevelOrderTraversal { - tree: tree, - // over allocating, but all at once instead of re-sizing and re-allocating as we go - data: VecDeque::with_capacity(tree.nodes.capacity()), - }; - traversal.process_nodes(node_id); - traversal + // over allocating, but all at once instead of re-sizing and re-allocating as we go + let mut ids = VecDeque::with_capacity(tree.nodes.capacity()); + + LevelOrderTraversal::process_nodes(node_id, tree, &mut ids); + + LevelOrderTraversal { + tree: tree, + data: ids.into_iter(), + } } } @@ -282,7 +285,7 @@ impl<'a, T> Iterator for LevelOrderTraversal<'a, T> { type Item = &'a Node; fn next(&mut self) -> Option<&'a Node> { - let id = self.data.pop_front(); + let id = self.data.next(); if let Some(ref node_id_ref) = id { return Some(self.tree.get_unsafe(node_id_ref)); From 593fae05cdad87ee9770a5a8c51afdc55b6d618d Mon Sep 17 00:00:00 2001 From: Ian Burns Date: Thu, 9 Mar 2017 08:38:43 -0600 Subject: [PATCH 24/26] switch to owning the VecDeque and get rid of the process_nodes call --- src/tree/iterators.rs | 38 +++++++++++++------------------------- 1 file changed, 13 insertions(+), 25 deletions(-) diff --git a/src/tree/iterators.rs b/src/tree/iterators.rs index 21571ac..7073d80 100644 --- a/src/tree/iterators.rs +++ b/src/tree/iterators.rs @@ -1,7 +1,6 @@ use std::slice::Iter; use std::vec::IntoIter; use std::collections::VecDeque; -use std::collections::vec_deque; use Tree; use Node; @@ -245,38 +244,20 @@ impl<'a, T> Iterator for PostOrderTraversal<'a, T> { /// pub struct LevelOrderTraversal<'a, T: 'a> { tree: &'a Tree, - data: vec_deque::IntoIter, -} - -impl<'a, T> LevelOrderTraversal<'a, T> { - fn process_nodes(starting_id: NodeId, tree: &Tree, ids: &mut VecDeque) { - - ids.push_back(starting_id); - let mut index: usize = 0; - - while let Some(node_id) = ids.get(index).cloned() { - let node = tree.get_unsafe(&node_id); - - for child_id in node.children() { - ids.push_back(child_id.clone()); - } - - index += 1; - } - } + data: VecDeque, } impl<'a, T> IteratorNew<'a, T, LevelOrderTraversal<'a, T>> for LevelOrderTraversal<'a, T> { fn new(tree: &'a Tree, node_id: NodeId) -> LevelOrderTraversal { // over allocating, but all at once instead of re-sizing and re-allocating as we go - let mut ids = VecDeque::with_capacity(tree.nodes.capacity()); + let mut data = VecDeque::with_capacity(tree.nodes.capacity()); - LevelOrderTraversal::process_nodes(node_id, tree, &mut ids); + data.push_back(node_id); LevelOrderTraversal { tree: tree, - data: ids.into_iter(), + data: data, } } } @@ -285,10 +266,17 @@ impl<'a, T> Iterator for LevelOrderTraversal<'a, T> { type Item = &'a Node; fn next(&mut self) -> Option<&'a Node> { - let id = self.data.next(); + let id = self.data.pop_front(); if let Some(ref node_id_ref) = id { - return Some(self.tree.get_unsafe(node_id_ref)); + + let node_ref = self.tree.get_unsafe(node_id_ref); + + for child_id in node_ref.children() { + self.data.push_back(child_id.clone()); + } + + return Some(node_ref); } None From ebc54d6648bee67f497843fadaf9a80265899e71 Mon Sep 17 00:00:00 2001 From: Ian Burns Date: Thu, 9 Mar 2017 09:36:27 -0600 Subject: [PATCH 25/26] simplify PreOrderTraversal memory layout and next() --- src/tree/iterators.rs | 35 +++++++++++++++-------------------- 1 file changed, 15 insertions(+), 20 deletions(-) diff --git a/src/tree/iterators.rs b/src/tree/iterators.rs index 7073d80..15494d9 100644 --- a/src/tree/iterators.rs +++ b/src/tree/iterators.rs @@ -141,17 +141,20 @@ impl<'a> Iterator for ChildrenIds<'a> { /// pub struct PreOrderTraversal<'a, T: 'a> { tree: &'a Tree, - node_id: Option, - future_data: Vec<&'a NodeId>, + data: VecDeque, } impl<'a, T> IteratorNew<'a, T, PreOrderTraversal<'a, T>> for PreOrderTraversal<'a, T> { fn new(tree: &'a Tree, node_id: NodeId) -> PreOrderTraversal { + + // over allocating, but all at once instead of re-sizing and re-allocating as we go + let mut data = VecDeque::with_capacity(tree.nodes.capacity()); + + data.push_front(node_id); + PreOrderTraversal { tree: tree, - node_id: Some(node_id), - // over allocating, but all at once instead of re-sizing and re-allocating as we go - future_data: Vec::with_capacity(tree.nodes.capacity()), + data: data, } } } @@ -160,25 +163,17 @@ impl<'a, T> Iterator for PreOrderTraversal<'a, T> { type Item = &'a Node; fn next(&mut self) -> Option<&'a Node> { - if let Some(node_id) = self.node_id.clone() { - - let node = self.tree.get_unsafe(&node_id); - - if !node.children().is_empty() { - let mut children_ids = node.children().iter(); - - // take the first child and set it as the next one to be processed - self.node_id = children_ids.next().cloned(); + let id = self.data.pop_front(); - // reverse it because we will pop to get the next one later. - let mut new_ids: Vec<&NodeId> = children_ids.rev().collect(); + if let Some(ref node_id) = id { + let node_ref = self.tree.get_unsafe(node_id); - self.future_data.append(&mut new_ids); - } else { - self.node_id = self.future_data.pop().cloned(); + //prepend child_ids + for child_id in node_ref.children().iter().rev() { + self.data.push_front(child_id.clone()); } - return Some(node); + return Some(node_ref); } None } From fcea716067757b0e7dab5ec8d8e0692aec8d6151 Mon Sep 17 00:00:00 2001 From: Ian Burns Date: Thu, 9 Mar 2017 09:37:15 -0600 Subject: [PATCH 26/26] fix formatting --- src/tree/iterators.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tree/iterators.rs b/src/tree/iterators.rs index 15494d9..befbf0d 100644 --- a/src/tree/iterators.rs +++ b/src/tree/iterators.rs @@ -168,7 +168,7 @@ impl<'a, T> Iterator for PreOrderTraversal<'a, T> { if let Some(ref node_id) = id { let node_ref = self.tree.get_unsafe(node_id); - //prepend child_ids + // prepend child_ids for child_id in node_ref.children().iter().rev() { self.data.push_front(child_id.clone()); }