1use std::fmt::Display;
2use std::marker::PhantomData;
3use std::str::FromStr;
4
5#[cfg(feature = "typing")]
6use crate::typing::Type;
7
8pub trait Validator {
10 fn validate(&self, value: &str) -> Result<(), String>;
13
14 #[cfg(feature = "typing")]
22 fn valid_type(&self) -> Option<Type> {
23 None
24 }
25}
26
27#[derive(Default)]
29pub struct TypeValidator<T>(PhantomData<T>);
30impl<T> TypeValidator<T> {
31 #[inline]
32 pub fn new() -> Self {
33 TypeValidator(PhantomData)
34 }
35}
36impl<T: 'static> Validator for TypeValidator<T>
37 where
38 T: FromStr,
39{
40 fn validate(&self, value: &str) -> Result<(), String> {
41 match T::from_str(value) {
42 Ok(_) => Ok(()),
43 Err(_) => Err(format!("`{}`", value)),
44 }
45 }
46
47 #[cfg(feature = "typing")]
48 fn valid_type(&self) -> Option<Type> {
49 Some(Type::of::<T>())
50 }
51}
52
53pub struct RangeValidator<T>(T, T);
56impl<T> RangeValidator<T>
57 where
58 T: FromStr + PartialOrd + Display,
59{
60 #[inline]
61 pub fn new(min: T, max: T) -> Self {
62 assert!(min < max, "min cannot be greater than max");
63 RangeValidator(min, max)
64 }
65}
66impl<T: 'static> Validator for RangeValidator<T>
67 where
68 T: FromStr + PartialOrd + Display,
69{
70 fn validate(&self, value: &str) -> Result<(), String> {
71 match T::from_str(value) {
72 Err(_) => Err(format!("`{}`", value)),
73 Ok(n) => {
74 if n >= self.0 && n <= self.1 {
75 Ok(())
76 } else {
77 Err(format!("{} is out of range: {}..{}", n, self.0, self.1))
78 }
79 }
80 }
81 }
82
83 #[cfg(feature = "typing")]
84 fn valid_type(&self) -> Option<Type> {
85 Some(Type::of::<T>())
86 }
87}
88
89impl<F> Validator for F
91 where
92 F: Fn(&str) -> std::result::Result<(), String>,
93{
94 fn validate(&self, value: &str) -> Result<(), String> {
95 match (self)(value) {
96 Ok(_) => Ok(()),
97 Err(msg) => Err(msg),
98 }
99 }
100}
101
102#[inline]
104pub fn validate_type<T: 'static + FromStr>() -> TypeValidator<T> {
105 TypeValidator::new()
106}
107
108#[inline]
110pub fn validate_range<T: 'static>(min: T, max: T) -> RangeValidator<T>
111 where
112 T: FromStr + PartialOrd + Display,
113{
114 RangeValidator::new(min, max)
115}