Skip to content

Commit

Permalink
Merge pull request #116 from greyblake/arbitrary-float
Browse files Browse the repository at this point in the history
Arbitrary support for float types
  • Loading branch information
greyblake committed Jan 5, 2024
2 parents 80aafef + bcc4cca commit affa79c
Show file tree
Hide file tree
Showing 12 changed files with 600 additions and 39 deletions.
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@

* Support integration with [`arbitrary`](https://crates.io/crates/arbitrary) crate (see `arbitrary` feature).
* Support `Arbitrary` for integer types
* Ability to specify boundaries (`greater`, `greater_or_equal`, `less`, `less_or_equal`, `len_char_min`, `len_char_max`) with expressions or constants.
* Support `Arbitrary` for float types
* Ability to specify boundaries (`greater`, `greater_or_equal`, `less`, `less_or_equal`, `len_char_min`, `len_char_max`) with expressions or named constants.

### v0.4.0 - 2023-11-21
* Support of arbitrary inner types with custom sanitizers and validators.
Expand Down
9 changes: 9 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

11 changes: 11 additions & 0 deletions examples/float_arbitrary/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
[package]
name = "float_arbitrary"
version = "0.1.0"
edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
arbitrary = "1.3.2"
arbtest = "0.2.0"
nutype = { path = "../../nutype", features = ["arbitrary"] }
114 changes: 114 additions & 0 deletions examples/float_arbitrary/src/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
use arbitrary::Arbitrary;
use nutype::nutype;

#[nutype(
derive(Debug, Arbitrary),
sanitize(with = |x| x),
)]
struct UnrestrictedFloatNumber(f64);

#[nutype(derive(Debug, Arbitrary), validate(finite))]
struct FiniteF64(f64);

#[nutype(derive(Debug, Arbitrary), validate(finite))]
struct FiniteF32(f32);

#[nutype(derive(Debug, Arbitrary), validate(greater_or_equal = -64.4))]
struct GreaterOrEqualF64(f64);

#[nutype(derive(Debug, Arbitrary), validate(greater_or_equal = 32.2))]
struct GreaterOrEqualF32(f32);

#[nutype(derive(Debug, Arbitrary), validate(greater = -64.0))]
struct GreaterF64(f64);

#[nutype(derive(Debug, Arbitrary), validate(greater = 32.0))]
struct GreaterF32(f32);

#[nutype(derive(Debug, Arbitrary), validate(greater = -1.0, less = 1.0))]
struct GreaterAndLessF64(f64);

#[nutype(derive(Debug, Arbitrary), validate(greater = -10.0, less = 10.0))]
struct GreaterAndLessF32(f32);

#[nutype(derive(Debug, Arbitrary), validate(greater_or_equal = -10.0, less = 10.0))]
struct GreaterOrEqualAndLessF32(f32);

#[nutype(derive(Debug, Arbitrary), validate(greater = -10.0, less_or_equal = 10.0))]
struct GreaterAndLessOrEqualF32(f32);

#[nutype(derive(Debug, Arbitrary), validate(greater = -1.0, less_or_equal = -0.5))]
struct GreaterOrEqualAndLessOrEqualF64(f64);

fn main() {
arbtest::builder().run(|u| {
let _num = UnrestrictedFloatNumber::arbitrary(u)?.into_inner();
Ok(())
});

arbtest::builder().run(|u| {
let value: f64 = FiniteF64::arbitrary(u)?.into_inner();
assert!(value.is_finite());
Ok(())
});

arbtest::builder().run(|u| {
let value: f32 = FiniteF32::arbitrary(u)?.into_inner();
assert!(value.is_finite());
Ok(())
});

arbtest::builder().run(|u| {
let value: f64 = GreaterOrEqualF64::arbitrary(u)?.into_inner();
assert!(value >= -64.4);
Ok(())
});

arbtest::builder().run(|u| {
let value: f32 = GreaterOrEqualF32::arbitrary(u)?.into_inner();
assert!(value >= 32.2);
Ok(())
});

arbtest::builder().run(|u| {
let value: f64 = GreaterF64::arbitrary(u)?.into_inner();
assert!(value > -64.0);
Ok(())
});

arbtest::builder().run(|u| {
let value: f32 = GreaterF32::arbitrary(u)?.into_inner();
assert!(value > 32.0);
Ok(())
});

arbtest::builder().run(|u| {
let value: f64 = GreaterAndLessF64::arbitrary(u)?.into_inner();
assert!(value > -1.0 && value < 1.0);
Ok(())
});

arbtest::builder().run(|u| {
let value: f32 = GreaterAndLessF32::arbitrary(u)?.into_inner();
assert!(value > -10.0 && value < 10.0);
Ok(())
});

arbtest::builder().run(|u| {
let value: f32 = GreaterOrEqualAndLessF32::arbitrary(u)?.into_inner();
assert!((-10.0..10.0).contains(&value));
Ok(())
});

arbtest::builder().run(|u| {
let value: f32 = GreaterAndLessOrEqualF32::arbitrary(u)?.into_inner();
assert!(value > -10.0 && value <= 10.0);
Ok(())
});

arbtest::builder().run(|u| {
let value: f64 = GreaterOrEqualAndLessOrEqualF64::arbitrary(u)?.into_inner();
assert!((-1.0..=-0.5).contains(&value));
Ok(())
});
}
9 changes: 9 additions & 0 deletions nutype_macros/src/common/validate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,15 @@ where
return Err(err);
}

// less VS greater
if let (Some(lower), Some(upper)) = (maybe_greater.clone(), maybe_less.clone()) {
if lower.item >= upper.item {
let msg = "The lower bound (`greater`) cannot be equal or higher than the upper bound (`less`).";
let err = syn::Error::new(upper.span(), msg);
return Err(err);
}
}

let maybe_lower_bound = maybe_greater.or(maybe_greater_or_equal);
let maybe_upper_bound = maybe_less.or(maybe_less_or_equal);

Expand Down
7 changes: 4 additions & 3 deletions nutype_macros/src/float/gen/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -140,15 +140,16 @@ where
maybe_error_type_name: Option<ErrorTypeName>,
traits: HashSet<Self::TypedTrait>,
maybe_default_value: Option<syn::Expr>,
_guard: &FloatGuard<T>,
guard: &FloatGuard<T>,
) -> Result<GeneratedTraits, syn::Error> {
Ok(gen_traits(
gen_traits(
type_name,
inner_type,
maybe_error_type_name,
maybe_default_value,
traits,
))
guard,
)
}

fn gen_tests(
Expand Down
Loading

0 comments on commit affa79c

Please sign in to comment.