diff --git a/src/common_traits/from_depth_first_iter.rs b/src/common_traits/from_depth_first_iter.rs index 33a608b..0b3a96a 100644 --- a/src/common_traits/from_depth_first_iter.rs +++ b/src/common_traits/from_depth_first_iter.rs @@ -190,6 +190,8 @@ pub enum DepthFirstSequenceError { }, } +impl DepthFirstSequence where I: IntoIterator {} + impl TryFrom> for Tree where V: TreeVariant, @@ -215,14 +217,25 @@ where None => Ok(Tree::default()), Some((d, root)) => match d { 0 => { - let mut tree = Tree::new_with_root(root); - match tree.root_mut().try_append_subtree_as_child(iter, 0) { - Ok(_) => Ok(tree), - Err((depth, succeeding_depth)) => { - Err(DepthFirstSequenceError::DepthIncreaseGreaterThanOne { - depth, - succeeding_depth, - }) + let tree = Tree::new_with_root(root); + + // # SAFETY: + // `push_dfs_under_root` panics if iter is empty. Therefore, + // + // * We first check if lower-bound(len) > 0, this allows us to directly use the iter + // which is faster. + // * Otherwise, we use a peekable iterator to make sure that the iterator has at least + // one element. + let (lb_len, _) = iter.size_hint(); + + match lb_len > 0 { + true => push_dfs_under_root(tree, iter), + false => { + let mut peekable = iter.peekable(); + match peekable.peek().is_some() { + true => push_dfs_under_root(tree, peekable), + false => Ok(tree), + } } } } @@ -231,3 +244,31 @@ where } } } + +/// # Panics +/// +/// Panics +/// +/// * If the `iter` is an empty iterator; it must contain at least one child node. +/// * If the `tree` is empty, it must have at least the `root`. +fn push_dfs_under_root( + mut tree: Tree, + iter: I, +) -> Result, DepthFirstSequenceError> +where + V: TreeVariant, + M: MemoryPolicy, + P: PinnedStorage, + P::PinnedVec: Default, + I: IntoIterator, +{ + match tree.root_mut().try_append_subtree_as_child(iter, 0) { + Ok(_) => Ok(tree), + Err((depth, succeeding_depth)) => { + Err(DepthFirstSequenceError::DepthIncreaseGreaterThanOne { + depth, + succeeding_depth, + }) + } + } +} diff --git a/src/node_mut.rs b/src/node_mut.rs index b31cf6b..91c7a27 100644 --- a/src/node_mut.rs +++ b/src/node_mut.rs @@ -3264,6 +3264,10 @@ where /// greater than one. /// The method returns the (depth, succeeding_depth) pair as the error when this error /// is observed. + /// + /// # Panics + /// + /// Panics if the `subtree` is an empty iterator. It must contain at least one child node. #[allow(clippy::unwrap_in_result)] pub(crate) fn try_append_subtree_as_child( &mut self, diff --git a/tests/leaf_nodes.rs b/tests/leaf_nodes.rs new file mode 100644 index 0000000..22f9740 --- /dev/null +++ b/tests/leaf_nodes.rs @@ -0,0 +1,70 @@ +// tests on nodes without any children + +use orx_tree::*; + +/// https://github.com/orxfun/orx-tree/issues/183 +#[test] +fn leaf_into_new_tree() { + let mut tree = DynTree::new(0); + let idx = tree.root_mut().push_child(1); + + let tree2: DynTree<_> = tree.node_mut(idx).into_new_tree(); + + assert_eq!(tree2.len(), 1); + assert_eq!( + tree2.root().walk::().copied().collect::>(), + vec![1] + ); +} + +#[test] +fn root_into_new_tree() { + let mut tree = DynTree::new(0); + + let tree2: DynTree<_> = tree.root_mut().into_new_tree(); + + assert_eq!(tree2.len(), 1); + assert_eq!( + tree2.root().walk::().copied().collect::>(), + vec![0] + ); +} + +#[test] +fn leaf_into_walk() { + let mut tree = DynTree::new(0); + let idx = tree.root_mut().push_child(1); + + let values: Vec<_> = tree.node_mut(idx).into_walk::().collect(); + assert_eq!(values, vec![1]); + + let remaining: Vec<_> = tree.root().walk::().copied().collect(); + assert_eq!(remaining, vec![0]); +} + +#[test] +fn leaf_into_leaves() { + let mut tree = DynTree::new(0); + let idx = tree.root_mut().push_child(1); + + let values: Vec<_> = tree.node_mut(idx).into_leaves::().collect(); + assert_eq!(values, vec![1]); + + let remaining: Vec<_> = tree.root().walk::().copied().collect(); + assert_eq!(remaining, vec![0]); +} + +#[test] +fn leaf_into_subtree() { + let mut tree = DynTree::new(0); + let idx = tree.root_mut().push_child(1); + + let subtree = tree.node_mut(idx).into_subtree(); + let mut tree2 = DynTree::new(42); + tree2.root_mut().push_child_tree(subtree); + let values: Vec<_> = tree2.root().walk::().copied().collect(); + assert_eq!(values, vec![42, 1]); + + let remaining: Vec<_> = tree.root().walk::().copied().collect(); + assert_eq!(remaining, vec![0]); +}