2022-07-04 02:26:48 -07:00
|
|
|
# Vet
|
|
|
|
|
|
2022-07-21 11:45:33 -07:00
|
|
|
Arbitrary type validation.
|
2022-07-04 02:26:48 -07:00
|
|
|
|
|
|
|
|
## Usage
|
|
|
|
|
|
|
|
|
|
Add a dependency entry in `Cargo.toml`.
|
|
|
|
|
|
|
|
|
|
```toml
|
|
|
|
|
[dependencies]
|
|
|
|
|
vet = "0.1"
|
|
|
|
|
```
|
|
|
|
|
|
2022-07-21 11:21:36 -07:00
|
|
|
Implement the `Vet` trait on your type.
|
|
|
|
|
|
2022-07-04 02:26:48 -07:00
|
|
|
```rust
|
2022-07-21 11:21:36 -07:00
|
|
|
use vet::{Valid, Vet};
|
2022-07-04 02:26:48 -07:00
|
|
|
|
2022-07-21 11:21:36 -07:00
|
|
|
// A valid username consists of between 3 and 32 alphanumeric characters
|
2022-07-04 02:26:48 -07:00
|
|
|
#[derive(Debug)]
|
|
|
|
|
struct Username(String);
|
|
|
|
|
|
|
|
|
|
#[derive(Debug, PartialEq)]
|
2022-07-21 11:21:36 -07:00
|
|
|
enum InvalidUsername {
|
|
|
|
|
TooShort, // Under 3 characters
|
|
|
|
|
TooLong, // Over 3 characters
|
|
|
|
|
InvalidChar, // Contains non-alphanumeric character
|
2022-07-04 02:26:48 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl Vet for Username {
|
2022-07-21 11:21:36 -07:00
|
|
|
type Error = InvalidUsername;
|
|
|
|
|
|
|
|
|
|
// Arbitrary logic to validate the Username type
|
|
|
|
|
fn is_valid(&self) -> Result<(), Self::Error> {
|
2022-07-04 02:26:48 -07:00
|
|
|
if self.0.len() < 3 {
|
2022-07-21 11:21:36 -07:00
|
|
|
return Err(Self::Error::TooShort);
|
2022-07-04 02:26:48 -07:00
|
|
|
}
|
|
|
|
|
if self.0.len() > 32 {
|
2022-07-21 11:21:36 -07:00
|
|
|
return Err(Self::Error::TooLong);
|
2022-07-04 02:26:48 -07:00
|
|
|
}
|
|
|
|
|
if self.0.chars().any(|c| !c.is_alphanumeric()) {
|
2022-07-21 11:21:36 -07:00
|
|
|
return Err(Self::Error::InvalidChar);
|
2022-07-04 02:26:48 -07:00
|
|
|
}
|
|
|
|
|
Ok(())
|
|
|
|
|
}
|
|
|
|
|
}
|
2022-07-21 11:21:36 -07:00
|
|
|
```
|
2022-07-04 02:26:48 -07:00
|
|
|
|
2022-07-21 11:45:33 -07:00
|
|
|
`Valid`-wrapped types provide safety guarantees about their contents.
|
2022-07-21 11:21:36 -07:00
|
|
|
|
|
|
|
|
```rust
|
2022-07-04 02:26:48 -07:00
|
|
|
fn main() {
|
2022-07-21 11:21:36 -07:00
|
|
|
let args: Vec<String> = env::args().collect();
|
2022-07-21 11:45:33 -07:00
|
|
|
|
|
|
|
|
let username: Username = Username(args[1].clone());
|
|
|
|
|
let username: Result<Valid<Username>, InvalidUsername> = username.vet();
|
|
|
|
|
|
|
|
|
|
match username {
|
|
|
|
|
Ok(n) => create_account(n),
|
|
|
|
|
Err(e) => eprintln!("Invalid username: {:?}", e),
|
2022-07-04 02:26:48 -07:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-07-21 11:45:33 -07:00
|
|
|
// Any `Valid<Username>` passed is guaranteed to be 3-32 alphanumeric characters.
|
2022-07-21 11:21:36 -07:00
|
|
|
fn create_account(username: Valid<Username>) {
|
2022-07-21 11:33:14 -07:00
|
|
|
let username = username.into_inner(); // Unwrap
|
|
|
|
|
|
2022-07-04 02:26:48 -07:00
|
|
|
println!("Account {:?} created", username);
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
## License
|
|
|
|
|
|
|
|
|
|
Licensed under either of
|
|
|
|
|
|
|
|
|
|
- Apache License, Version 2.0 ([license-apache.txt](license-apache.txt) or
|
|
|
|
|
http://www.apache.org/licenses/LICENSE-2.0)
|
|
|
|
|
- MIT license ([license-mit.txt](license-mit.txt) or
|
|
|
|
|
http://opensource.org/licenses/MIT)
|
|
|
|
|
|
|
|
|
|
at your option.
|
|
|
|
|
|
|
|
|
|
## Contribution
|
|
|
|
|
|
|
|
|
|
Unless you explicitly state otherwise, any contribution intentionally submitted
|
|
|
|
|
for inclusion in the work by you, as defined in the Apache-2.0 license, shall be
|
|
|
|
|
dual licensed as above, without any additional terms or conditions.
|