SkillAgentSearch skills...

Nutype

Rust newtype with guarantees πŸ‡ΊπŸ‡¦ πŸ¦€

Install / Use

/learn @greyblake/Nutype

README

<p align="center"> <picture> <source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/greyblake/nutype/master/art/rust_nutype_inverted.png"> <source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/greyblake/nutype/master/art/rust_nutype.png"> <img width="300" alt="Rust Nutype Logo" src="https://raw.githubusercontent.com/greyblake/nutype/master/art/rust_nutype.png"> </picture> </p> <h2 align="center">The newtype with guarantees.</h2> <p align="center"> <a href="https://github.com/greyblake/nutype/actions/workflows/ci.yml" rel="nofollow"><img src="https://github.com/greyblake/nutype/actions/workflows/ci.yml/badge.svg" alt="Nutype Build Status"></a> <a href="https://docs.rs/nutype" rel="nofollow"><img src="https://docs.rs/nutype/badge.svg" alt="Nutype Documentation"></a> <a href="https://github.com/greyblake/nutype/discussions"><img src="https://img.shields.io/github/discussions/greyblake/nutype"/></a> <p>

Nutype is a proc macro that allows adding extra constraints like sanitization and validation to the regular newtype pattern. The generated code makes it impossible to instantiate a value without passing the checks. It works this way even with serde deserialization.

Quick start

use nutype::nutype;

// Define newtype Username
#[nutype(
    sanitize(trim, lowercase),
    validate(not_empty, len_char_max = 20),
    derive(Debug, PartialEq, Clone),
)]
pub struct Username(String);

// We can obtain a value of Username with `::try_new()`.
// Note that Username holds a sanitized string
assert_eq!(
    Username::try_new("   FooBar  ").unwrap().into_inner(),
    "foobar"
);

// It's impossible to obtain an invalid Username
// Note that we also got `UsernameError` enum generated implicitly
// based on the validation rules.
assert_eq!(
    Username::try_new("   "),
    Err(UsernameError::NotEmptyViolated),
);
assert_eq!(
    Username::try_new("TheUserNameIsVeryVeryLong"),
    Err(UsernameError::LenCharMaxViolated),
);

For more please see:

Inner types

Available sanitizers, validators, and derivable traits are determined by the inner type, which falls into the following categories:

  • String
  • Integer (u8, u16,u32, u64, u128, i8, i16, i32, i64, i128, usize, isize)
  • Float (f32, f64)
  • Anything else

String

At the moment the string inner type supports only String (owned) type.

String sanitizers

| Sanitizer | Description | Example | |-------------|-------------------------------------------------------------------------------------|-------------------------------------------------| | trim | Removes leading and trailing whitespaces | trim | | lowercase | Converts the string to lowercase | lowercase | | uppercase | Converts the string to uppercase | uppercase | | with | Custom sanitizer. A function or closure that receives String and returns String | with = \|mut s: String\| ( s.truncate(5); s ) |

String validators

| Validator | Description | Error variant | Example | |-----------------|---------------------------------------------------------------------------------|-----------------------|----------------------------------------------| | len_char_min | Min length of the string (in chars, not bytes) | LenCharMinViolated | len_char_min = 5 | | len_char_max | Max length of the string (in chars, not bytes) | LenCharMaxViolated | len_char_max = 255 | | len_utf16_min | Min length of the string in UTF-16 code units (useful for JavaScript interop) | LenUtf16MinViolated | len_utf16_min = 5 | | len_utf16_max | Max length of the string in UTF-16 code units (useful for JavaScript interop) | LenUtf16MaxViolated | len_utf16_max = 255 | | not_empty | Rejects an empty string | NotEmptyViolated | not_empty | | regex | Validates format with a regex. Requires regex feature. | RegexViolated | regex = "^[0-9]{7}$" or regex = ID_REGEX | | predicate | Custom validator. A function or closure that receives &str and returns bool | PredicateViolated | predicate = \|s: &str\| s.contains('@') | | with | Custom validator with a custom error | N/A | (see example below) |

Regex validation

Requirements:

  • regex feature of nutype is enabled.
  • You have to explicitly include regex as a dependency.

There are a number of ways you can use regex.

A regular expression can be defined right in place:

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

or it can be defined with std::sync::LazyLock:

use regex::Regex;

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

#[nutype(validate(regex = PHONE_NUMBER_REGEX))]
pub struct PhoneNumber(String);

or it can be defined with lazy_static:

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

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

#[nutype(validate(regex = PHONE_NUMBER_REGEX))]
pub struct PhoneNumber(String);

or once_cell:

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

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

#[nutype(validate(regex = PHONE_NUMBER_REGEX))]
pub struct PhoneNumber(String);

String derivable traits

The following traits can be derived for a string-based type: Debug, Clone, PartialEq, Eq, PartialOrd, Ord, FromStr, AsRef, Deref, From, TryFrom, Into, Hash, Borrow, Display, Default, Serialize, Deserialize.

Integer

The integer inner types are: u8, u16,u32, u64, u128, i8, i16, i32, i64, i128, usize, isize.

Integer sanitizers

| Sanitizer | Description | Example | |-----------|-------------------|------------------------------------| | with | Custom sanitizer. | with = \|raw\| raw.clamp(0, 100) |

Integer validators

| Validator | Description | Error variant | Example | | ------------------- | ------------------------------------- | ------------------------- | ------------------------------------ | | less | Exclusive upper bound | LessViolated | less = 100 | | less_or_equal | Inclusive upper bound | LessOrEqualViolated | less_or_equal = 99 | | greater | Exclusive lower bound | GreaterViolated | greater = 17 | | greater_or_equal | Inclusive lower bound | GreaterOrEqualViolated | greater_or_equal = 18 | | predicate | Custom predicate | PredicateViolated | predicate = \|num\| num % 2 == 0 | | with | Custom validator with a custom error | N/A | (see example below) |

Integer derivable traits

The following traits can be derived for an integer-based type: Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, FromStr, AsRef, Deref, Into, From, TryFrom, Hash, Borrow, Display, Default, Serialize, Deserialize.

Float

The float inner types are: f32, f64.

Float sanitizers

| Sanitizer | Description | Example | |-----------|-------------------|----------------------------------------| | with | Custom sanitizer. | with = \|val\| val.clamp(0.0, 100.0) |

Float validators

| Validator | Description | Error variant | Example | | ------------------ | ------------------------------------ | ------------------------ | ----------------------------------- | | less | Exclusive upper bound | LessViolated | less = 100.0 | | less_or_equal | Inclusive upper bound | LessOrEqualViolated | less_or_equal = 100.0

View on GitHub
GitHub Stars1.7k
CategoryDevelopment
Updated4d ago
Forks30

Languages

Rust

Security Score

100/100

Audited on Mar 27, 2026

No findings