Tell me why my self-made crate is terrible and make me cry
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
- GitHub: https://github.com/tomoikey/refined_type
- Docs: https://docs.tomoikey.com/quickstart
- crates.io: https://crates.io/crates/refined_type
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(())
}