1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
use prelude::v1::*;
#[derive(Debug, Clone, PartialEq)]
pub enum PropertyValidationError<T> {
InvalidInput,
ValueTooSmall { min: T, val: T },
ValueTooBig { max: T, val: T }
}
pub trait ValueInput<T> {
fn input(&self, s: &str) -> Result<T, PropertyValidationError<T>>;
}
pub trait ValueInputValidate<T> {
fn validate(&self, val: &T) -> Result<(), PropertyValidationError<T>>;
}
pub trait ValueOutput<T> {
fn output(&self, v: &T) -> Result<String, PropertyValidationError<T>>;
}
pub struct ValueInputFromStr;
impl<T: FromStr> ValueInput<T> for ValueInputFromStr {
fn input(&self, s: &str) -> Result<T, PropertyValidationError<T>> {
match T::from_str(s) {
Ok(v) => Ok(v),
Err(_) => Err(PropertyValidationError::InvalidInput)
}
}
}
pub struct ValueOutputToString;
impl<T: ToString> ValueOutput<T> for ValueOutputToString {
fn output(&self, v: &T) -> Result<String, PropertyValidationError<T>> {
Ok(v.to_string())
}
}
pub struct ValueBool;
impl ValueInput<bool> for ValueBool {
fn input(&self, s: &str) -> Result<bool, PropertyValidationError<bool>> {
match s.to_lowercase().trim() {
"0" | "false" | "off" | "no" => Ok(false),
"1" | "true" | "on" | "yes" => Ok(true),
_ => Err(PropertyValidationError::InvalidInput)
}
}
}
impl ValueOutput<bool> for ValueBool {
fn output(&self, v: &bool) -> Result<String, PropertyValidationError<bool>> {
Ok(v.to_string())
}
}
pub struct ValueInputWithValidation<T, I, V> where I: ValueInput<T>, V: ValueInputValidate<T> {
t: PhantomData<T>,
input: I,
validate: V
}
impl<T, I, V> ValueInput<T> for ValueInputWithValidation<T, I, V> where I: ValueInput<T>, V: ValueInputValidate<T> {
fn input(&self, s: &str) -> Result<T, PropertyValidationError<T>> {
let val = try!(self.input.input(s));
try!(self.validate.validate(&val));
Ok(val)
}
}
pub struct ValueMin<T> { min: T }
impl<T: PartialOrd + Copy> ValueInputValidate<T> for ValueMin<T> {
fn validate(&self, val: &T) -> Result<(), PropertyValidationError<T>> {
if *val < self.min {
Err(PropertyValidationError::ValueTooSmall { min: self.min, val: *val })
} else {
Ok(())
}
}
}
pub struct ValueMax<T> { max: T }
impl<T: PartialOrd + Copy> ValueInputValidate<T> for ValueMax<T> {
fn validate(&self, val: &T) -> Result<(), PropertyValidationError<T>> {
if *val > self.max {
Err(PropertyValidationError::ValueTooBig { max: self.max, val: *val })
} else {
Ok(())
}
}
}
pub struct ValueCombineValidators<T, A, B> where A: ValueInputValidate<T>, B: ValueInputValidate<T> {
t: PhantomData<T>,
a: A,
b: B
}
impl<T, A, B> ValueInputValidate<T> for ValueCombineValidators<T, A, B> where A: ValueInputValidate<T>, B: ValueInputValidate<T> {
fn validate(&self, val: &T) -> Result<(), PropertyValidationError<T>> {
try!(self.a.validate(val));
try!(self.b.validate(val));
Ok(())
}
}
pub fn validate_property_min_max<T>(min: T, max: T) -> ValueInputWithValidation<T, ValueInputFromStr, ValueCombineValidators<T, ValueMin<T>, ValueMax<T>>>
where T: FromStr + Copy + PartialOrd
{
let min = ValueMin { min: min };
let max = ValueMax { max: max };
let validate = ValueCombineValidators { t: PhantomData, a: min, b: max };
let input = ValueInputWithValidation { t: PhantomData, input: ValueInputFromStr, validate: validate };
input
}