icydb_base/validator/
num.rs1use crate::{
2 core::traits::{NumCast, Validator},
3 prelude::*,
4};
5
6fn cast_decimal<N: NumCast + Clone>(value: &N) -> Result<Decimal, String> {
7 <Decimal as NumCast>::from(value.clone()).ok_or_else(|| {
8 format!(
9 "value of type {} cannot be represented as Decimal",
10 core::any::type_name::<N>()
11 )
12 })
13}
14
15#[validator]
20pub struct Lt {
21 target: Decimal,
22}
23
24impl Lt {
25 pub fn new<N: NumCast + Clone>(target: N) -> Self {
26 let target = cast_decimal(&target)
27 .unwrap_or_else(|e| panic!("Lt::new failed to convert target: {e}"));
28
29 Self { target }
30 }
31}
32
33impl<N: NumCast + Clone> Validator<N> for Lt {
34 fn validate(&self, value: &N) -> Result<(), String> {
35 let v = cast_decimal(value)?;
36
37 if v < self.target {
38 Ok(())
39 } else {
40 Err(format!("{} must be < {}", v, self.target))
41 }
42 }
43}
44
45#[validator]
50pub struct Gt {
51 target: Decimal,
52}
53
54impl Gt {
55 pub fn new<N: NumCast + Clone>(target: N) -> Self {
56 let target = cast_decimal(&target)
57 .unwrap_or_else(|e| panic!("Gt::new failed to convert target: {e}"));
58
59 Self { target }
60 }
61}
62
63impl<N: NumCast + Clone> Validator<N> for Gt {
64 fn validate(&self, value: &N) -> Result<(), String> {
65 let v = cast_decimal(value)?;
66
67 if v > self.target {
68 Ok(())
69 } else {
70 Err(format!("{} must be > {}", v, self.target))
71 }
72 }
73}
74
75#[validator]
80pub struct Lte {
81 target: Decimal,
82}
83
84impl Lte {
85 pub fn new<N: NumCast + Clone>(target: N) -> Self {
86 let target = cast_decimal(&target)
87 .unwrap_or_else(|e| panic!("Lte::new failed to convert target: {e}"));
88
89 Self { target }
90 }
91}
92
93impl<N: NumCast + Clone> Validator<N> for Lte {
94 fn validate(&self, value: &N) -> Result<(), String> {
95 let v = cast_decimal(value)?;
96
97 if v <= self.target {
98 Ok(())
99 } else {
100 Err(format!("{} must be <= {}", v, self.target))
101 }
102 }
103}
104
105#[validator]
110pub struct Gte {
111 target: Decimal,
112}
113
114impl Gte {
115 pub fn new<N: NumCast + Clone>(target: N) -> Self {
116 let target = cast_decimal(&target)
117 .unwrap_or_else(|e| panic!("Gte::new failed to convert target: {e}"));
118
119 Self { target }
120 }
121}
122
123impl<N: NumCast + Clone> Validator<N> for Gte {
124 fn validate(&self, value: &N) -> Result<(), String> {
125 let v = cast_decimal(value)?;
126
127 if v >= self.target {
128 Ok(())
129 } else {
130 Err(format!("{} must be >= {}", v, self.target))
131 }
132 }
133}
134
135#[validator]
140pub struct Equal {
141 target: Decimal,
142}
143
144impl Equal {
145 pub fn new<N: NumCast + Clone>(target: N) -> Self {
146 let target = cast_decimal(&target)
147 .unwrap_or_else(|e| panic!("Equal::new failed to convert target: {e}"));
148
149 Self { target }
150 }
151}
152
153impl<N: NumCast + Clone> Validator<N> for Equal {
154 fn validate(&self, value: &N) -> Result<(), String> {
155 let v = cast_decimal(value)?;
156
157 if v == self.target {
158 Ok(())
159 } else {
160 Err(format!("{} must be == {}", v, self.target))
161 }
162 }
163}
164
165#[validator]
170pub struct NotEqual {
171 target: Decimal,
172}
173
174impl NotEqual {
175 pub fn new<N: NumCast + Clone>(target: N) -> Self {
176 let target = cast_decimal(&target)
177 .unwrap_or_else(|e| panic!("NotEqual::new failed to convert target: {e}"));
178
179 Self { target }
180 }
181}
182
183impl<N: NumCast + Clone> Validator<N> for NotEqual {
184 fn validate(&self, value: &N) -> Result<(), String> {
185 let v = cast_decimal(value)?;
186
187 if v == self.target {
188 Err(format!("{} must be != {}", v, self.target))
189 } else {
190 Ok(())
191 }
192 }
193}
194
195#[validator]
200pub struct Range {
201 min: Decimal,
202 max: Decimal,
203}
204
205impl Range {
206 pub fn new<N: NumCast + Clone>(min: N, max: N) -> Self {
207 let min =
208 cast_decimal(&min).unwrap_or_else(|e| panic!("Range::new failed to convert min: {e}"));
209 let max =
210 cast_decimal(&max).unwrap_or_else(|e| panic!("Range::new failed to convert max: {e}"));
211 assert!(min <= max, "range requires min <= max");
212
213 Self { min, max }
214 }
215}
216
217impl<N: NumCast + Clone> Validator<N> for Range {
218 fn validate(&self, n: &N) -> Result<(), String> {
219 let v = cast_decimal(n)?;
220
221 if v < self.min || v > self.max {
222 Err(format!(
223 "{} must be between {} and {}",
224 v, self.min, self.max
225 ))
226 } else {
227 Ok(())
228 }
229 }
230}
231
232#[validator]
237pub struct MultipleOf {
238 target: Decimal,
239}
240
241impl MultipleOf {
242 pub fn new<N: NumCast + Clone>(target: N) -> Self {
243 let target = cast_decimal(&target)
244 .unwrap_or_else(|e| panic!("MultipleOf::new failed to convert target: {e}"));
245 Self { target }
246 }
247}
248
249impl<N: NumCast + Clone> Validator<N> for MultipleOf {
250 fn validate(&self, n: &N) -> Result<(), String> {
251 let v = cast_decimal(n)?;
252
253 if (*v % *self.target).is_zero() {
254 Ok(())
255 } else {
256 Err(format!("{v} is not a multiple of {}", self.target))
257 }
258 }
259}
260
261#[cfg(test)]
266mod tests {
267 use super::*;
268
269 fn dec(v: &str) -> Decimal {
270 Decimal::from_str(v).unwrap()
271 }
272
273 #[test]
278 fn lt_success() {
279 assert!(Lt::new(10).validate(&5).is_ok());
280 assert!(Lt::new(5.1).validate(&5.0).is_ok());
281 assert!(Lt::new(dec("10.0")).validate(&dec("9.999")).is_ok());
282 }
283
284 #[test]
285 fn lt_failure() {
286 assert!(Lt::new(5).validate(&5).is_err());
287 assert!(Lt::new(5).validate(&6).is_err());
288 }
289
290 #[test]
295 fn gt_success() {
296 assert!(Gt::new(5).validate(&10).is_ok());
297 assert!(Gt::new(dec("1.0")).validate(&dec("1.0001")).is_ok());
298 }
299
300 #[test]
301 fn gt_failure() {
302 assert!(Gt::new(10).validate(&10).is_err());
303 assert!(Gt::new(10).validate(&5).is_err());
304 }
305
306 #[test]
311 fn lte_success() {
312 assert!(Lte::new(5).validate(&5).is_ok());
313 assert!(Lte::new(5).validate(&4).is_ok());
314 assert!(Lte::new(dec("1.0")).validate(&dec("1.0")).is_ok());
315 }
316
317 #[test]
318 fn lte_failure() {
319 assert!(Lte::new(5).validate(&6).is_err());
320 }
321
322 #[test]
327 fn gte_success() {
328 assert!(Gte::new(5).validate(&5).is_ok());
329 assert!(Gte::new(5).validate(&6).is_ok());
330 }
331
332 #[test]
333 fn gte_failure() {
334 assert!(Gte::new(5).validate(&4).is_err());
335 }
336
337 #[test]
342 fn equal_success() {
343 assert!(Equal::new(5).validate(&5).is_ok());
344 assert!(Equal::new(dec("1.23")).validate(&dec("1.23")).is_ok());
345 }
346
347 #[test]
348 fn equal_failure() {
349 assert!(Equal::new(5).validate(&6).is_err());
350 assert!(Equal::new(dec("1.23")).validate(&dec("1.2300001")).is_err());
351 }
352
353 #[test]
358 fn not_equal_success() {
359 assert!(NotEqual::new(5).validate(&6).is_ok());
360 assert!(NotEqual::new(dec("1.23")).validate(&dec("1.2301")).is_ok());
361 }
362
363 #[test]
364 fn not_equal_failure() {
365 assert!(NotEqual::new(5).validate(&5).is_err());
366 assert!(NotEqual::new(dec("1.23")).validate(&dec("1.23")).is_err());
367 }
368
369 #[test]
374 fn range_success() {
375 let r = Range::new(0, 10);
376 assert!(r.validate(&0).is_ok());
377 assert!(r.validate(&5).is_ok());
378 assert!(r.validate(&10).is_ok());
379
380 let r2 = Range::new(dec("1.23"), dec("2.34"));
381 assert!(r2.validate(&dec("1.23")).is_ok());
382 assert!(r2.validate(&dec("2.34")).is_ok());
383 assert!(r2.validate(&dec("1.5")).is_ok());
384 }
385
386 #[test]
387 fn range_failure() {
388 let r = Range::new(0, 10);
389 assert!(r.validate(&-1).is_err());
390 assert!(r.validate(&11).is_err());
391 assert!(r.validate(&dec("-0.0001")).is_err());
392 }
393
394 #[test]
395 fn range_min_equals_max() {
396 let r = Range::new(5, 5);
397 assert!(r.validate(&5).is_ok());
398 assert!(r.validate(&4).is_err());
399 assert!(r.validate(&6).is_err());
400 }
401
402 #[test]
403 #[should_panic(expected = "range requires min <= max")]
404 fn range_invalid_constructor() {
405 Range::new(10, 5);
406 }
407
408 #[test]
413 fn multiple_of_int_success() {
414 assert!(MultipleOf::new(5).validate(&10).is_ok());
415 assert!(MultipleOf::new(5).validate(&0).is_ok());
416 }
417
418 #[test]
419 fn multiple_of_int_failure() {
420 assert!(MultipleOf::new(5).validate(&11).is_err());
421 assert!(MultipleOf::new(3).validate(&10).is_err());
422 }
423
424 #[test]
425 fn multiple_of_decimal_success() {
426 assert!(MultipleOf::new(dec("0.5")).validate(&dec("2.5")).is_ok());
427 assert!(MultipleOf::new(dec("0.1")).validate(&dec("1.2")).is_ok());
428 assert!(MultipleOf::new(dec("1.25")).validate(&dec("6.25")).is_ok());
429 }
430
431 #[test]
432 fn multiple_of_decimal_failure() {
433 assert!(MultipleOf::new(dec("0.5")).validate(&dec("2.6")).is_err());
434 assert!(MultipleOf::new(dec("0.1")).validate(&dec("1.23")).is_err());
435 }
436
437 #[test]
438 fn multiple_of_zero_edge_case() {
439 assert!(MultipleOf::new(1).validate(&0).is_ok());
442 }
443}