Baike.dev
All toolsOnline toolsAI codingTrendingOpen sourceNewsSubmit
Log in
< Back to tools
N

nutype

> 编程语言
Open source

Rust newtype with guarantees

1.8K stars0 likes1 views
WebsiteGitHub

About

Rust newtype with guarantees

The newtype with guarantees.

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
  • Inner types (String | Integer | Float | Decimal | Other)
  • Custom (sanitizers | validators | errors)
  • Deriving traits
  • Constants
  • Recipes
  • Constructor visibility
  • Breaking constraints with new_unchecked
  • Feature Flags
  • Support Ukrainian military forces
  • Similar projects

Quick start

…

For more please see:

  • Examples
  • Tests

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)
  • Decimal (rust_decimal::Decimal, requires the rust_decimal feature)
  • 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:

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

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

rust
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:

rust
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:

rust
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
greater Exclusive lower bound GreaterViolated greater = 0.0
greater_or_equal Inclusive lower bound GreaterOrEqualViolated greater_or_equal = 0.0
finite Check against NaN and infinity FiniteViolated finite
predicate Custom predicate PredicateViolated predicate = |val| val != 50.0
with Custom validator with a custom error N/A (see example below)

Float derivable traits

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

It's also possible to derive Eq and Ord if the validation rules guarantee that NaN is excluded. This can be done applying by finite validation. For example:

rust
#[nutype(
    validate(finite),
    derive(PartialEq, Eq, PartialOrd, Ord),
)]
struct Size(f64);

Decimal

The rust_decimal::Decimal type is supported as an inner type behind the rust_decimal feature flag.

Requirements:

  • The rust_decimal feature of nutype is enabled.
  • You have to explicitly include rust_decimal as a dependency of your crate.
  • For derive(Arbitrary) you also need rust_decimal's rust-fuzz feature, and for derive(Serialize, Deserialize) its serde feature.

All three spellings of the inner type are detected:

rust
struct A(Decimal);                  // assumes `use rust_decimal::Decimal;`
struct B(rust_decimal::Decimal);
struct C(::rust_decimal::Decimal);

Example:

rust
use nutype::nutype;
use rust_decimal::Decimal;

#[nutype(
    validate(greater_or_equal = 0, less_or_equal = 100),  // bare literals, no dec!() needed
    derive(Debug, Clone, Copy, PartialEq, PartialOrd, Display),
)]
pub struct Percentage(Decimal);

Note the asymmetry: bounds in the attribute are written as bare literals (parsed at compile time via rust_decimal's FromStr), while values passed to try_new() are real Decimals, so you typically reach for dec!(...) or Decimal::from(...) there.

Decimal sanitizers

Sanitizer Description Example
with Custom sanitizer. with = |d: Decimal| d.round_dp(2)

Decimal validators

Validator Description Error variant Example
less Exclusive upper bound LessViolated less = 100
less_or_equal Inclusive upper bound

Issues· 0 open

View all issuesOpen on GitHub

No open issues yet, or sync has not completed.

> Tags

Rustdatadata-structuresinvarianceinvariant

No comments yet. Be the first to share.

> Details

PublishedAug 1, 2026
UpdatedSep 17, 2026
Category编程语言
PricingOpen source

> Related tools

T
TypeScript
JavaScript 的超集,为前端与全栈提供静态类型
P
Python
通用编程语言,广泛用于 Web、数据与 AI
G
Go
Google 推出的简洁高效系统语言