diff --git a/crates/fj-core/src/objects/object_set.rs b/crates/fj-core/src/objects/object_set.rs index 9fb8f61d5..9f727f144 100644 --- a/crates/fj-core/src/objects/object_set.rs +++ b/crates/fj-core/src/objects/object_set.rs @@ -28,16 +28,17 @@ impl ObjectSet { /// # Panics /// /// Panics, if the iterator contains duplicate `Handle`s. - pub fn new(handles: impl IntoIterator>) -> Self + pub fn new(handles: impl IntoIterator) -> Self where T: Debug + Ord, + H: Into>, { let mut added = BTreeSet::new(); let mut inner = Vec::new(); - for handle in handles { - let handle = HandleWrapper::from(handle); + let handles = handles.into_iter().map(|handle| handle.into()); + for handle in handles { if added.contains(&handle) { panic!( "Constructing `ObjectSet` with duplicate handle: {:?}", @@ -149,13 +150,14 @@ impl ObjectSet { /// /// Panics, if the update results in a duplicate item. #[must_use] - pub fn replace( + pub fn replace( &self, original: &Handle, - replacements: [Handle; N], + replacements: impl IntoIterator, ) -> Option where T: Debug + Ord, + H: Into>, { let mut iter = self.iter().cloned().peekable(); @@ -185,7 +187,7 @@ impl ObjectSet { Some( before .into_iter() - .chain(replacements) + .chain(replacements.into_iter().map(|handle| handle.into())) .chain(after) .collect(), ) @@ -244,7 +246,12 @@ pub type ObjectSetIntoIter = iter::Map< #[cfg(test)] mod tests { - use crate::{objects::Cycle, operations::insert::Insert, Core}; + use std::collections::HashSet; + + use crate::{ + objects::Cycle, operations::insert::Insert, storage::HandleWrapper, + Core, + }; use super::ObjectSet; @@ -260,4 +267,38 @@ mod tests { // Nothing more to test. `ObjectSet` panics on duplicate objects, and it // shouldn't do that in this case. } + + #[test] + fn deduplicate_with_hashset() { + let mut core = Core::new(); + + let bare_cycle = Cycle::new([]); + let cycle = bare_cycle.insert(&mut core); + + let standard_set = HashSet::from([cycle.clone(), cycle.clone()]); + + assert_eq!(standard_set, [cycle].into()); + } + + #[test] + fn object_set_from_handle_wrappers() { + let mut core = Core::new(); + + let bare_cycle = Cycle::new([]); + let cycle_a = HandleWrapper::from(bare_cycle.clone().insert(&mut core)); + let cycle_b = HandleWrapper::from(bare_cycle.insert(&mut core)); + + let _object_set = ObjectSet::new([cycle_a, cycle_b]); + } + + #[test] + fn object_set_from_deduplicated_hash_set() { + let mut core = Core::new(); + + let bare_cycle = Cycle::new([]); + let cycle_a = HandleWrapper::from(bare_cycle.clone().insert(&mut core)); + let cycle_b = HandleWrapper::from(bare_cycle.insert(&mut core)); + + let _object_set = ObjectSet::new(HashSet::from([cycle_a, cycle_b])); + } } diff --git a/crates/fj-core/src/operations/update/cycle.rs b/crates/fj-core/src/operations/update/cycle.rs index 1f672a424..9d1d6353b 100644 --- a/crates/fj-core/src/operations/update/cycle.rs +++ b/crates/fj-core/src/operations/update/cycle.rs @@ -23,16 +23,17 @@ pub trait UpdateCycle { /// /// Panics, if the object can't be found. /// - /// Panics, if the update results in a duplicate object. + /// Panics, if the update results in multiple handles referencing the same object. #[must_use] - fn update_half_edge( + fn update_half_edge( &self, handle: &Handle, - update: impl FnOnce(&Handle, &mut Core) -> [T; N], + update: impl FnOnce(&Handle, &mut Core) -> R, core: &mut Core, ) -> Self where - T: Insert>; + T: Insert>, + R: IntoIterator; } impl UpdateCycle for Cycle { @@ -51,20 +52,21 @@ impl UpdateCycle for Cycle { Cycle::new(half_edges) } - fn update_half_edge( + fn update_half_edge( &self, handle: &Handle, - update: impl FnOnce(&Handle, &mut Core) -> [T; N], + update: impl FnOnce(&Handle, &mut Core) -> R, core: &mut Core, ) -> Self where T: Insert>, + R: IntoIterator, { let edges = self .half_edges() .replace( handle, - update(handle, core).map(|object| { + update(handle, core).into_iter().map(|object| { object.insert(core).derive_from(handle, core) }), ) diff --git a/crates/fj-core/src/operations/update/region.rs b/crates/fj-core/src/operations/update/region.rs index cc83b6daa..9f28c7e83 100644 --- a/crates/fj-core/src/operations/update/region.rs +++ b/crates/fj-core/src/operations/update/region.rs @@ -33,16 +33,17 @@ pub trait UpdateRegion { /// /// Panics, if the object can't be found. /// - /// Panics, if the update results in a duplicate object. + /// Panics, if the update results in multiple handles referencing the same object. #[must_use] - fn update_interior( + fn update_interior( &self, handle: &Handle, - update: impl FnOnce(&Handle, &mut Core) -> [T; N], + update: impl FnOnce(&Handle, &mut Core) -> R, core: &mut Core, ) -> Self where - T: Insert>; + T: Insert>, + R: IntoIterator; } impl UpdateRegion for Region { @@ -73,20 +74,21 @@ impl UpdateRegion for Region { Region::new(self.exterior().clone(), interiors) } - fn update_interior( + fn update_interior( &self, handle: &Handle, - update: impl FnOnce(&Handle, &mut Core) -> [T; N], + update: impl FnOnce(&Handle, &mut Core) -> R, core: &mut Core, ) -> Self where T: Insert>, + R: IntoIterator, { let interiors = self .interiors() .replace( handle, - update(handle, core).map(|object| { + update(handle, core).into_iter().map(|object| { object.insert(core).derive_from(handle, core) }), ) diff --git a/crates/fj-core/src/operations/update/shell.rs b/crates/fj-core/src/operations/update/shell.rs index 6b46c76cd..961e3b730 100644 --- a/crates/fj-core/src/operations/update/shell.rs +++ b/crates/fj-core/src/operations/update/shell.rs @@ -23,16 +23,17 @@ pub trait UpdateShell { /// /// Panics, if the object can't be found. /// - /// Panics, if the update results in a duplicate object. + /// Panics, if the update results in multiple handles referencing the same object. #[must_use] - fn update_face( + fn update_face( &self, handle: &Handle, - update: impl FnOnce(&Handle, &mut Core) -> [T; N], + update: impl FnOnce(&Handle, &mut Core) -> R, core: &mut Core, ) -> Self where - T: Insert>; + T: Insert>, + R: IntoIterator; /// Remove a face from the shell #[must_use] @@ -53,20 +54,21 @@ impl UpdateShell for Shell { Shell::new(faces) } - fn update_face( + fn update_face( &self, handle: &Handle, - update: impl FnOnce(&Handle, &mut Core) -> [T; N], + update: impl FnOnce(&Handle, &mut Core) -> R, core: &mut Core, ) -> Self where T: Insert>, + R: IntoIterator, { let faces = self .faces() .replace( handle, - update(handle, core).map(|object| { + update(handle, core).into_iter().map(|object| { object.insert(core).derive_from(handle, core) }), ) diff --git a/crates/fj-core/src/operations/update/sketch.rs b/crates/fj-core/src/operations/update/sketch.rs index 192e7da19..33a96e832 100644 --- a/crates/fj-core/src/operations/update/sketch.rs +++ b/crates/fj-core/src/operations/update/sketch.rs @@ -23,16 +23,17 @@ pub trait UpdateSketch { /// /// Panics, if the object can't be found. /// - /// Panics, if the update results in a duplicate object. + /// Panics, if the update results in multiple handles referencing the same object. #[must_use] - fn update_region( + fn update_region( &self, handle: &Handle, - update: impl FnOnce(&Handle, &mut Core) -> [T; N], + update: impl FnOnce(&Handle, &mut Core) -> R, core: &mut Core, ) -> Self where - T: Insert>; + T: Insert>, + R: IntoIterator; } impl UpdateSketch for Sketch { @@ -49,20 +50,21 @@ impl UpdateSketch for Sketch { Sketch::new(regions) } - fn update_region( + fn update_region( &self, handle: &Handle, - update: impl FnOnce(&Handle, &mut Core) -> [T; N], + update: impl FnOnce(&Handle, &mut Core) -> R, core: &mut Core, ) -> Self where T: Insert>, + R: IntoIterator, { let regions = self .regions() .replace( handle, - update(handle, core).map(|object| { + update(handle, core).into_iter().map(|object| { object.insert(core).derive_from(handle, core) }), ) diff --git a/crates/fj-core/src/operations/update/solid.rs b/crates/fj-core/src/operations/update/solid.rs index f7882a637..3d30ff513 100644 --- a/crates/fj-core/src/operations/update/solid.rs +++ b/crates/fj-core/src/operations/update/solid.rs @@ -23,16 +23,17 @@ pub trait UpdateSolid { /// /// Panics, if the object can't be found. /// - /// Panics, if the update results in a duplicate object. + /// Panics, if the update results in multiple handles referencing the same object. #[must_use] - fn update_shell( + fn update_shell( &self, handle: &Handle, - update: impl FnOnce(&Handle, &mut Core) -> [T; N], + update: impl FnOnce(&Handle, &mut Core) -> R, core: &mut Core, ) -> Self where - T: Insert>; + T: Insert>, + R: IntoIterator; } impl UpdateSolid for Solid { @@ -49,20 +50,21 @@ impl UpdateSolid for Solid { Solid::new(shells) } - fn update_shell( + fn update_shell( &self, handle: &Handle, - update: impl FnOnce(&Handle, &mut Core) -> [T; N], + update: impl FnOnce(&Handle, &mut Core) -> R, core: &mut Core, ) -> Self where T: Insert>, + R: IntoIterator, { let shells = self .shells() .replace( handle, - update(handle, core).map(|object| { + update(handle, core).into_iter().map(|object| { object.insert(core).derive_from(handle, core) }), )