peer-pressure
Peer pressure is a stupidly simple parse-don't-validation micro-framework for Rust types that seek to conform to society's expectations. You know, rules like these:
- A file name must not contain a
/slash, - The number of items in cart must be non-negative,
- Password must contain exactly 3 emojis, a prime number, your mother's maiden name in reverse, and cannot include any letter found in the word "password",
..yada yada yada - peer-pressure gives you a small, cohesive set of traits to define your validation logic in a principled way.
Principles
This crate is highly opinionated and deliberately constraining in accordance with the following beliefs:
- Validation should happen at system boundary and no constructed value should still need to be validated. In a perfect world, this crate would not exist.
- Validation should be functionally pure
- Validation should consume the validated value
- Validity should be expressed at the type level
- Validation context should be declared explicitly
- Types should have a single notion of validity
Quick Start
Add peer-pressure to your dependencies and implement Validate for any
raw type that needs to be turned into a validated shape:
use Validate;
;
;
// `validate()` is a syntax sugar for types with context-free validation:
let valid_email = RawEmail.validate.unwrap;
For types whose validation require context, eg. a config or a lookup table, define a Context type other than ():
use Validate;
use HashSet;
;
;
type Alphabet = ;
let alphabet = from;
let valid_text = Text.validate_in_context.unwrap;
let validation_error = Text.validate_in_context.unwrap_err;
Valid types
Types whose values are considered already valid can implement the Valid marker trait.
use Valid;
/// I make no sense at all as a type!
;
#
#
This gives two benefits:
- it auto-derives
Validatefor the type, preventing anyone from implementing a spurious one, - it can be put as a bound in generic code that assumes valid input.
The Validate trait does not impose that the Output type implements Valid, but it's a good practice.
Tuples
All traits are implemented for tuples up to 26 elements, so a tuple of inputs validates into a tuple of outputs:
use ValidateFrom;
;
;
let = validate_from.unwrap;
One constraint for this is that all elements must agree on one Context type and one Error type.
Async
In a perfect world, all validation would be synchronous and pure. But unlike types in computer systems,
the world doesn't cave to any pressure, and sometimes a "validation" step needs to be async. A typical
case is the need for a database lookup or a call to another service. To account for this, peer-pressure
provides Resolve and ResolveFrom traits analogous to Validate and ValidateFrom.
Features
derive: provides#[derive(Valid)]for theValidtrait.async: enables the asyncResolvetrait family.
License
Apache License, Version 2.0 or MIT license.
Any contribution submitted to this crate by you shall be dual licensed as above, without any additional terms or conditions. You've been warned.