This crate provides helper macros for defining newtypes with validation & preprocessors.
- Validators
- Preprocessors
- Postprocessors
- Visibility specifiers (e.g.
pub,pub(crate))
- It is possible to circumvent the validation by defining
impl From<String> for Username. This is because an impl can constructUsernamedirectly without callingUsername::new. There is no workaround for this, you just need to be careful. - It is possible to circumvent the validation by adding
#[derive(serde::Deserialize)]. This is becauseimpl serde::Deserializecan construct the target type directly without calling thenewfunction. There's a workaround: add#[serde(try_from = "Foo")]where Foo is the underlying type of this newtype.
- In macro invocations, the generics and trait bounds must be wrapped in square brackets (
[]) instead of angle brackets (<>). This is a limitation of macro_rules. It applies only to the definitions of generics and trait bounds, not to their usage. See examples:newtype!- Good:
newtype!(pub struct ProjectDirectoryRef['a](&'a Path)); - Bad:
newtype!(pub struct ProjectDirectoryRef<'a>(&'a Path));
- Good:
validate_as_check!- Good:
validate_as_check!(impl[V] Validate<V> for Even where [V: IsEven]); - Bad:
validate_as_check!(impl<V> Validate<V> for Even where V: IsEven);
- Good:
- Constraint types must be empty structs (without fields)
- Constraint types must have the following derive attribute:
#[derive(Default, Eq, PartialEq, Hash, Clone, Copy, Debug)]Defaultis necessary to display the genericValidationError(itsDisplayimpl requiresChecker: Display)- Other traits are necessary to enable the same derives for newtypes
- Error types must derive
Error(obviously) - Error types must take ownership of the value that triggered the error, so that the caller would have access to the value in an error handler
- Error type fields must be
pub
Min<Minimum, Inclusivity>is used instead ofMin<Minimum, const INCLUSIVITY: bool>because it provides more informative error messages.Min, Max, EqualusePartialOrd, PartialEqinstead ofOrd, Eqbecause more types implement the Partial traits. Also, if the developer specifiespub struct MyFloat(f32 | Min<0.5, Exclusive>), they don't wantNANto pass this validation. This is exactly whatMindoes by delegating toPartialCmp, which returnsfalseforNAN.
- refinement
- You can't implement foreign traits on a
Refinementtype (because theRefinementtype comes from therefinementcrate, which is also foreign to your code) - You can't sanitize the value in the constructor
- You can't implement foreign traits on a
- nutype
- You can't return a specific error from the validation predicate
- You have to wait longer due to increased compilation speed
- You can't use autocompletion while writing out the macro call
- synonym
- You can automatically get certain derives based on the underlying type
- You can't get automatic derives for unknown types (for example, if
Address: Copy, thenpub struct AddressNewtype(Address)you won't getimpl Copy for AddressNewtype, you need to explicitly add#[derive(Copy)])
- You can't get automatic derives for unknown types (for example, if
- You can automatically get certain derives based on the underlying type
- aliri_braid
- It only supports
Stringas the base type
- It only supports
- prae
- Very similar design
- Wrapper trait imposes too much structure (TryFrom already provides the Error type)
- tightness
- Last commit on May 30, 2021
- prae improves on tightness
- semval
- validators
cargo add subtypeLike the project? ⭐ Star this repo on GitHub!
Apache-2.0 or MIT.
Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in this crate by you, shall be licensed as above, without any additional terms or conditions.