From 39ce915157bcf40ee272342071e678c47d8f5a8a Mon Sep 17 00:00:00 2001 From: Kenneth Loeffler Date: Tue, 30 May 2023 13:38:24 -0700 Subject: [PATCH] Use an iterative implementation for Instance::clone_inner --- packages/lib-roblox/src/instance/mod.rs | 30 ++++++++++++++++++------- 1 file changed, 22 insertions(+), 8 deletions(-) diff --git a/packages/lib-roblox/src/instance/mod.rs b/packages/lib-roblox/src/instance/mod.rs index 0eb302f..7a1073a 100644 --- a/packages/lib-roblox/src/instance/mod.rs +++ b/packages/lib-roblox/src/instance/mod.rs @@ -214,9 +214,11 @@ impl Instance { parent_ref: DomRef, reference_map: &mut HashMap, ) -> DomRef { - // NOTE: We create a new scope here to avoid deadlocking since - // our clone implementation must have exclusive write access - let (new_ref, child_refs) = { + fn do_clone( + dom_ref: DomRef, + parent_ref: DomRef, + reference_map: &mut HashMap, + ) -> (DomRef, Vec) { let mut dom = INTERNAL_DOM .try_write() .expect("Failed to get write access to document"); @@ -243,13 +245,25 @@ impl Instance { reference_map.insert(dom_ref, new_ref); (new_ref, child_refs) - }; - - for child_ref in child_refs { - Self::clone_inner(child_ref, new_ref, reference_map); } - new_ref + let (cloned_parent, uncloned_children) = do_clone(dom_ref, parent_ref, reference_map); + let mut queue = VecDeque::with_capacity(uncloned_children.len()); + + for uncloned_child in uncloned_children.iter() { + queue.push_back((cloned_parent, *uncloned_child)); + } + + while let Some((cloned_parent, uncloned_child)) = queue.pop_front() { + let (cloned_parent, uncloned_children) = + do_clone(uncloned_child, cloned_parent, reference_map); + + for uncloned_child in uncloned_children.iter() { + queue.push_back((*uncloned_child, cloned_parent)) + } + } + + cloned_parent } /**