From af44f3e4d2d5332ab26deb7cd09ae90c4138fdb2 Mon Sep 17 00:00:00 2001 From: Nettika Date: Thu, 21 Jul 2022 11:21:36 -0700 Subject: [PATCH] Rename error type alias --- readme.md | 47 ++++++++++++++++++++++++++++++----------------- src/lib.rs | 42 +++++++++++++++++++++--------------------- src/tests.rs | 4 ++-- 3 files changed, 53 insertions(+), 40 deletions(-) diff --git a/readme.md b/readme.md index a2453b1..3cbbee1 100644 --- a/readme.md +++ b/readme.md @@ -11,47 +11,60 @@ Add a dependency entry in `Cargo.toml`. vet = "0.1" ``` -```rust -use vet::Vet; +Implement the `Vet` trait on your type. +```rust +use vet::{Valid, Vet}; + +// A valid username consists of between 3 and 32 alphanumeric characters #[derive(Debug)] struct Username(String); #[derive(Debug, PartialEq)] -enum UsernameVetError { - TooShort, - TooLong, - InvalidChar, +enum InvalidUsername { + TooShort, // Under 3 characters + TooLong, // Over 3 characters + InvalidChar, // Contains non-alphanumeric character } impl Vet for Username { - type VetError = UsernameVetError; - fn is_valid(&self) -> Result<(), Self::VetError> { + type Error = InvalidUsername; + + // Arbitrary logic to validate the Username type + fn is_valid(&self) -> Result<(), Self::Error> { if self.0.len() < 3 { - return Err(Self::VetError::TooShort); + return Err(Self::Error::TooShort); } if self.0.len() > 32 { - return Err(Self::VetError::TooLong); + return Err(Self::Error::TooLong); } if self.0.chars().any(|c| !c.is_alphanumeric()) { - return Err(Self::VetError::InvalidChar); + return Err(Self::Error::InvalidChar); } Ok(()) } } +``` +Vetted types provide safety guarantees for the types contents. + +```rust fn main() { - let username = Username(String::from("hi")); - assert_eq!(username.is_valid(), Err(UsernameVetError::TooShort)); - - let username = Username(String::from("benjamin")); + let args: Vec = env::args().collect(); + let username = Username(args[1].clone()); + + // If successfully vetted, the username will be wrapped in a `Valid` struct match username.vet() { Ok(username) => create_account(username), - Err(error) => println!("Could not create account: {:?}", error), + Err(InvalidUsername::TooShort) => eprintln!("Username too short! (3 min)"), + Err(InvalidUsername::TooLong) => eprintln!("Username too long! (32 max)"), + Err(InvalidUsername::InvalidChar) => eprintln!("Username contains invalid characters!"), } } -fn create_account(username: Vetted) { +// Any `Valid` passed is guaranteed +// to have met the arbitrary validation checks. +fn create_account(username: Valid) { println!("Account {:?} created", username); } ``` diff --git a/src/lib.rs b/src/lib.rs index 84a8260..4781b98 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,8 +1,8 @@ //! Provides an interface for validation of arbitrary types. //! -//! The `Vet` trait requires an implementation of a `VetError` type alias and -//! an `is_valid` method, which executes arbitrary validation logic and returns -//! a result indicating whether the instance is valid. +//! The `Vet` trait requires an `Error` type alias and an implementation of an +//! `is_valid` method, which executes arbitrary validation logic and returns a +//! result indicating whether the instance is valid. //! //! The `Vet` trait also provides a default implementation of a `vet` method //! which, dependant on the result of `is_valid`, either wraps the instance with @@ -11,8 +11,8 @@ //! The `Valid` wrapper guarantees that the inner value was successfully //! validated and remains immutable as long as it is wrapped. //! -//! Implementations for the common standard library types `Vec` and -//! `Option` are provided. +//! Implementations for generic arrays, and for the common standard library +//! types `Vec` and `Option` are provided. //! //! # Examples //! @@ -23,24 +23,24 @@ //! struct Username(String); //! //! #[derive(Debug, PartialEq)] -//! enum UsernameVetError { +//! enum InvalidUsername { //! TooShort, //! TooLong, //! InvalidChar, //! } //! //! impl Vet for Username { -//! type VetError = UsernameVetError; +//! type Error = InvalidUsername; //! -//! fn is_valid(&self) -> Result<(), Self::VetError> { +//! fn is_valid(&self) -> Result<(), Self::Error> { //! if self.0.len() < 3 { -//! return Err(Self::VetError::TooShort); +//! return Err(Self::Error::TooShort); //! } //! if self.0.len() > 32 { -//! return Err(Self::VetError::TooLong); +//! return Err(Self::Error::TooLong); //! } //! if self.0.chars().any(|c| !c.is_alphanumeric()) { -//! return Err(Self::VetError::InvalidChar); +//! return Err(Self::Error::InvalidChar); //! } //! Ok(()) //! } @@ -48,7 +48,7 @@ //! //! fn main() { //! let username = Username(String::from("hi")); -//! assert_eq!(username.is_valid(), Err(UsernameVetError::TooShort)); +//! assert_eq!(username.is_valid(), Err(InvalidUsername::TooShort)); //! //! let username = Username(String::from("benjamin")); //! match username.vet() { @@ -85,13 +85,13 @@ impl core::ops::Deref for Valid { /// An interface for arbitrary type validation pub trait Vet { /// The error returned by failed validation - type VetError; + type Error; /// Executes arbitrary validation logic on this instance. - fn is_valid(&self) -> Result<(), Self::VetError>; + fn is_valid(&self) -> Result<(), Self::Error>; /// Validates this instance and results in a wrapped instance if successful. - fn vet(self) -> Result, Self::VetError> + fn vet(self) -> Result, Self::Error> where Self: Sized, { @@ -103,17 +103,17 @@ pub trait Vet { } impl Vet for [T; N] { - type VetError = T::VetError; + type Error = T::Error; - fn is_valid(&self) -> Result<(), Self::VetError> { + fn is_valid(&self) -> Result<(), Self::Error> { self.iter().try_for_each(|i| i.is_valid()) } } impl Vet for Option { - type VetError = T::VetError; + type Error = T::Error; - fn is_valid(&self) -> Result<(), Self::VetError> { + fn is_valid(&self) -> Result<(), Self::Error> { match self { Some(o) => o.is_valid(), None => Ok(()), @@ -132,9 +132,9 @@ impl Valid> { #[cfg(feature = "alloc")] impl Vet for alloc::vec::Vec { - type VetError = T::VetError; + type Error = T::Error; - fn is_valid(&self) -> Result<(), Self::VetError> { + fn is_valid(&self) -> Result<(), Self::Error> { self.iter().try_for_each(|t| t.is_valid()) } } diff --git a/src/tests.rs b/src/tests.rs index 2fa162c..31cb26a 100644 --- a/src/tests.rs +++ b/src/tests.rs @@ -7,8 +7,8 @@ struct EvenUsize(usize); struct OddUsize; impl Vet for EvenUsize { - type VetError = OddUsize; - fn is_valid(&self) -> Result<(), Self::VetError> { + type Error = OddUsize; + fn is_valid(&self) -> Result<(), Self::Error> { if self.0 % 2 == 0 { Ok(()) } else {