4 releases

Uses new Rust 2021

new 0.2.1 May 21, 2022
0.2.0 May 10, 2022
0.1.2 May 4, 2022
0.1.1 May 4, 2022
0.1.0 May 4, 2022

#181 in Data structures

Download history 60/week @ 2022-05-01 34/week @ 2022-05-08 90/week @ 2022-05-15

186 downloads per month

MIT/Apache

29KB
516 lines

type-rules

A tool to easily constrain a struct and recover errors.

Table of Contents

  1. Install
  2. Basic checking
  3. Advanced checking
  4. Make your own rule
  5. Rules list

Install

# Cargo.toml
[dependencies]
type-rules = { version = "0.2.1", features = ["derive", "regex"] }

Basic checking

You can declare a struct and impose some constraints on each field and check the validity like this:

use chrono::prelude::*;
use type_rules::prelude::*;

#[derive(Validator)]
struct NewUser {
    #[rule(MaxLength(100), RegEx(r"^\S+@\S+\.\S+"))]
    email: String,
    #[rule(MinMaxLength(8, 50))]
    password: String,
    #[rule(Opt(MaxRange(Utc::now())))]
    birth_date: Option<DateTime<Utc>>
}

let new_user = NewUser {
    email: "examples@examples.com".to_string(),
    password: "OPw$5%hJ".to_string(),
    birth_date: None,
};
assert!(new_user.check_validity().is_ok());
let new_user = NewUser {
    email: "examples@examples.com".to_string(),
    password: "O".to_string(),
    birth_date: None,
};
assert!(new_user.check_validity().is_err()); //Value is too short

Also works with enums :

use type_rules::prelude::*;

#[derive(Validator)]
enum MyEnum {
    Option1(#[rule(MaxLength(200))] String),
    Option2 {
        #[rule(MinMaxRange(1, 10))]
        integer: u32
    },
    Option3,
}

Advanced checking

To check recursively, you can use the Validate rule

use type_rules::prelude::*;

#[derive(Validator)]
struct EmailWrapper(#[rule(MaxLength(100), RegEx(r"^\S+@\S+\.\S+"))] String);

#[derive(Validator)]
struct User {
    #[rule(Validate())]
    email: EmailWrapper,
    #[rule(MinMaxLength(8, 50))]
    password: String,
}

You can use expressions directly in rule derive attribute.

For example, you can use const or function directly in the rule parameters:

use type_rules::prelude::*;
use chrono::prelude::*;

#[derive(Validator)]
struct BirthDate(#[rule(MaxRange(Utc::now()))] DateTime<Utc>);
use type_rules::prelude::*;

#[derive(Validator)]
struct Range {
    #[rule(MaxRange(self.max))]
    min: u32,
    #[rule(MinRange(self.min))]
    max: u32,
};

Or use expressions to express a rule directly. Here is an example of using a rule with more complex values:

use std::env;
use type_rules::prelude::*;

fn generate_max_payload_rule() -> MaxLength {
    MaxLength(match env::var("MAX_PAYLOAD") {
        Ok(val) => val.parse().unwrap_or_else(|_| 10000),
        Err(_) => 10000,
    })
}

#[derive(Validator)]
struct Payload(#[rule(generate_max_payload_rule())] String);

In this case the generate_max_payload_rule function is executed at each check

Make your own rule

If you need a specific rule, just make a tuple struct (or struct if you make the declaration outside the struct definition) that implements the Rule feature :

use type_rules::prelude::*;

struct IsEven();

impl Rule<i32> for IsEven {
    fn check(&self, value: &i32) -> Result<(), String> {
        if value % 2 == 0 {
            Ok(())
        } else {
            Err("Value is not even".into())
        }
    }
}

#[derive(Validator)]
struct MyInteger(#[rule(IsEven())] i32);

Rules list

Here a list of the rules you can find in this crate.

Each rule has its own documentation with examples.

Check the length of any type that implements AsRef<str> such as String or &str:

  • MinLength: Minimum length ex: MinLength(5)
  • MaxLength: Maximum length ex: MaxLength(20)
  • MinMaxLength: Minimum and maximum length ex: MinMaxLength(5, 20)

Check the range for anything that implements PartialOrd<Self> like all numeric/floating types or dates with chrono:

  • MinRange: Minimum range ex: MinRange(5)
  • MaxRange: Maximum range ex: MaxRange(20)
  • MinMaxRange: Minimum and maximum range ex: MinMaxRange(5, 20)

Check the size of a Vec<T> :

  • MinSize: Minimum size ex: MinSize(5)
  • MaxSize: Maximum size ex: MaxSize(20)
  • MinMaxSize: Minimum and maximum size ex: MinMaxSize(5, 20)

others :

  • Opt: Apply another rule to inner value of an Option ex: Opt(MinMaxRange(1, 4))
  • And: Rule to ensure that 2 other rules are Ok ex: And(MaxLength(1000), RegEx(r"^\S+@\S+\.\S+"))
  • Or: Rule to apply an Or condition on two other rules. ex: Or(MaxRange(-1), MinRange(1))
  • Eval: Rule to constrain any type to a predicate ex: Eval(predicate, "Error message")
  • Validate: Recursive checking ex: Validate()
  • In: Rule to constrain a type to be in a collection ex: In(["apple", "banana", "orange", "pear"], "Value need to be a fruit")
  • All: Rule to constrain a collection to valid the specified rule ex: All(MinLength(1), "You can't use empty string")
  • RegEx: check if a type that implement AsRef<str> (String, &str, ...) matches the regex. You need the regex feature to use it. ex: RegEx(r"^\S+@\S+\.\S+")

Dependencies

~100KB