use regex::Regex;
use std::any::Any;
use std::fmt::Debug;
use std::ops::Deref;
use std::path::Path;
pub trait Validator: Debug {
fn validate(&self, data: &str) -> Option<String>;
fn as_any(&self) -> &dyn Any;
}
#[derive(Clone, Debug)]
pub struct Required;
impl Validator for Required {
fn validate(&self, data: &str) -> Option<String> {
if data.len() == 0 {
Some("Field is required".to_string())
} else {
None
}
}
fn as_any(&self) -> &dyn Any {
self
}
}
#[derive(Clone, Debug)]
pub struct PathFree;
impl Validator for PathFree {
fn validate(&self, data: &str) -> Option<String> {
let path = Path::new(data);
if path.exists() {
Some("Path is already used".to_string())
} else {
None
}
}
fn as_any(&self) -> &dyn Any {
self
}
}
#[derive(Clone, Debug)]
pub struct DirExists;
impl Validator for DirExists {
fn validate(&self, data: &str) -> Option<String> {
let path = Path::new(data);
if path.exists() {
if path.metadata().unwrap().is_dir() {
None
} else {
Some("It's not a dir".to_string())
}
} else {
Some("Dir doesn't exist".to_string())
}
}
fn as_any(&self) -> &dyn Any {
self
}
}
#[derive(Clone, Debug)]
pub struct FileExists;
impl Validator for FileExists {
fn validate(&self, data: &str) -> Option<String> {
let path = Path::new(data);
if path.exists() {
if path.metadata().unwrap().is_file() {
None
} else {
Some("It's not a file".to_string())
}
} else {
Some("File doesn't exist".to_string())
}
}
fn as_any(&self) -> &dyn Any {
self
}
}
#[derive(Clone, Debug)]
pub struct OneOf<T>(pub T);
impl<T: Debug + 'static> Validator for OneOf<Vec<T>>
where
T: Deref<Target = str>,
{
fn validate(&self, data: &str) -> Option<String> {
if let None = self.0.iter().position(|x| &**x == data) {
Some("Value must be one of options".to_string())
} else {
None
}
}
fn as_any(&self) -> &dyn Any {
self
}
}
impl Validator for Regex {
fn validate(&self, data: &str) -> Option<String> {
if self.is_match(data) {
None
} else {
Some(format!(
"Value {:?} does not match: \"{:?}\" regular exp.",
data, self
))
}
}
fn as_any(&self) -> &dyn Any {
self
}
}