A tool to easily constrain a struct and recover errors.
```toml
[dependencies] type-rules = { version = "0.2.2", features = ["derive", "regex"] } ```
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::;
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::*;
enum MyEnum { Option1(#[rule(MaxLength(200))] String), Option2 { #[rule(MinMaxRange(1, 10))] integer: u32 }, Option3, } ```
To check recursively, you can use the Validate
rule
```rust use type_rules::prelude::*;
struct EmailWrapper(#[rule(MaxLength(100), RegEx(r"^\S+@\S+.\S+"))] String);
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::;
struct BirthDate(#[rule(MaxRange(Utc::now()))] DateTime
```rust use type_rules::prelude::*;
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, }) }
struct Payload(#[rule(generatemaxpayload_rule())] String); ```
In this case the generate_max_payload_rule
function is executed at each check
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
struct MyInteger(#[rule(IsEven())] i32); ```
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+")