Support Ukraine. DONATE.
A blog about software development.

Nutype 0.4.2 with Arbitrary support!

Serhii Potapov April 10, 2024 #rust #macro #newtype #nutype #arbitrary #fuzzing

I'm thrilled to unveil the latest update, Nutype 0.4.2, now available for the community. Dive into the details on GitHub.

About Nutype

Nutype is an innovative Rust crate designed to revolutionize the standard newtype pattern. By incorporating procedural macros, it introduces features such as sanitization and validation, ensuring that values are only instantiated once they satisfy specific, predefined criteria.

Exciting New Feature: Arbitrary

With the release of Nutype 0.4.2, we've introduced the ability to derive the Arbitrary trait, a powerful tool for generating pseudo-random structures of a given type. This functionality is crucial for fuzzing and property-based testing, expanding the utility of Nutype. For an in-depth exploration, check out my previous article, Property-Based Testing in Rust with Arbitrary.

What sets this feature apart is its intelligent derived implementation of Arbitrary, which respects the established validation rules. Here’s how it works:

use nutype::nutype;
use arbtest::arbtest;
use arbitrary::Arbitrary;

#[nutype(
    derive(Arbitrary, AsRef),
    sanitize(trim),
    validate(
        not_empty,
        len_char_max = 100,
    ),
)]
pub struct Title(String);

fn main() {
    arbtest(|u| {
        // Generate an arbitrary valid Title
        let title = Title::arbitrary(u)?;

        // The inner string is guaranteed to be non-empty
        assert!(!title.as_ref().is_empty());

        // The inner string is guaranteed not to exceed 100 characters
        assert!(title.as_ref().chars().count() <= 100);
        Ok(())
    });
}

This functionality extends to integer and float-based types as well:

#[nutype(
    derive(Arbitrary, AsRef),
    validate(
        finite,
        greater_or_equal = -1.0,
        less_or_equal = 1.0,
    ),
)]
pub struct PearsonCorrelation(f64);

fn main() {
    arbtest(|u| {
        let correlation = PearsonCorrelation::arbitrary(u)?;
        assert!(correlation.as_ref().is_finite());
        assert!(*correlation.as_ref() >= -1.0);
        assert!(*correlation.as_ref() <= 1.0);
        Ok(())
    });
}

Understanding Limitations

While Nutype 0.4.2 expands possibilities, certain scenarios might limit the derivation of Arbitrary for valid newtypes, resulting in a compilation error. This occurs in cases like custom validation logic defined with the predicate = attribute:

#[nutype(
    derive(Arbitrary, AsRef),
    validate(
        predicate = |x: &i32| x % 2 == 0,
    ),
)]
pub struct Even(i32);

Error:

error: Cannot derive trait `Arbitrary` for a type with `predicate` validator
  --> dummy/src/main.rs:5:1
   |
5  | / #[nutype(
6  | |     derive(Arbitrary, AsRef),
7  | |     validate(
8  | |         predicate = |x: &i32| x % 2 == 0,
9  | |     ),
10 | | )]
   | |__^
   |

Other changes

For a comprehensive overview of all enhancements and modifications, please refer to the release notes.

Back to top