pub type Validation = Result<(), String>;
pub trait Validator {
fn validate(&self, input: &str) -> Validation;
}
impl<F> Validator for F
where
F: Fn(&str) -> Validation,
{
fn validate(&self, input: &str) -> Validation {
self(input)
}
}
#[must_use]
pub fn non_empty(message: impl Into<String>) -> impl Validator {
let message = message.into();
move |input: &str| {
if input.trim().is_empty() {
Err(message.clone())
} else {
Ok(())
}
}
}
#[cfg(test)]
mod tests {
use super::{Validator, non_empty};
#[test]
fn closure_is_a_validator() {
let v = |input: &str| {
if input.len() >= 2 {
Ok(())
} else {
Err("too short".to_string())
}
};
assert!(v.validate("ok").is_ok());
assert_eq!(v.validate("x"), Err("too short".to_string()));
}
#[test]
fn non_empty_rejects_blank() {
let v = non_empty("required");
assert!(v.validate("value").is_ok());
assert_eq!(v.validate(" "), Err("required".to_string()));
}
}