validator_async/
traits.rs

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