validator_async/validation/
range.rs1pub trait ValidateRange<T> {
5 fn validate_range(
6 &self,
7 min: Option<T>,
8 max: Option<T>,
9 exclusive_min: Option<T>,
10 exclusive_max: Option<T>,
11 ) -> bool {
12 if let Some(max) = max {
13 if let Some(gt) = self.greater_than(max) {
14 if gt {
15 return false;
16 }
17 }
18 }
19
20 if let Some(min) = min {
21 if let Some(lt) = self.less_than(min) {
22 if lt {
23 return false;
24 }
25 }
26 }
27
28 if let Some(exclusive_max) = exclusive_max {
29 if let Some(lt) = self.less_than(exclusive_max) {
30 if !lt {
31 return false;
32 }
33 }
34 }
35
36 if let Some(exclusive_min) = exclusive_min {
37 if let Some(gt) = self.greater_than(exclusive_min) {
38 if !gt {
39 return false;
40 }
41 }
42 }
43
44 true
45 }
46 fn greater_than(&self, max: T) -> Option<bool>;
47 fn less_than(&self, min: T) -> Option<bool>;
48}
49
50pub trait ValidateRangeType {}
51
52impl<T> ValidateRange<T> for T
53where
54 T: PartialEq + PartialOrd + ValidateRangeType,
55{
56 fn greater_than(&self, max: T) -> Option<bool> {
57 Some(self > &max)
58 }
59
60 fn less_than(&self, min: T) -> Option<bool> {
61 Some(self < &min)
62 }
63}
64
65impl<T> ValidateRange<T> for Option<T>
66where
67 T: PartialEq + PartialOrd + ValidateRangeType,
68{
69 fn greater_than(&self, max: T) -> Option<bool> {
70 self.as_ref().map(|r| r > &max)
71 }
72
73 fn less_than(&self, min: T) -> Option<bool> {
74 self.as_ref().map(|r| r < &min)
75 }
76}
77
78impl<T> ValidateRange<T> for Option<Option<T>>
79where
80 T: PartialEq + PartialOrd + ValidateRangeType,
81{
82 fn greater_than(&self, max: T) -> Option<bool> {
83 if let Some(r) = self {
84 r.as_ref().map(|r| r > &max)
85 } else {
86 None
87 }
88 }
89
90 fn less_than(&self, min: T) -> Option<bool> {
91 if let Some(r) = self {
92 r.as_ref().map(|r| r < &min)
93 } else {
94 None
95 }
96 }
97}
98
99macro_rules! impl_val_range {
100 ($t:tt) => {
101 impl ValidateRange<$t> for $t {
102 fn greater_than(&self, max: $t) -> Option<bool> {
103 Some(self > &max)
104 }
105
106 fn less_than(&self, min: $t) -> Option<bool> {
107 Some(self < &min)
108 }
109 }
110
111 impl ValidateRange<$t> for Option<$t> {
112 fn greater_than(&self, max: $t) -> Option<bool> {
113 self.map(|r| r > max)
114 }
115
116 fn less_than(&self, min: $t) -> Option<bool> {
117 self.map(|r| r < min)
118 }
119 }
120
121 impl ValidateRange<$t> for Option<Option<$t>> {
122 fn greater_than(&self, max: $t) -> Option<bool> {
123 self.flatten().map(|r| r > max)
124 }
125
126 fn less_than(&self, min: $t) -> Option<bool> {
127 self.flatten().map(|r| r < min)
128 }
129 }
130 };
131}
132
133impl_val_range!(u8);
134impl_val_range!(u16);
135impl_val_range!(u32);
136impl_val_range!(u64);
137impl_val_range!(u128);
138impl_val_range!(usize);
139impl_val_range!(i8);
140impl_val_range!(i16);
141impl_val_range!(i32);
142impl_val_range!(i64);
143impl_val_range!(i128);
144impl_val_range!(isize);
145impl_val_range!(f32);
146impl_val_range!(f64);
147
148#[cfg(test)]
149mod tests {
150 use crate::validation::range::ValidateRangeType;
151
152 use super::ValidateRange;
153
154 #[test]
155 fn test_validate_range_generic_ok() {
156 assert!(10.validate_range(Some(-10), Some(10), None, None));
158 assert!(0.0.validate_range(Some(0.0), Some(10.0), None, None));
159
160 assert!(5u8.validate_range(Some(0), Some(255), None, None));
162 assert!(4u16.validate_range(Some(0), Some(16), None, None));
163 assert!(6u32.validate_range(Some(0), Some(23), None, None));
164 }
165
166 #[test]
167 fn test_validate_range_generic_fail() {
168 assert!(!5.validate_range(Some(17), Some(19), None, None));
169 assert!(!(-1.0).validate_range(Some(0.0), Some(10.0), None, None));
170 }
171
172 #[test]
173 fn test_validate_range_generic_min_only() {
174 assert!(!5.validate_range(Some(10), None, None, None));
175 assert!(15.validate_range(Some(10), None, None, None));
176 }
177
178 #[test]
179 fn test_validate_range_generic_max_only() {
180 assert!(5.validate_range(None, Some(10), None, None));
181 assert!(!15.validate_range(None, Some(10), None, None));
182 }
183
184 #[test]
185 fn test_validate_range_generic_exc_ok() {
186 assert!(6.validate_range(None, None, Some(5), Some(7)));
187 assert!(0.0001.validate_range(None, None, Some(0.0), Some(1.0)));
188 }
189
190 #[test]
191 fn test_validate_range_generic_exc_fail() {
192 assert!(!5.validate_range(None, None, Some(5), None));
193 }
194
195 #[test]
196 fn test_validate_range_generic_exclusive_max_only() {
197 assert!(!10.validate_range(None, None, None, Some(10)));
198 assert!(9.validate_range(None, None, None, Some(10)));
199 }
200
201 #[test]
202 fn test_validate_range_generic_exclusive_min_only() {
203 assert!(!10.validate_range(None, None, Some(10), None));
204 assert!(9.validate_range(None, None, Some(8), None));
205 }
206
207 #[test]
208 fn test_validate_range_with_enums() {
209 #[derive(PartialEq, PartialOrd)]
210 enum Test {
211 One,
212 Two,
213 Three,
214 Four,
215 }
216
217 impl ValidateRangeType for Test {}
218
219 assert!(Test::Two.validate_range(Some(Test::One), Some(Test::Three), None, None));
220 assert!(!Test::Four.validate_range(Some(Test::One), Some(Test::Three), None, None));
221 }
222
223 #[test]
224 fn test_validate_range_with_option() {
225 assert!(Some(5).validate_range(Some(1), Some(10), None, None));
226 assert!(!Some(11).validate_range(Some(1), Some(10), None, None));
227 }
228
229 #[test]
230 fn test_validate_range_with_none_value() {
231 let none: Option<usize> = None;
232 let none_none: Option<Option<usize>> = None;
233 assert!(none.validate_range(Some(1), Some(10), None, None));
234 assert!(none.validate_range(Some(1), None, None, Some(10)));
235 assert!(none_none.validate_range(Some(1), Some(10), None, None));
236 }
237}