validator/
traits.rs

1use crate::types::{ValidationErrors, ValidationErrorsKind};
2use std::borrow::Cow;
3use std::collections::btree_map::BTreeMap;
4use std::collections::HashMap;
5
6/// This is the original trait that was implemented by deriving `Validate`. It will still be
7/// implemented for struct validations that don't take custom arguments. The call is being
8/// forwarded to the `ValidateArgs<'v_a>` trait.
9pub trait Validate {
10    fn validate(&self) -> Result<(), ValidationErrors>;
11}
12
13impl<T: Validate> Validate for &T {
14    fn validate(&self) -> Result<(), ValidationErrors> {
15        T::validate(self)
16    }
17}
18
19macro_rules! impl_validate_list {
20    ($container:ty) => {
21        impl<T: Validate> Validate for $container {
22            fn validate(&self) -> Result<(), ValidationErrors> {
23                let mut vec_err: BTreeMap<usize, Box<ValidationErrors>> = BTreeMap::new();
24
25                for (index, item) in self.iter().enumerate() {
26                    if let Err(e) = item.validate() {
27                        vec_err.insert(index, Box::new(e));
28                    }
29                }
30
31                if vec_err.is_empty() {
32                    Ok(())
33                } else {
34                    let err_kind = ValidationErrorsKind::List(vec_err);
35                    let errors = ValidationErrors(std::collections::HashMap::from([(
36                        Cow::Borrowed("_tmp_validator"),
37                        err_kind,
38                    )]));
39                    Err(errors)
40                }
41            }
42        }
43    };
44}
45
46impl_validate_list!(std::collections::HashSet<T>);
47impl_validate_list!(std::collections::BTreeSet<T>);
48impl_validate_list!(std::collections::BinaryHeap<T>);
49impl_validate_list!(std::collections::LinkedList<T>);
50impl_validate_list!(std::collections::VecDeque<T>);
51impl_validate_list!(std::vec::Vec<T>);
52impl_validate_list!([T]);
53
54impl<T: Validate, const N: usize> Validate for [T; N] {
55    fn validate(&self) -> Result<(), ValidationErrors> {
56        let mut vec_err: BTreeMap<usize, Box<ValidationErrors>> = BTreeMap::new();
57
58        for (index, item) in self.iter().enumerate() {
59            if let Err(e) = item.validate() {
60                vec_err.insert(index, Box::new(e));
61            }
62        }
63
64        if vec_err.is_empty() {
65            Ok(())
66        } else {
67            let err_kind = ValidationErrorsKind::List(vec_err);
68            let errors = ValidationErrors(std::collections::HashMap::from([(
69                Cow::Borrowed("_tmp_validator"),
70                err_kind,
71            )]));
72            Err(errors)
73        }
74    }
75}
76
77impl<K, V: Validate, S> Validate for &HashMap<K, V, S> {
78    fn validate(&self) -> Result<(), ValidationErrors> {
79        let mut vec_err: BTreeMap<usize, Box<ValidationErrors>> = BTreeMap::new();
80
81        for (index, (_key, value)) in self.iter().enumerate() {
82            if let Err(e) = value.validate() {
83                vec_err.insert(index, Box::new(e));
84            }
85        }
86
87        if vec_err.is_empty() {
88            Ok(())
89        } else {
90            let err_kind = ValidationErrorsKind::List(vec_err);
91            let errors =
92                ValidationErrors(HashMap::from([(Cow::Borrowed("_tmp_validator"), err_kind)]));
93            Err(errors)
94        }
95    }
96}
97
98impl<K, V: Validate> Validate for &BTreeMap<K, V> {
99    fn validate(&self) -> Result<(), ValidationErrors> {
100        let mut vec_err: BTreeMap<usize, Box<ValidationErrors>> = BTreeMap::new();
101
102        for (index, (_key, value)) in self.iter().enumerate() {
103            if let Err(e) = value.validate() {
104                vec_err.insert(index, Box::new(e));
105            }
106        }
107
108        if vec_err.is_empty() {
109            Ok(())
110        } else {
111            let err_kind = ValidationErrorsKind::List(vec_err);
112            let errors =
113                ValidationErrors(HashMap::from([(Cow::Borrowed("_tmp_validator"), err_kind)]));
114            Err(errors)
115        }
116    }
117}
118
119/// This trait will be implemented by deriving `Validate`. This implementation can take one
120/// argument and pass this on to custom validators. The default `Args` type will be `()` if
121/// there is no custom validation with defined arguments.
122///
123/// The `Args` type can use the lifetime `'v_a` to pass references onto the validator.
124pub trait ValidateArgs<'v_a> {
125    type Args;
126    fn validate_with_args(&self, args: Self::Args) -> Result<(), ValidationErrors>;
127}
128
129impl<'v_a, T, U> ValidateArgs<'v_a> for Option<T>
130where
131    T: ValidateArgs<'v_a, Args = U>,
132{
133    type Args = U;
134
135    fn validate_with_args(&self, args: Self::Args) -> Result<(), ValidationErrors> {
136        if let Some(nested) = self {
137            T::validate_with_args(nested, args)
138        } else {
139            Ok(())
140        }
141    }
142}