serde_valid/
validation.rs

1mod array;
2mod composited;
3pub mod custom;
4pub mod error;
5mod generic;
6mod numeric;
7mod object;
8mod string;
9
10use crate::{
11    EnumerateError, ExclusiveMaximumError, ExclusiveMinimumError, MaxLengthError,
12    MaxPropertiesError, MaximumError, MinLengthError, MinPropertiesError, MinimumError,
13    MultipleOfError, PatternError,
14};
15pub use composited::Composited;
16
17pub use array::{ValidateMaxItems, ValidateMinItems, ValidateUniqueItems};
18pub use error::{
19    ArrayErrors, Error, Errors, IntoError, ItemErrorsMap, ItemVecErrorsMap, ObjectErrors,
20    PropertyErrorsMap, PropertyVecErrorsMap, VecErrors,
21};
22pub use generic::ValidateEnumerate;
23use indexmap::IndexMap;
24pub use numeric::{
25    ValidateExclusiveMaximum, ValidateExclusiveMinimum, ValidateMaximum, ValidateMinimum,
26    ValidateMultipleOf,
27};
28pub use object::{ValidateMaxProperties, ValidateMinProperties};
29pub use serde_valid_literal::{Literal, Number, Pattern};
30pub use string::{ValidateMaxLength, ValidateMinLength, ValidatePattern};
31
32macro_rules! impl_composited_validation_1args {
33    (
34        pub trait $ValidateCompositedTrait:ident {
35            fn $validate_composited_method:ident(
36                &self,
37                $limit:ident: $limit_type:ty$(,)*
38            ) -> Result<(), Composited<$Error:ty>>;
39        }
40    ) => {
41        paste::paste! {
42            pub trait $ValidateCompositedTrait {
43                fn $validate_composited_method(
44                    &self,
45                    $limit: $limit_type
46                ) -> Result<(), Composited<$Error>>;
47            }
48
49            impl<T> $ValidateCompositedTrait for T
50            where
51                T: [<Validate $limit:camel>],
52            {
53                fn $validate_composited_method(
54                    &self,
55                    $limit: $limit_type,
56                ) -> Result<(), Composited<$Error>> {
57                    self.[<validate_ $limit>]($limit)
58                        .map_err(|error| Composited::Single(error))
59                }
60            }
61
62            impl<T> $ValidateCompositedTrait for Vec<T>
63            where
64                T: $ValidateCompositedTrait,
65            {
66                fn $validate_composited_method(
67                    &self,
68                    $limit: $limit_type,
69                ) -> Result<(), Composited<$Error>> {
70                    let errors: IndexMap<usize, crate::validation::Composited<$Error>> = self
71                        .iter()
72                        .enumerate()
73                        .filter_map(
74                            |(index, item)| match item.$validate_composited_method($limit) {
75                                Ok(_) => None,
76                                Err(error) => Some((index, error)),
77                            },
78                        )
79                        .collect();
80
81                    if errors.is_empty() {
82                        Ok(())
83                    } else {
84                        Err(Composited::Array(errors))
85                    }
86                }
87            }
88
89            impl<T, const N: usize> $ValidateCompositedTrait for [T; N]
90            where
91                T: $ValidateCompositedTrait,
92            {
93                fn $validate_composited_method(
94                    &self,
95                    $limit: $limit_type,
96                ) -> Result<(), Composited<$Error>> {
97                    let errors: IndexMap<usize, crate::validation::Composited<$Error>> = self
98                        .iter()
99                        .enumerate()
100                        .filter_map(
101                            |(index, item)| match item.$validate_composited_method($limit) {
102                                Ok(_) => None,
103                                Err(error) => Some((index, error)),
104                            },
105                        )
106                        .collect();
107
108                    if errors.is_empty() {
109                        Ok(())
110                    } else {
111                        Err(Composited::Array(errors))
112                    }
113                }
114            }
115
116            impl<T> $ValidateCompositedTrait for Option<T>
117            where
118                T: $ValidateCompositedTrait,
119            {
120                fn $validate_composited_method(
121                    &self,
122                    $limit: $limit_type,
123                ) -> Result<(), Composited<$Error>> {
124                    match self {
125                        Some(value) => value.$validate_composited_method($limit),
126                        None => Ok(()),
127                    }
128                }
129            }
130        }
131    };
132    (
133        pub trait $ValidateCompositedTrait:ident {
134            fn $validate_composited_method:ident(
135                &self,
136                $limit:ident: $limit_type:ty$(,)*
137            ) -> Result<(), Composited<$Error:ty>>;
138        }
139
140        impl<K, V> $ValidateCompositedTrait2:ident for std::collections::HashMap<K, V>
141        where
142            V: $ValidateCompositedTrait3:ident;
143    ) => {
144        impl_composited_validation_1args!(
145            pub trait $ValidateCompositedTrait {
146                fn $validate_composited_method(
147                    &self,
148                    $limit: $limit_type
149                ) -> Result<(), Composited<$Error>>;
150            }
151        );
152        paste::paste! {
153            impl<K, V> $ValidateCompositedTrait2 for std::collections::HashMap<K, V>
154            where
155                V: $ValidateCompositedTrait3,
156            {
157                fn $validate_composited_method(
158                    &self,
159                    $limit: $limit_type,
160                ) -> Result<(), Composited<$Error>> {
161                    let errors: IndexMap<usize, crate::validation::Composited<$Error>> = self
162                        .iter()
163                        .enumerate()
164                        .filter_map(
165                            |(index, (_key, value))| match value.$validate_composited_method($limit) {
166                                Ok(_) => None,
167                                Err(error) => Some((index, error)),
168                            },
169                        )
170                        .collect();
171
172                    if errors.is_empty() {
173                        Ok(())
174                    } else {
175                        Err(Composited::Array(errors))
176                    }
177                }
178            }
179        }
180    };
181    (
182        pub trait $ValidateCompositedTrait:ident<T> {
183            fn $validate_composited_method:ident(
184                &self,
185                $limit:ident: T$(,)*
186            ) -> Result<(), Composited<$Error:ty>>;
187        }
188    ) => {
189        pub trait $ValidateCompositedTrait<T> {
190            fn $validate_composited_method(
191                &self,
192                limit: T,
193            ) -> Result<(), crate::validation::Composited<$Error>>;
194        }
195
196        impl<T, U> $ValidateCompositedTrait<T> for Vec<U>
197        where
198            T: Copy,
199            U: $ValidateCompositedTrait<T>,
200        {
201            fn $validate_composited_method(
202                &self,
203                $limit: T,
204            ) -> Result<(), crate::validation::Composited<$Error>> {
205                let errors: IndexMap<usize, crate::validation::Composited<$Error>> = self
206                    .iter()
207                    .enumerate()
208                    .filter_map(
209                        |(index, item)| match item.$validate_composited_method($limit) {
210                            Ok(_) => None,
211                            Err(error) => Some((index, error)),
212                        },
213                    )
214                    .collect();
215
216                if errors.is_empty() {
217                    Ok(())
218                } else {
219                    Err(Composited::Array(errors))
220                }
221            }
222        }
223
224        impl<T, K, V> $ValidateCompositedTrait<T> for std::collections::HashMap<K, V>
225        where
226            T: Copy,
227            V: $ValidateCompositedTrait<T>,
228        {
229            fn $validate_composited_method(&self, $limit: T) -> Result<(), Composited<$Error>> {
230                let errors: IndexMap<usize, crate::validation::Composited<$Error>> = self
231                    .iter()
232                    .enumerate()
233                    .filter_map(|(index, (_key, value))| {
234                        match value.$validate_composited_method($limit) {
235                            Ok(_) => None,
236                            Err(error) => Some((index, error)),
237                        }
238                    })
239                    .collect();
240
241                if errors.is_empty() {
242                    Ok(())
243                } else {
244                    Err(Composited::Array(errors))
245                }
246            }
247        }
248
249        impl<T, U, const N: usize> $ValidateCompositedTrait<T> for [U; N]
250        where
251            T: Copy,
252            U: $ValidateCompositedTrait<T>,
253        {
254            fn $validate_composited_method(
255                &self,
256                $limit: T,
257            ) -> Result<(), crate::validation::Composited<$Error>> {
258                let errors: IndexMap<usize, crate::validation::Composited<$Error>> = self
259                    .iter()
260                    .enumerate()
261                    .filter_map(
262                        |(index, item)| match item.$validate_composited_method($limit) {
263                            Ok(_) => None,
264                            Err(error) => Some((index, error)),
265                        },
266                    )
267                    .collect();
268
269                if errors.is_empty() {
270                    Ok(())
271                } else {
272                    Err(Composited::Array(errors))
273                }
274            }
275        }
276
277        impl<T, U> $ValidateCompositedTrait<T> for Option<U>
278        where
279            T: Copy,
280            U: $ValidateCompositedTrait<T>,
281        {
282            fn $validate_composited_method(
283                &self,
284                limit: T,
285            ) -> Result<(), crate::validation::Composited<$Error>> {
286                match self {
287                    Some(value) => value.$validate_composited_method(limit),
288                    None => Ok(()),
289                }
290            }
291        }
292    };
293}
294
295macro_rules! impl_generic_composited_validation_1args {
296    (
297        $ErrorType:ident,
298        $type:ty
299    ) => {
300        paste::paste! {
301            impl<T> [<ValidateComposited $ErrorType >]<$type> for T
302            where
303                T: [<Validate $ErrorType >]<$type>,
304            {
305                fn [< validate_composited_ $ErrorType:snake>](
306                    &self,
307                    limit: $type,
308                ) -> Result<(), crate::validation::Composited<[<$ErrorType Error>]>> {
309                    self.[< validate_ $ErrorType:snake>](limit)
310                        .map_err(|error| crate::validation::Composited::Single(error))
311                }
312            }
313        }
314    };
315}
316
317pub(crate) use impl_generic_composited_validation_1args;
318
319// Number
320impl_composited_validation_1args!(
321    pub trait ValidateCompositedMaximum<T> {
322        fn validate_composited_maximum(&self, maximum: T) -> Result<(), Composited<MaximumError>>;
323    }
324);
325
326impl_composited_validation_1args!(
327    pub trait ValidateCompositedMinimum<T> {
328        fn validate_composited_minimum(&self, minimum: T) -> Result<(), Composited<MinimumError>>;
329    }
330);
331
332impl_composited_validation_1args!(
333    pub trait ValidateCompositedExclusiveMaximum<T> {
334        fn validate_composited_exclusive_maximum(
335            &self,
336            exclusive_maximum: T,
337        ) -> Result<(), Composited<ExclusiveMaximumError>>;
338    }
339);
340
341impl_composited_validation_1args!(
342    pub trait ValidateCompositedExclusiveMinimum<T> {
343        fn validate_composited_exclusive_minimum(
344            &self,
345            exclusive_minimum: T,
346        ) -> Result<(), Composited<ExclusiveMinimumError>>;
347    }
348);
349
350impl_composited_validation_1args!(
351    pub trait ValidateCompositedMultipleOf<T> {
352        fn validate_composited_multiple_of(
353            &self,
354            exclusive_minimum: T,
355        ) -> Result<(), Composited<MultipleOfError>>;
356    }
357);
358
359// String
360impl_composited_validation_1args!(
361    pub trait ValidateCompositedMaxLength {
362        fn validate_composited_max_length(
363            &self,
364            max_length: usize,
365        ) -> Result<(), Composited<MaxLengthError>>;
366    }
367
368    impl<K, V> ValidateCompositedMaxLength for std::collections::HashMap<K, V>
369    where
370        V: ValidateCompositedMaxLength;
371);
372
373impl_composited_validation_1args!(
374    pub trait ValidateCompositedMinLength {
375        fn validate_composited_min_length(
376            &self,
377            min_length: usize,
378        ) -> Result<(), Composited<MinLengthError>>;
379    }
380
381    impl<K, V> ValidateCompositedMinLength for std::collections::HashMap<K, V>
382    where
383        V: ValidateCompositedMinLength;
384);
385
386impl_composited_validation_1args!(
387    pub trait ValidateCompositedPattern {
388        fn validate_composited_pattern(
389            &self,
390            pattern: &regex::Regex,
391        ) -> Result<(), Composited<PatternError>>;
392    }
393
394    impl<K, V> ValidateCompositedPattern for std::collections::HashMap<K, V>
395    where
396        V: ValidateCompositedPattern;
397);
398
399// Object
400impl_composited_validation_1args!(
401    pub trait ValidateCompositedMaxProperties {
402        fn validate_composited_max_properties(
403            &self,
404            max_properties: usize,
405        ) -> Result<(), Composited<MaxPropertiesError>>;
406    }
407);
408
409impl_composited_validation_1args!(
410    pub trait ValidateCompositedMinProperties {
411        fn validate_composited_min_properties(
412            &self,
413            min_properties: usize,
414        ) -> Result<(), Composited<MinPropertiesError>>;
415    }
416);
417
418// Generic
419impl_composited_validation_1args!(
420    pub trait ValidateCompositedEnumerate<T> {
421        fn validate_composited_enumerate(
422            &self,
423            enumerate: T,
424        ) -> Result<(), Composited<EnumerateError>>;
425    }
426);