Skip to content

Commit

Permalink
Implement ValidationCheck for the check
Browse files Browse the repository at this point in the history
The way it was previously, fully qualified method call syntax would have
been required to run a validation check. This wasn't visible in the code
so far, as there only is one validation check currently.

This change makes running validation checks a bit more convenient
(compared to what it would have needed to be, not what's currently in
the code). It preserves the discoverability, as the implementations are
still listed in the documentation of the object type.
  • Loading branch information
hannobraun committed Feb 28, 2024
1 parent cdc0ef7 commit 37688be
Show file tree
Hide file tree
Showing 3 changed files with 25 additions and 15 deletions.
9 changes: 7 additions & 2 deletions crates/fj-core/src/validate/cycle.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
use crate::{
objects::Cycle,
validation::{ValidationCheck, ValidationConfig, ValidationError},
validation::{
checks::AdjacentHalfEdgesNotConnected, ValidationCheck,
ValidationConfig, ValidationError,
},
};

use super::Validate;
Expand All @@ -11,6 +14,8 @@ impl Validate for Cycle {
config: &ValidationConfig,
errors: &mut Vec<ValidationError>,
) {
errors.extend(self.check(config).map(Into::into));
errors.extend(
AdjacentHalfEdgesNotConnected::check(self, config).map(Into::into),
);
}
}
14 changes: 8 additions & 6 deletions crates/fj-core/src/validation/checks/half_edge_connection.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,12 +37,12 @@ pub struct AdjacentHalfEdgesNotConnected {
pub unconnected_half_edges: [Handle<HalfEdge>; 2],
}

impl ValidationCheck<AdjacentHalfEdgesNotConnected> for Cycle {
impl ValidationCheck<Cycle> for AdjacentHalfEdgesNotConnected {
fn check(
&self,
object: &Cycle,
config: &ValidationConfig,
) -> impl Iterator<Item = AdjacentHalfEdgesNotConnected> {
self.half_edges().pairs().filter_map(|(first, second)| {
) -> impl Iterator<Item = Self> {
object.half_edges().pairs().filter_map(|(first, second)| {
let end_pos_of_first_half_edge = {
let [_, end] = first.boundary().inner;
first.path().point_from_path_coords(end)
Expand Down Expand Up @@ -80,12 +80,14 @@ mod tests {
Core,
};

use super::AdjacentHalfEdgesNotConnected;

#[test]
fn adjacent_half_edges_connected() -> anyhow::Result<()> {
let mut core = Core::new();

let valid = Cycle::polygon([[0., 0.], [1., 0.], [1., 1.]], &mut core);
valid.check_and_return_first_error()?;
AdjacentHalfEdgesNotConnected::check_and_return_first_error(&valid)?;

let invalid = valid.update_half_edge(
valid.half_edges().first(),
Expand All @@ -94,7 +96,7 @@ mod tests {
},
&mut core,
);
invalid.check_and_expect_one_error();
AdjacentHalfEdgesNotConnected::check_and_expect_one_error(&invalid);

Ok(())
}
Expand Down
17 changes: 10 additions & 7 deletions crates/fj-core/src/validation/validation_check.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,20 @@ use super::ValidationConfig;
///
/// This trait is implemented once per validation check and object it applies
/// to. `Self` is the object, while `T` identifies the validation check.
pub trait ValidationCheck<T> {
pub trait ValidationCheck<T>: Sized {
/// Run the validation check on the implementing object
fn check(&self, config: &ValidationConfig) -> impl Iterator<Item = T>;
fn check(
object: &T,
config: &ValidationConfig,
) -> impl Iterator<Item = Self>;

/// Convenience method to run the check return the first error
///
/// This method is designed for convenience over flexibility (it is intended
/// for use in unit tests), and thus always uses the default configuration.
fn check_and_return_first_error(&self) -> Result<(), T> {
fn check_and_return_first_error(object: &T) -> Result<(), Self> {
let config = ValidationConfig::default();
let mut errors = self.check(&config);
let mut errors = Self::check(object, &config);

if let Some(err) = errors.next() {
return Err(err);
Expand All @@ -29,12 +32,12 @@ pub trait ValidationCheck<T> {
///
/// This method is designed for convenience over flexibility (it is intended
/// for use in unit tests), and thus always uses the default configuration.
fn check_and_expect_one_error(&self) -> T
fn check_and_expect_one_error(object: &T) -> Self
where
T: Display,
Self: Display,
{
let config = ValidationConfig::default();
let mut errors = self.check(&config).peekable();
let mut errors = Self::check(object, &config).peekable();

let err = errors
.next()
Expand Down

0 comments on commit 37688be

Please sign in to comment.