Support Ukraine. DONATE.
A blog about software development.

Nutype 0.2.0 is out!

Serhii Potapov April 11, 2023 #rust #macro #newtype #nutype

I recently released nutype version 0.2.0, and I'd like to cover some of it's features in this post.

What is nutype?

Nutype is a Rust library powered by proc macros that allows to define newtypes which are guaranteed to satisfy some specified constraints. The constraints are typically set of sanitizers and validators.

Validating string types with regex

The biggest thing in the release is support of regex.

For this you'd need the following:

Now it's possible to enforce format of a string with a given regex, for example:

use nutype::nutype;

#[nutype(validate(regex = "^[0-9]{3}-[0-9]{2}-[0-9]{4}$"))]
pub struct Ssn(String);

// valid SSN
let ssn = Ssn::new("123-45-6789").unwrap();

// Invalid SSN
assert_eq!(
    Ssn::new("123-45-67"),
    SsnError::RegexMismatch
);

If you need to use the regex in multiple places, you're already probably using lazy_static. So nutype can handle this too:

use lazy_static::lazy_static;
use regex::Regex;
use nutype::nutype;

lazy_static! {
    static ref SSN_REGEX: Regex = Regex::new("^[0-9]{3}-[0-9]{2}-[0-9]{4}$").unwrap();
}

#[nutype(validate(regex = SSN_REGEX))]
pub struct Ssn(String);

If you prefer once_cell over lazy_static, no problem:

use once_cell::sync::Lazy;
use regex::Regex;
use nutype::nutype;

static SSN_REGEX: Lazy<Regex> =
    Lazy::new(|| Regex::new("^[0-9]{3}-[0-9]{2}-[0-9]{4}$").unwrap());

#[nutype(validate(regex = SSN_REGEX))]
pub struct Ssn(String);

Bypassing nutype guards

In very extreme cases, for the sake of performance, you may want to be able to initiate nutype values avoiding sanitization and validation. But it's your responsibility to guarantee that the data satisfy the constraints.

This feature was requested, but since it allows you to shoot your own foot, nutype makes it very verbose and discourages its usage, unless it's really needed.

So, here we are. For this you need to enable new_unchecked feature of nutype crate.

#[nutype(
    new_unchecked
    validate(min = 0.0, max = 100.0)
)]
#[derive(Debug)]
pub struct Percent(f64);

// Using `::new()` hits the validation guard, which returns TooBig error
assert_eq!(
    Percent::new(109.0).unwrap_err(),
    PercentError::TooBig,
);

// But using `::new_unchecked()` within `unsafe` it's possible to bypass
// the guard and obtain invalid instance of Percent.
let percent: Percent = unsafe { Percent::new_unchecked(109.0) };

Please note:

Other changes

To get full list of changes please refer to nutype v0.2.0 release notes.

Back to top