type-rules

Crates.io version docs.rs docs License

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

```toml

Cargo.toml

[dependencies] type-rules = { version = "0.2.3", features = ["derive", "regex", "serde"] } ```

Basic checking

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

```rust 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> }

let newuser = NewUser { email: "examples@examples.com".tostring(), password: "OPw$5%hJ".tostring(), birthdate: None, }; assert!(newuser.checkvalidity().isok()); let newuser = NewUser { email: "examples@examples.com".tostring(), password: "O".tostring(), birthdate: None, }; assert!(newuser.checkvalidity().iserr()); //Value is too short ```

Also works with enums :

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

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

```rust use type_rules::prelude::; use chrono::prelude::;

[derive(Validator)]

struct BirthDate(#[rule(MaxRange(Utc::now()))] DateTime); ```

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

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

fn generatemaxpayloadrule() -> MaxLength { MaxLength(match env::var("MAXPAYLOAD") { Ok(val) => val.parse().unwraporelse(|| 10000), Err() => 10000, }) }

[derive(Validator)]

struct Payload(#[rule(generatemaxpayload_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 :

```rust use type_rules::prelude::*;

struct IsEven();

impl Rule 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); ```

Valid wrapper

Valid is a wrapper for any type that implements Validator it permit to ensure at compile time that the inner type as been verified.

With the serde feature, Valid can be serialized and deserialized with validity check. ```rust use type_rules::prelude::*;

[derive(Validator)]

struct NewUser { #[rule(MinMaxLength(3, 50))] username: String, #[rule(MinMaxLength(8, 100))] password: String, }

fn do_something(user: Valid) { // No need to check if user is valid }

let newuser = NewUser { username: "example".tostring(), password: "OPw$5%hJJ".tostring(), }; dosomething(Valid::new(new_user).unwrap()); ```

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:

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

Check the size of a Vec<T> :

others :