Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Complete transition to new validation infrastructure #1330

Merged
merged 4 commits into from
Nov 9, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion crates/fj-kernel/src/objects/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ use crate::{
storage::{Handle, Store},
validate::{
CycleValidationError, FaceValidationError, HalfEdgeValidationError,
SurfaceVertexValidationError, Validate2, VertexValidationError,
SurfaceVertexValidationError, Validate, VertexValidationError,
},
};

Expand Down
6 changes: 3 additions & 3 deletions crates/fj-kernel/src/validate/curve.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@ use std::convert::Infallible;

use crate::objects::{Curve, GlobalCurve};

use super::{Validate2, ValidationConfig};
use super::{Validate, ValidationConfig};

impl Validate2 for Curve {
impl Validate for Curve {
type Error = Infallible;

fn validate_with_config(
Expand All @@ -15,7 +15,7 @@ impl Validate2 for Curve {
}
}

impl Validate2 for GlobalCurve {
impl Validate for GlobalCurve {
type Error = Infallible;

fn validate_with_config(
Expand Down
6 changes: 3 additions & 3 deletions crates/fj-kernel/src/validate/cycle.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@ use crate::{
storage::Handle,
};

use super::{Validate2, ValidationConfig};
use super::{Validate, ValidationConfig};

impl Validate2 for Cycle {
impl Validate for Cycle {
type Error = CycleValidationError;

fn validate_with_config(
Expand Down Expand Up @@ -69,7 +69,7 @@ mod tests {
builder::{CycleBuilder, HalfEdgeBuilder, VertexBuilder},
objects::{Cycle, Objects},
partial::HasPartial,
validate::Validate2,
validate::Validate,
};

#[test]
Expand Down
8 changes: 4 additions & 4 deletions crates/fj-kernel/src/validate/edge.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,9 @@ use crate::{
storage::Handle,
};

use super::{Validate2, ValidationConfig};
use super::{Validate, ValidationConfig};

impl Validate2 for HalfEdge {
impl Validate for HalfEdge {
type Error = HalfEdgeValidationError;

fn validate_with_config(
Expand All @@ -33,7 +33,7 @@ impl Validate2 for HalfEdge {
}
}

impl Validate2 for GlobalEdge {
impl Validate for GlobalEdge {
type Error = Infallible;

fn validate_with_config(
Expand Down Expand Up @@ -204,7 +204,7 @@ mod tests {
builder::{HalfEdgeBuilder, VertexBuilder},
objects::{GlobalCurve, HalfEdge, Objects},
partial::HasPartial,
validate::Validate2,
validate::Validate,
};

#[test]
Expand Down
6 changes: 3 additions & 3 deletions crates/fj-kernel/src/validate/face.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@ use crate::{
storage::Handle,
};

use super::{Validate2, ValidationConfig};
use super::{Validate, ValidationConfig};

impl Validate2 for Face {
impl Validate for Face {
type Error = FaceValidationError;

fn validate_with_config(
Expand Down Expand Up @@ -108,7 +108,7 @@ mod tests {
builder::CycleBuilder,
objects::{Cycle, Face, Objects},
partial::HasPartial,
validate::Validate2,
validate::Validate,
};

#[test]
Expand Down
158 changes: 4 additions & 154 deletions crates/fj-kernel/src/validate/mod.rs
Original file line number Diff line number Diff line change
@@ -1,18 +1,4 @@
//! Infrastructure for validating shapes
//!
//! Validation enforces various constraints about shapes and the objects that
//! constitute them. These constraints fall into 4 categories:
//!
//! - **Coherence:** Local forms of objects must be consistent with their
//! canonical forms.
//! - **Geometric:** Comprises various object-specific constraints, for example
//! edges or faces might not be allowed to intersect.
//! - **Structural:** All other objects that an object references must be part
//! of the same shape.
//! - **Uniqueness:** Objects within a shape must be unique.
//!
//! Please note that not all of these validation categories are fully
//! implemented, as of this writing.
//! Infrastructure for validating objects

mod curve;
mod cycle;
Expand All @@ -22,87 +8,23 @@ mod shell;
mod sketch;
mod solid;
mod surface;
mod uniqueness;
mod vertex;

pub use self::{
cycle::CycleValidationError,
edge::HalfEdgeValidationError,
face::FaceValidationError,
uniqueness::UniquenessIssues,
vertex::{SurfaceVertexValidationError, VertexValidationError},
};

use std::{collections::HashSet, convert::Infallible, ops::Deref};
use std::convert::Infallible;

use fj_math::Scalar;

use crate::iter::ObjectIters;

/// Validate an object
///
/// This trait is used automatically when inserting an object into a store.
pub trait Validate: Sized {
/// Validate the object using default configuration
///
/// The following calls are equivalent:
/// ``` rust
/// # use fj_kernel::{
/// # objects::{GlobalVertex, Objects},
/// # validate::{Validate, ValidationConfig},
/// # };
/// # let objects = Objects::new();
/// # let object = objects.global_vertices.insert(
/// # GlobalVertex::from_position([0., 0., 0.])
/// # );
/// object.validate();
/// ```
/// ``` rust
/// # use fj_kernel::{
/// # objects::{GlobalVertex, Objects},
/// # validate::{Validate, ValidationConfig},
/// # };
/// # let objects = Objects::new();
/// # let object = objects.global_vertices.insert(
/// # GlobalVertex::from_position([0., 0., 0.])
/// # );
/// object.validate_with_config(&ValidationConfig::default());
/// ```
fn validate(self) -> Result<Validated<Self>, ValidationError> {
self.validate_with_config(&ValidationConfig::default())
}

/// Validate the object
fn validate_with_config(
self,
config: &ValidationConfig,
) -> Result<Validated<Self>, ValidationError>;
}

impl<T> Validate for T
where
T: for<'r> ObjectIters<'r>,
{
fn validate_with_config(
self,
config: &ValidationConfig,
) -> Result<Validated<Self>, ValidationError> {
let mut global_vertices = HashSet::new();

for global_vertex in self.global_vertex_iter() {
uniqueness::validate_vertex(
global_vertex,
&global_vertices,
config.distinct_min_distance,
)?;

global_vertices.insert(*global_vertex);
}

Ok(Validated(self))
}
}

/// Validate an object
pub trait Validate2: Sized {
/// The error that validation of the implementing type can result in
type Error: Into<ValidationError>;

Expand Down Expand Up @@ -150,35 +72,10 @@ impl Default for ValidationConfig {
}
}

/// Wrapper around an object that indicates the object has been validated
///
/// Returned by implementations of `Validate`.
#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash, Ord, PartialOrd)]
pub struct Validated<T>(T);

impl<T> Validated<T> {
/// Consume this instance of `Validated` and return the wrapped object
pub fn into_inner(self) -> T {
self.0
}
}

impl<T> Deref for Validated<T> {
type Target = T;

fn deref(&self) -> &Self::Target {
&self.0
}
}

/// An error that can occur during a validation
#[allow(clippy::large_enum_variant)]
#[derive(Debug, thiserror::Error)]
pub enum ValidationError {
/// Uniqueness validation failed
#[error("Uniqueness validation failed")]
Uniqueness(#[from] UniquenessIssues),

/// `Cycle` validation error
#[error(transparent)]
Cycle(#[from] CycleValidationError),
Expand All @@ -205,50 +102,3 @@ impl From<Infallible> for ValidationError {
match infallible {}
}
}

#[cfg(test)]
mod tests {
use fj_math::{Point, Scalar};

use crate::{
objects::{GlobalVertex, Objects},
validate::{Validate, ValidationConfig, ValidationError},
};

#[test]
fn uniqueness_vertex() -> anyhow::Result<()> {
let objects = Objects::new();
let mut shape = Vec::new();

let deviation = Scalar::from_f64(0.25);

let a = Point::from([0., 0., 0.]);

let mut b = a;
b.x += deviation;

let config = ValidationConfig {
distinct_min_distance: deviation * 2.,
..ValidationConfig::default()
};

// Adding a vertex should work.
shape.push(
objects
.global_vertices
.insert(GlobalVertex::from_position(a)),
);
shape.clone().validate_with_config(&config)?;

// Adding a second vertex that is considered identical should fail.
shape.push(
objects
.global_vertices
.insert(GlobalVertex::from_position(b)),
);
let result = shape.validate_with_config(&config);
assert!(matches!(result, Err(ValidationError::Uniqueness(_))));

Ok(())
}
}
4 changes: 2 additions & 2 deletions crates/fj-kernel/src/validate/shell.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@ use std::convert::Infallible;

use crate::objects::Shell;

use super::{Validate2, ValidationConfig};
use super::{Validate, ValidationConfig};

impl Validate2 for Shell {
impl Validate for Shell {
type Error = Infallible;

fn validate_with_config(
Expand Down
4 changes: 2 additions & 2 deletions crates/fj-kernel/src/validate/sketch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@ use std::convert::Infallible;

use crate::objects::Sketch;

use super::{Validate2, ValidationConfig};
use super::{Validate, ValidationConfig};

impl Validate2 for Sketch {
impl Validate for Sketch {
type Error = Infallible;

fn validate_with_config(
Expand Down
4 changes: 2 additions & 2 deletions crates/fj-kernel/src/validate/solid.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@ use std::convert::Infallible;

use crate::objects::Solid;

use super::{Validate2, ValidationConfig};
use super::{Validate, ValidationConfig};

impl Validate2 for Solid {
impl Validate for Solid {
type Error = Infallible;

fn validate_with_config(
Expand Down
4 changes: 2 additions & 2 deletions crates/fj-kernel/src/validate/surface.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@ use std::convert::Infallible;

use crate::objects::Surface;

use super::{Validate2, ValidationConfig};
use super::{Validate, ValidationConfig};

impl Validate2 for Surface {
impl Validate for Surface {
type Error = Infallible;

fn validate_with_config(
Expand Down
51 changes: 0 additions & 51 deletions crates/fj-kernel/src/validate/uniqueness.rs

This file was deleted.

Loading