Skip to content

Commit

Permalink
Merge pull request #1907 from hannobraun/validation
Browse files Browse the repository at this point in the history
Improve handling of validation errors
  • Loading branch information
hannobraun authored Jun 26, 2023
2 parents ca96963 + 3e10906 commit 447720c
Show file tree
Hide file tree
Showing 9 changed files with 78 additions and 18 deletions.
18 changes: 17 additions & 1 deletion crates/fj-core/src/services/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,10 @@ mod objects;
mod service;
mod validation;

use crate::objects::{Object, ObjectSet, Objects, WithHandle};
use crate::{
objects::{Object, ObjectSet, Objects, WithHandle},
validate::ValidationErrors,
};

pub use self::{
objects::{InsertObject, Operation},
Expand Down Expand Up @@ -61,6 +64,19 @@ impl Services {
self.validation
.execute(ValidationCommand::OnlyValidate { objects }, &mut events);
}

/// Drop `Services`; return any unhandled validation error
pub fn drop_and_validate(self) -> Result<(), ValidationErrors> {
let errors = ValidationErrors(
self.validation.errors.values().cloned().collect(),
);

if errors.0.is_empty() {
Ok(())
} else {
Err(errors)
}
}
}

impl Default for Services {
Expand Down
3 changes: 2 additions & 1 deletion crates/fj-core/src/services/validation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ use super::State;
/// Errors that occurred while validating the objects inserted into the stores
#[derive(Default)]
pub struct Validation {
errors: BTreeMap<ObjectId, ValidationError>,
/// All unhandled validation errors
pub errors: BTreeMap<ObjectId, ValidationError>,
}

impl Drop for Validation {
Expand Down
20 changes: 19 additions & 1 deletion crates/fj-core/src/validate/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ pub use self::{
solid::SolidValidationError,
};

use std::convert::Infallible;
use std::{convert::Infallible, fmt};

use fj_math::Scalar;

Expand Down Expand Up @@ -124,3 +124,21 @@ impl From<Infallible> for ValidationError {
match infallible {}
}
}

/// A collection of validation errors
#[derive(Debug, thiserror::Error)]
pub struct ValidationErrors(pub Vec<ValidationError>);

impl fmt::Display for ValidationErrors {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let num_errors = self.0.len();

writeln!(f, "{num_errors} unhandled validation errors:")?;

for err in &self.0 {
writeln!(f, "{err}")?;
}

Ok(())
}
}
4 changes: 4 additions & 0 deletions crates/fj/src/args.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,10 @@ pub struct Args {
/// How much the export can deviate from the original model
#[arg(short, long, value_parser = parse_tolerance)]
pub tolerance: Option<Tolerance>,

/// Ignore validation errors
#[arg(short, long)]
pub ignore_validation: bool,
}

impl Args {
Expand Down
31 changes: 24 additions & 7 deletions crates/fj/src/handle_model.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
use std::ops::Deref;

use fj_core::algorithms::{
approx::{InvalidTolerance, Tolerance},
bounding_volume::BoundingVolume,
triangulate::Triangulate,
use std::{mem, ops::Deref};

use fj_core::{
algorithms::{
approx::{InvalidTolerance, Tolerance},
bounding_volume::BoundingVolume,
triangulate::Triangulate,
},
services::Services,
validate::ValidationErrors,
};
use fj_interop::model::Model;
use fj_math::{Aabb, Point, Scalar};
Expand All @@ -18,13 +22,22 @@ use crate::Args;
///
/// This function is used by Fornjot's own testing infrastructure, but is useful
/// beyond that, when using Fornjot directly to define a model.
pub fn handle_model<M>(model: impl Deref<Target = M>) -> Result
pub fn handle_model<M>(
model: impl Deref<Target = M>,
services: Services,
) -> Result
where
for<'r> (&'r M, Tolerance): Triangulate,
M: BoundingVolume<3>,
{
let args = Args::parse();

if args.ignore_validation {
mem::forget(services);
} else {
services.drop_and_validate()?;
}

let aabb = model.aabb().unwrap_or(Aabb {
min: Point::origin(),
max: Point::origin(),
Expand Down Expand Up @@ -80,4 +93,8 @@ pub enum Error {
/// Invalid tolerance
#[error(transparent)]
Tolerance(#[from] InvalidTolerance),

/// Unhandled validation errors
#[error(transparent)]
Validation(#[from] ValidationErrors),
}
5 changes: 3 additions & 2 deletions models/all/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
use fj::{core::services::Services, handle_model};

fn main() -> fj::Result {
let model = all::model(&mut Services::new());
handle_model(model)?;
let mut services = Services::new();
let model = all::model(&mut services);
handle_model(model, services)?;
Ok(())
}
5 changes: 3 additions & 2 deletions models/cuboid/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
use fj::{core::services::Services, handle_model};

fn main() -> fj::Result {
let model = cuboid::model(3., 2., 1., &mut Services::new());
handle_model(model)?;
let mut services = Services::new();
let model = cuboid::model(3., 2., 1., &mut services);
handle_model(model, services)?;
Ok(())
}
5 changes: 3 additions & 2 deletions models/spacer/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
use fj::{core::services::Services, handle_model};

fn main() -> fj::Result {
let model = spacer::model(1., 0.5, 1., &mut Services::new());
handle_model(model)?;
let mut services = Services::new();
let model = spacer::model(1., 0.5, 1., &mut services);
handle_model(model, services)?;
Ok(())
}
5 changes: 3 additions & 2 deletions models/star/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
use fj::{core::services::Services, handle_model};

fn main() -> fj::Result {
let model = star::model(5, 1., 2., 1., &mut Services::new());
handle_model(model)?;
let mut services = Services::new();
let model = star::model(5, 1., 2., 1., &mut services);
handle_model(model, services)?;
Ok(())
}

0 comments on commit 447720c

Please sign in to comment.