From d9bc6fbfea788f3032ea3d89144e16e0cb439441 Mon Sep 17 00:00:00 2001 From: Hanno Braun Date: Wed, 27 Sep 2023 11:02:06 +0200 Subject: [PATCH 1/4] Fix panic message --- crates/fj-core/src/objects/handles.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/fj-core/src/objects/handles.rs b/crates/fj-core/src/objects/handles.rs index 1114a8f86..3c490d1f9 100644 --- a/crates/fj-core/src/objects/handles.rs +++ b/crates/fj-core/src/objects/handles.rs @@ -128,7 +128,7 @@ impl Handles { let handles = items.collect(); - assert!(updated.is_none(), "Edge not found in cycle"); + assert!(updated.is_none(), "Item not found"); handles } From a7c3b625fe55e913315eae6eca46dc5677477cff Mon Sep 17 00:00:00 2001 From: Hanno Braun Date: Wed, 27 Sep 2023 11:09:26 +0200 Subject: [PATCH 2/4] Refactor to prepare for follow-on change --- crates/fj-core/src/objects/handles.rs | 30 +++++++++++++++++---------- 1 file changed, 19 insertions(+), 11 deletions(-) diff --git a/crates/fj-core/src/objects/handles.rs b/crates/fj-core/src/objects/handles.rs index 3c490d1f9..51c910ce4 100644 --- a/crates/fj-core/src/objects/handles.rs +++ b/crates/fj-core/src/objects/handles.rs @@ -114,23 +114,31 @@ impl Handles { where T: Debug + Ord, { - let mut updated = Some(update(handle)); + let mut iter = self.iter().cloned().peekable(); + + // Collect all items before the item we want to update. + let mut before = Vec::new(); + loop { + let h = match iter.peek() { + Some(h) => h, + None => panic!("Item not found"), + }; - let items = self.iter().map(|h| { if h.id() == handle.id() { - updated - .take() - .expect("`Handles` should not contain same item twice") - } else { - h.clone() + // Found the item we want to update. Remove it from the + // iterator, then move on. + iter.next(); + break; } - }); - let handles = items.collect(); + let next = iter.next().expect("Peek just returned `Some`"); + before.push(next.clone()); + } - assert!(updated.is_none(), "Item not found"); + let updated = update(handle); + let after = iter; - handles + before.into_iter().chain([updated]).chain(after).collect() } } From 7990e85865237fbd266868a7499d48a0fe3e1c8e Mon Sep 17 00:00:00 2001 From: Hanno Braun Date: Wed, 27 Sep 2023 11:11:16 +0200 Subject: [PATCH 3/4] Add `Handles::replace` --- crates/fj-core/src/objects/handles.rs | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/crates/fj-core/src/objects/handles.rs b/crates/fj-core/src/objects/handles.rs index 51c910ce4..d9ee8b6a5 100644 --- a/crates/fj-core/src/objects/handles.rs +++ b/crates/fj-core/src/objects/handles.rs @@ -111,6 +111,27 @@ impl Handles { handle: &Handle, update: impl FnOnce(&Handle) -> Handle, ) -> Self + where + T: Debug + Ord, + { + self.replace(handle, |handle| [update(handle)]) + } + + /// Create a new instance in which the provided item has been replaced + /// + /// This is a more general version of [`Handles::update`] which can replace + /// a single item with multiple others. + /// + /// # Panics + /// + /// Panics, if the provided item is not present. + /// Panics, if the update results in a duplicate item. + #[must_use] + pub fn replace( + &self, + handle: &Handle, + replace: impl FnOnce(&Handle) -> [Handle; N], + ) -> Self where T: Debug + Ord, { @@ -135,10 +156,10 @@ impl Handles { before.push(next.clone()); } - let updated = update(handle); + let replaced = replace(handle); let after = iter; - before.into_iter().chain([updated]).chain(after).collect() + before.into_iter().chain(replaced).chain(after).collect() } } From 03be493579b740df9c0d6de7f95f5baab93ad1a8 Mon Sep 17 00:00:00 2001 From: Hanno Braun Date: Wed, 27 Sep 2023 11:13:57 +0200 Subject: [PATCH 4/4] Add `UpdateCycle::replace_edge` --- crates/fj-core/src/operations/update/cycle.rs | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/crates/fj-core/src/operations/update/cycle.rs b/crates/fj-core/src/operations/update/cycle.rs index 3a67bf54b..ba34205e4 100644 --- a/crates/fj-core/src/operations/update/cycle.rs +++ b/crates/fj-core/src/operations/update/cycle.rs @@ -22,6 +22,23 @@ pub trait UpdateCycle { edge: &Handle, update: impl FnOnce(&Handle) -> Handle, ) -> Self; + + /// Replace the provided edge + /// + /// This is a more general version of [`UpdateCycle::update_edge`] which can + /// replace a single edge with multiple others. + /// + /// # Panics + /// + /// Uses [`Handles::update`] internally, and panics for the same reasons. + /// + /// [`Handles::update`]: crate::objects::Handles::update + #[must_use] + fn replace_edge( + &self, + edge: &Handle, + replace: impl FnOnce(&Handle) -> [Handle; N], + ) -> Self; } impl UpdateCycle for Cycle { @@ -38,4 +55,13 @@ impl UpdateCycle for Cycle { let edges = self.edges().update(edge, update); Cycle::new(edges) } + + fn replace_edge( + &self, + edge: &Handle, + replace: impl FnOnce(&Handle) -> [Handle; N], + ) -> Self { + let edges = self.edges().replace(edge, replace); + Cycle::new(edges) + } }