diff --git a/crates/fj-core/src/validate/mod.rs b/crates/fj-core/src/validate/mod.rs index f9c07e135..85444da49 100644 --- a/crates/fj-core/src/validate/mod.rs +++ b/crates/fj-core/src/validate/mod.rs @@ -78,7 +78,10 @@ use crate::{ validation::{ValidationConfig, ValidationError}, }; -pub use self::{sketch::SketchValidationError, solid::SolidValidationError}; +pub use self::{ + references::ObjectNotExclusivelyOwned, sketch::SketchValidationError, + solid::SolidValidationError, +}; /// Assert that some object has a validation error which matches a specific /// pattern. This is preferred to matching on [`Validate::validate_and_return_first_error`], since usually we don't care about the order. diff --git a/crates/fj-core/src/validate/references.rs b/crates/fj-core/src/validate/references.rs index e5cd04fab..9606997a8 100644 --- a/crates/fj-core/src/validate/references.rs +++ b/crates/fj-core/src/validate/references.rs @@ -1,9 +1,34 @@ use std::{any::type_name_of_val, collections::HashMap, fmt}; -use crate::{ - storage::Handle, - topology::{Cycle, Face, HalfEdge, Region, Shell}, -}; +use crate::storage::Handle; + +/// Object that should be exclusively owned by another, is not +/// +/// Some objects are expected to be "owned" by a single other object. This means +/// that only one reference to these objects must exist within the topological +/// object graph. +#[derive(Clone, Debug, thiserror::Error)] +pub struct ObjectNotExclusivelyOwned { + object: Handle, + referenced_by: Vec>, +} + +impl fmt::Display for ObjectNotExclusivelyOwned +where + T: fmt::Debug, + U: fmt::Debug, +{ + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!( + f, + "`{}` ({:?}) referenced by multiple `{}` objects ({:?})", + type_name_of_val(&self.object), + self.object, + type_name_of_val(&self.referenced_by), + self.referenced_by + ) + } +} #[derive(Default)] pub struct ReferenceCounter(HashMap, Vec>>); @@ -17,11 +42,11 @@ impl ReferenceCounter { self.0.entry(to).or_default().push(from); } - pub fn find_multiples(&self) -> Vec> { + pub fn find_multiples(&self) -> Vec> { self.0 .iter() .filter(|(_, referenced_by)| referenced_by.len() > 1) - .map(|(object, referenced_by)| MultipleReferences { + .map(|(object, referenced_by)| ObjectNotExclusivelyOwned { object: object.clone(), referenced_by: referenced_by.to_vec(), }) @@ -32,64 +57,12 @@ impl ReferenceCounter { /// Find errors and convert to [`crate::validate::ValidationError`] #[macro_export] macro_rules! validate_references { - ($errors:ident, $error_ty:ty;$($counter:ident, $err:ident;)*) => { + ($errors:ident;$($counter:ident, $err:ident;)*) => { $( $counter.find_multiples().iter().for_each(|multiple| { - let reference_error = ObjectNotExclusivelyOwned::$err { references: multiple.clone() }; - $errors.push(Into::<$error_ty>::into(reference_error).into()); + let reference_error = ValidationError::$err(multiple.clone()); + $errors.push(reference_error.into()); }); )* }; } - -/// Object that should be exclusively owned by another, is not -/// -/// Some objects are expected to be "owned" by a single other object. This means -/// that only one reference to these objects must exist within the topological -/// object graph. -#[derive(Clone, Debug, thiserror::Error)] -pub enum ObjectNotExclusivelyOwned { - /// [`Region`] referenced by more than one [`Face`] - #[error(transparent)] - Region { - references: MultipleReferences, - }, - /// [`Face`] referenced by more than one [`Shell`] - #[error(transparent)] - Face { - references: MultipleReferences, - }, - /// [`HalfEdge`] referenced by more than one [`Cycle`] - #[error(transparent)] - HalfEdge { - references: MultipleReferences, - }, - /// [`Cycle`] referenced by more than one [`Region`] - #[error(transparent)] - Cycle { - references: MultipleReferences, - }, -} - -#[derive(Clone, Debug, thiserror::Error)] -pub struct MultipleReferences { - object: Handle, - referenced_by: Vec>, -} - -impl fmt::Display for MultipleReferences -where - T: fmt::Debug, - U: fmt::Debug, -{ - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!( - f, - "`{}` ({:?}) referenced by multiple `{}` objects ({:?})", - type_name_of_val(&self.object), - self.object, - type_name_of_val(&self.referenced_by), - self.referenced_by - ) - } -} diff --git a/crates/fj-core/src/validate/sketch.rs b/crates/fj-core/src/validate/sketch.rs index c44495cd5..9d5f64f45 100644 --- a/crates/fj-core/src/validate/sketch.rs +++ b/crates/fj-core/src/validate/sketch.rs @@ -9,8 +9,7 @@ use crate::{ }; use super::{ - references::{ObjectNotExclusivelyOwned, ReferenceCounter}, - Validate, ValidationConfig, ValidationError, + references::ReferenceCounter, Validate, ValidationConfig, ValidationError, }; impl Validate for Sketch { @@ -37,10 +36,6 @@ impl Validate for Sketch { /// [`Sketch`] validation failed #[derive(Clone, Debug, thiserror::Error)] pub enum SketchValidationError { - /// Object within sketch referenced by more than one other object - #[error("Object within sketch referenced by more than one other Object")] - ObjectNotExclusivelyOwned(#[from] ObjectNotExclusivelyOwned), - /// Region within sketch has exterior cycle with clockwise winding #[error( "Exterior cycle within sketch region has clockwise winding\n @@ -81,9 +76,9 @@ impl SketchValidationError { }); validate_references!( - errors, SketchValidationError; - referenced_edges, HalfEdge; - referenced_cycles, Cycle; + errors; + referenced_edges, MultipleReferencesToHalfEdge; + referenced_cycles, MultipleReferencesToCycle; ); } @@ -135,10 +130,7 @@ mod tests { build::BuildHalfEdge, build::BuildRegion, insert::Insert, }, topology::{Cycle, HalfEdge, Region, Sketch, Vertex}, - validate::{ - references::ObjectNotExclusivelyOwned, SketchValidationError, - Validate, ValidationError, - }, + validate::{SketchValidationError, Validate, ValidationError}, Core, }; @@ -170,11 +162,7 @@ mod tests { assert_contains_err!( core, invalid_sketch, - ValidationError::Sketch( - SketchValidationError::ObjectNotExclusivelyOwned( - ObjectNotExclusivelyOwned::Cycle { references: _ } - ) - ) + ValidationError::MultipleReferencesToCycle(_) ); Ok(()) @@ -210,11 +198,7 @@ mod tests { assert_contains_err!( core, invalid_sketch, - ValidationError::Sketch( - SketchValidationError::ObjectNotExclusivelyOwned( - ObjectNotExclusivelyOwned::HalfEdge { references: _ } - ) - ) + ValidationError::MultipleReferencesToHalfEdge(_) ); Ok(()) diff --git a/crates/fj-core/src/validate/solid.rs b/crates/fj-core/src/validate/solid.rs index 031d93199..75c1df518 100644 --- a/crates/fj-core/src/validate/solid.rs +++ b/crates/fj-core/src/validate/solid.rs @@ -9,8 +9,7 @@ use crate::{ use fj_math::Point; use super::{ - references::{ObjectNotExclusivelyOwned, ReferenceCounter}, - Validate, ValidationConfig, ValidationError, + references::ReferenceCounter, Validate, ValidationConfig, ValidationError, }; impl Validate for Solid { @@ -67,10 +66,6 @@ pub enum SolidValidationError { /// Position of second vertex position_b: Point<3>, }, - - /// Object within solid referenced by more than one other object - #[error("Object within solid referenced by more than one other Object")] - MultipleReferences(#[from] ObjectNotExclusivelyOwned), } impl SolidValidationError { @@ -168,11 +163,11 @@ impl SolidValidationError { }); validate_references!( - errors, SolidValidationError; - referenced_regions, Region; - referenced_faces, Face; - referenced_edges, HalfEdge; - referenced_cycles, Cycle; + errors; + referenced_regions, MultipleReferencesToRegion; + referenced_faces, MultipleReferencesToFace; + referenced_edges, MultipleReferencesToHalfEdge; + referenced_cycles, MultipleReferencesToCycle; ); } } @@ -187,10 +182,7 @@ mod tests { insert::Insert, }, topology::{Cycle, Face, HalfEdge, Region, Shell, Solid, Surface}, - validate::{ - references::ObjectNotExclusivelyOwned, SolidValidationError, - Validate, ValidationError, - }, + validate::{Validate, ValidationError}, Core, }; @@ -238,9 +230,7 @@ mod tests { assert_contains_err!( core, invalid_solid, - ValidationError::Solid(SolidValidationError::MultipleReferences( - ObjectNotExclusivelyOwned::Face { references: _ } - )) + ValidationError::MultipleReferencesToFace(_) ); let valid_solid = Solid::new(vec![]).insert(&mut core); @@ -284,9 +274,7 @@ mod tests { assert_contains_err!( core, invalid_solid, - ValidationError::Solid(SolidValidationError::MultipleReferences( - ObjectNotExclusivelyOwned::Region { references: _ } - )) + ValidationError::MultipleReferencesToRegion(_) ); let valid_solid = Solid::new(vec![]).insert(&mut core); @@ -334,9 +322,7 @@ mod tests { assert_contains_err!( core, invalid_solid, - ValidationError::Solid(SolidValidationError::MultipleReferences( - ObjectNotExclusivelyOwned::Cycle { references: _ } - )) + ValidationError::MultipleReferencesToCycle(_) ); let valid_solid = Solid::new(vec![]).insert(&mut core); @@ -376,9 +362,7 @@ mod tests { assert_contains_err!( core, invalid_solid, - ValidationError::Solid(SolidValidationError::MultipleReferences( - ObjectNotExclusivelyOwned::HalfEdge { references: _ } - )) + ValidationError::MultipleReferencesToHalfEdge(_) ); let valid_solid = Solid::new(vec![]).insert(&mut core); diff --git a/crates/fj-core/src/validation/error.rs b/crates/fj-core/src/validation/error.rs index 0b75cce32..c054953cd 100644 --- a/crates/fj-core/src/validation/error.rs +++ b/crates/fj-core/src/validation/error.rs @@ -1,6 +1,11 @@ use std::{convert::Infallible, fmt}; -use crate::validate::{SketchValidationError, SolidValidationError}; +use crate::{ + topology::{Cycle, Face, HalfEdge, Region, Shell}, + validate::{ + ObjectNotExclusivelyOwned, SketchValidationError, SolidValidationError, + }, +}; use super::checks::{ AdjacentHalfEdgesNotConnected, CoincidentHalfEdgesAreNotSiblings, @@ -37,6 +42,22 @@ pub enum ValidationError { #[error(transparent)] InteriorCycleHasInvalidWinding(#[from] InteriorCycleHasInvalidWinding), + /// Multiple references to [`Cycle`] + #[error(transparent)] + MultipleReferencesToCycle(ObjectNotExclusivelyOwned), + + /// Multiple references to [`Face`] + #[error(transparent)] + MultipleReferencesToFace(ObjectNotExclusivelyOwned), + + /// Multiple references to [`HalfEdge`] + #[error(transparent)] + MultipleReferencesToHalfEdge(ObjectNotExclusivelyOwned), + + /// Multiple references to [`Region`] + #[error(transparent)] + MultipleReferencesToRegion(ObjectNotExclusivelyOwned), + /// `Solid` validation error #[error("`Solid` validation error")] Solid(#[from] SolidValidationError),