From c07b8aabe9cf5d3f36ecad45034d9bbaf57dfeb1 Mon Sep 17 00:00:00 2001 From: Alexander Annenkov Date: Wed, 25 Jun 2025 07:34:03 +0300 Subject: [PATCH 1/2] Added deep_clone for nodes --- src/lib.rs | 31 ++++++++++++++++++++++++++++ tests/tree.rs | 57 +++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 88 insertions(+) diff --git a/src/lib.rs b/src/lib.rs index 3b42f0f..5d85c59 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -290,6 +290,29 @@ impl Tree { } } +impl Tree { + /// Clones the node deeply and creates a new tree. + /// Skips orphaned nodes. + pub fn deep_clone(&self, id: NodeId) -> Self { + let start_node = unsafe { self.get_unchecked(id) }; + let mut result = Self::new(start_node.value().clone()); + + let mut queue = std::collections::VecDeque::<(NodeId, NodeId)>::new(); + queue.push_back((id, result.root().id)); + + while let Some((src_id, dst_id)) = queue.pop_front() { + let src = unsafe { self.get_unchecked(src_id) }; + let mut dst = unsafe { result.get_unchecked_mut(dst_id) }; + for src_child in src.children() { + let dst_child_id = dst.append(src_child.value().clone()).id; + queue.push_back((src_child.id, dst_child_id)); + } + } + + result + } +} + impl<'a, T: 'a> NodeRef<'a, T> { /// Returns the ID of this node. pub fn id(&self) -> NodeId { @@ -349,6 +372,14 @@ impl<'a, T: 'a> NodeRef<'a, T> { } } +impl<'a, T: 'a + Clone> NodeRef<'a, T> { + /// Clones the node deeply and creates a new tree. + /// Skips orphaned nodes. + pub fn deep_clone(&self) -> Tree { + self.tree.deep_clone(self.id) + } +} + impl<'a, T: 'a> NodeMut<'a, T> { /// Returns the ID of this node. pub fn id(&self) -> NodeId { diff --git a/tests/tree.rs b/tests/tree.rs index cb28780..046a4c8 100644 --- a/tests/tree.rs +++ b/tests/tree.rs @@ -238,3 +238,60 @@ fn test_display() { assert_eq!(repr, expected); } + +#[test] +fn clone_subtree() { + let mut tree = tree! { + "root" => { + "a" => { + "child 1", + "child 2", + "child 3" => { + "child child 1", + "child child 2", + "child child 3", + "child child 4", + }, + }, + "b" => { + "child 4", + }, + } + }; + + let test_node_id = tree.root().first_child().unwrap().id(); + let test_subtree = tree.deep_clone(test_node_id); + + assert_eq!( + test_subtree, + tree! { + "a" => { + "child 1", + "child 2", + "child 3" => { + "child child 1", + "child child 2", + "child child 3", + "child child 4", + }, + } + } + ); + + tree.root_mut() + .first_child() + .unwrap() + .last_child() + .unwrap() + .detach(); + let test_subtree = tree.deep_clone(test_node_id); + assert_eq!( + test_subtree, + tree! { + "a" => { + "child 1", + "child 2", + } + } + ); +} From 3d2a9afe746c9f86c190fe99d56d1b3bf0b16e53 Mon Sep 17 00:00:00 2001 From: Alexander Annenkov Date: Fri, 27 Jun 2025 16:36:32 +0300 Subject: [PATCH 2/2] Removed unnecessary mut --- src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index 5d85c59..538f99b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -401,7 +401,7 @@ impl<'a, T: 'a> NodeMut<'a, T> { } /// Downcast `NodeMut` to `NodeRef`. - pub fn as_ref(&mut self) -> NodeRef<'_, T> { + pub fn as_ref(&self) -> NodeRef<'_, T> { unsafe { self.tree.get_unchecked(self.id) } }