use crate::{ValidationError, Validator};
pub struct Ascii;
impl<S: AsRef<str> + ?Sized> Validator<S> for Ascii {
type Error = ValidationError;
fn validate(value: &S) -> Result<(), Self::Error> {
if value.as_ref().is_ascii() {
Ok(())
} else {
Err(ValidationError::new(
"ascii",
"value must contain only ASCII characters",
))
}
}
}
pub struct Alphanumeric;
impl<S: AsRef<str> + ?Sized> Validator<S> for Alphanumeric {
type Error = ValidationError;
fn validate(value: &S) -> Result<(), Self::Error> {
if value.as_ref().chars().all(char::is_alphanumeric) {
Ok(())
} else {
Err(ValidationError::new(
"alphanumeric",
"value must contain only alphanumeric characters",
))
}
}
}
pub struct Trimmed;
impl<S: AsRef<str> + ?Sized> Validator<S> for Trimmed {
type Error = ValidationError;
fn validate(value: &S) -> Result<(), Self::Error> {
let value = value.as_ref();
if value == value.trim() {
Ok(())
} else {
Err(ValidationError::new(
"trimmed",
"value must not have leading or trailing whitespace",
))
}
}
}
#[cfg(test)]
mod tests {
#![allow(clippy::unwrap_used, clippy::expect_used)]
use super::*;
#[test]
fn ascii_rule() {
assert!(Ascii::validate("abc123!").is_ok());
assert!(Ascii::validate("").is_ok());
assert_eq!(Ascii::validate("é").unwrap_err().code(), "ascii");
}
#[test]
fn alphanumeric_rule() {
assert!(Alphanumeric::validate("Abc123").is_ok());
assert!(Alphanumeric::validate("").is_ok());
assert!(Alphanumeric::validate("a-b").is_err());
}
#[test]
fn trimmed_rule() {
assert!(Trimmed::validate("ok").is_ok());
assert!(Trimmed::validate(" leading").is_err());
assert!(Trimmed::validate("trailing ").is_err());
assert!(Trimmed::validate("inner space ok".trim()).is_ok());
}
}