Tell me why my self-made crate is terrible and make me cry

150 points Novel_Principle_3831

Description

I wanted to create a crate that would allow for type-based validation and make my programs safer at runtime, so I made a crate called refined_type. It supports things like numeric types constrained to specific ranges, arrays that meet certain conditions, non-empty strings, and more.
I’ve also included features to easily compose validation rules together.

URLs

The appeal of refined_type

By combining it with serde, you can validate JSON or YAML based on types.

Example

MinMax type

MinMax is a type that signifies the target exists between a certain number and another number.

type Age = MinMaxU8<18, 80>;
fn min_max_example() -> Result<(), Error<u8>> {
    let age = Age::new(18)?;
    assert_eq!(age.into_value(), 18);

    let age = Age::new(80)?;
    assert_eq!(age.into_value(), 80);

    let age = Age::new(17);
    assert!(age.is_err());

    let age = Age::new(81);
    assert!(age.is_err());
    Ok(())
}

ForAll type

ForAll is a rule that applies a specific rule to all elements in the Iterator.

fn for_all_example() -> anyhow::Result<()> {
    let vec = vec!["Hello".to_string(), "World".to_string()];
    let for_all_ok = ForAllVec::<NonEmptyStringRule>::new(vec.clone())?;
    assert_eq!(vec, for_all_ok.into_value());

    let vec = vec!["Hello".to_string(), "".to_string()];
    let for_all_err = ForAllVec::<NonEmptyStringRule>::new(vec.clone());
    assert!(for_all_err.is_err());
    Ok(())
}

Define complex type

We can create types with complex conditions using And, Or, and Not.

type Target = Refined<
    Or![
        And![
            MinMaxRuleU8<0, 50>,
            EvenRuleU8,
            Not<Or![EqualRuleU8<10>, EqualRuleU8<20>]>
        ],
        And![
            MinMaxRuleU8<60, 100>,
            OddRuleU8,
            Not<Or![EqualRuleU8<75>, EqualRuleU8<85>]>
        ]
    ]
>;
fn complex_rule_example() -> Result<(), Error<u8>> {
    let target = Target::new(0)?;
    assert_eq!(target.into_value(), 0);

    let target = Target::new(2)?;
    assert_eq!(target.into_value(), 2);

    let target = Target::new(10);
    assert!(target.is_err());

    let target = Target::new(20);
    assert!(target.is_err());

    let target = Target::new(50)?;
    assert_eq!(target.into_value(), 50);

    let target = Target::new(60);
    assert!(target.is_err());

    let target = Target::new(61)?;
    assert_eq!(target.into_value(), 61);

    let target = Target::new(75);
    assert!(target.is_err());

    let target = Target::new(85);
    assert!(target.is_err());

    let target = Target::new(100);
    assert!(target.is_err());

    let target = Target::new(101);
    assert!(target.is_err());

    Ok(())
}