#newtype #serde #validation

no-std validated_newtype

Simple newtypes with checked predicates (primarily for serde)

2 releases

0.1.1 Dec 24, 2019
0.1.0 Dec 24, 2019

#2754 in Rust patterns

MIT license

10KB
105 lines

validated_newtype

Simple checked newtype generator, primarily for use with serde. Serde support (and dependency) may be disabled with default_features = false. This is #![no_std] library.

Usage:

validated_newtype! {
    /// Documentation comments and attributes are applied
    #[derive(Debug, PartialOrd, Ord, PartialEq, Eq)]
    // base type name => optional visibility + newtype name
    u32 => pub Percent
    // condition to check when creating/deserializing
    if |n: &u32| *n <= 100;
    // error message if condition is not met
    error "percent must be in range 0-100"
}

let x: Percent = serde_json::from_str("42").unwrap();
assert_eq!(*x, 42);
let y: Result<Percent, _> = serde_json::from_str("1337");
assert!(y.is_err());

Instances of generated newtype can be created only via TryFrom or Deserialize, so they always hold valid data.

Dynamic error generation

validated_newtype! {
    #[derive(Debug)]
    u32 => pub Percent
    if |n: &u32| *n <= 100;
    else |n: &u32| format!("number {} is not in range 0-100", n) => String
}

// Deserialize for newtypes uses try_into internally
let x: Result<Percent, _> = 1337.try_into();
assert!(x.is_err());
assert_eq!(x.unwrap_err(), "number 1337 is not in range 0-100");

Manually implement TryFrom

validated_newtype! {
    #[derive(Debug)]
    u32 => pub Percent
}

impl TryFrom<u32> for Percent {
    type Error = &'static str;

    fn try_from(val: u32) -> Result<Self, Self::Error> {
        if val > 100 {
            Err("percent must be in range 0-100")
        } else {
            Ok(Self(val))
        }
    }
}

let x: Percent = serde_json::from_str("42").unwrap();
assert_eq!(*x, 42);
let y: Result<Percent, _> = serde_json::from_str("1337");
assert!(y.is_err());

License: MIT

Dependencies

~100–335KB