verify/impls/schemars/
macros.rs

1//! This module contains macros for schema validation, as it is a very
2//! boilerplate-y procedure.
3//!
4//! Some of the macros below are repeated in every method for Validator.
5
6macro_rules! not_bool_schema {
7    ($schema:expr, $span:expr) => {
8        not_bool_schema!((), $schema, $span)
9    };
10    ($ret_val:expr, $schema:expr, $span:expr) => {
11        match &$schema {
12            SchemaRef::Bool(allow_all) => {
13                if *allow_all {
14                    return Ok($ret_val);
15                } else {
16                    let mut errors = ErrorsInner::new();
17                    errors.push(Error::new(None, ($span).clone(), ErrorValue::Never));
18                    return Err(Errors(errors));
19                }
20            }
21            SchemaRef::Object(o) => o,
22        }
23    };
24}
25
26macro_rules! check_type {
27    ($actual_type:ident, $schema:expr, $span:expr) => {
28        match &$schema.instance_type {
29            Some(s) => match s {
30                SingleOrVec::Single(single) => match &**single {
31                    InstanceType::$actual_type => Ok(()),
32                    _ => {
33                        let mut errors = ErrorsInner::new();
34                        errors.push(Error::new(
35                            $schema.metadata.clone(),
36                            $span.clone(),
37                            ErrorValue::InvalidType {
38                                expected: s.clone(),
39                                actual: InstanceType::$actual_type,
40                            },
41                        ));
42                        Err(Errors(errors))
43                    }
44                },
45                SingleOrVec::Vec(vec) => {
46                    if vec.iter().any(|i| *i == InstanceType::$actual_type) {
47                        Ok(())
48                    } else {
49                        let mut errors = ErrorsInner::new();
50                        errors.push(Error::new(
51                            $schema.metadata.clone(),
52                            $span.clone(),
53                            ErrorValue::InvalidType {
54                                expected: s.clone(),
55                                actual: InstanceType::$actual_type,
56                            },
57                        ));
58                        Err(Errors(errors))
59                    }
60                }
61            },
62            None => {
63                let mut errors = ErrorsInner::new();
64                errors.push(Error::new(
65                    $schema.metadata.clone(),
66                    $span.clone(),
67                    ErrorValue::InvalidType {
68                        expected: SingleOrVec::Single(Box::new(InstanceType::Object)),
69                        actual: InstanceType::$actual_type,
70                    },
71                ));
72                Err(Errors(errors))
73            }
74        }
75    };
76    ($schema:expr, $span:expr) => {
77        match &$schema.instance_type {
78            Some(s) => match s {
79                SingleOrVec::Single(single) => match &**single {
80                    InstanceType::Object => Ok(()),
81                    _ => {
82                        let mut errors = ErrorsInner::new();
83                        errors.push(Error::new(
84                            $schema.metadata.clone(),
85                            $span.clone(),
86                            ErrorValue::InvalidType {
87                                expected: s.clone(),
88                                actual: InstanceType::Object,
89                            },
90                        ));
91                        Err(Errors(errors))
92                    }
93                },
94                SingleOrVec::Vec(vec) => {
95                    if vec.iter().any(|i| *i == InstanceType::Object) {
96                        Ok(())
97                    } else {
98                        let mut errors = ErrorsInner::new();
99                        errors.push(Error::new(
100                            $schema.metadata.clone(),
101                            $span.clone(),
102                            ErrorValue::InvalidType {
103                                expected: s.clone(),
104                                actual: InstanceType::Object,
105                            },
106                        ));
107                        Err(Errors(errors))
108                    }
109                }
110            },
111            None => Ok(()),
112        }
113    };
114}
115
116macro_rules! check_enum {
117    (bool, $value:expr, $schema:expr, $span:expr) => {
118        if let Some(enum_vals) = &$schema.enum_values {
119            let mut enum_contains = false;
120            for val in enum_vals {
121                if let Some(v) = val.as_bool() {
122                    if v == $value {
123                        enum_contains = true;
124                        break;
125                    }
126                }
127            }
128
129            if enum_contains {
130                Ok(())
131            } else {
132                let mut errors = ErrorsInner::new();
133                errors.push(Error::new(
134                    $schema.metadata.clone(),
135                    $span.clone(),
136                    ErrorValue::InvalidEnumValue {
137                        expected: enum_vals.clone(),
138                    },
139                ));
140                Err(Errors(errors))
141            }
142        } else {
143            Ok(())
144        }
145    };
146    (int, $value:expr, $schema:expr, $span:expr) => {
147        if let Some(enum_vals) = &$schema.enum_values {
148            let mut errors = ErrorsInner::new();
149
150            let mut enum_contains = false;
151            for val in enum_vals {
152                if let Some(v) = val.as_i64() {
153                    if v == $value as i64 {
154                        enum_contains = true;
155                        break;
156                    }
157                }
158                if let Some(v) = val.as_u64() {
159                    if v == $value as u64 {
160                        enum_contains = true;
161                        break;
162                    }
163                }
164            }
165
166            if enum_contains {
167                Ok(())
168            } else {
169                errors.push(Error::new(
170                    $schema.metadata.clone(),
171                    $span.clone(),
172                    ErrorValue::InvalidEnumValue {
173                        expected: enum_vals.clone(),
174                    },
175                ));
176                Err(Errors(errors))
177            }
178        } else {
179            Ok(())
180        }
181    };
182    (float, $value:expr, $schema:expr, $span:expr) => {
183        if let Some(enum_vals) = &$schema.enum_values {
184            let mut errors = ErrorsInner::new();
185
186            let mut enum_contains = false;
187            for val in enum_vals {
188                if let Some(v) = val.as_f64() {
189                    if f64::abs(v - $value as f64) < core::f64::EPSILON {
190                        enum_contains = true;
191                        break;
192                    }
193                }
194            }
195
196            if enum_contains {
197                Ok(())
198            } else {
199                errors.push(Error::new(
200                    $schema.metadata.clone(),
201                    $span.clone(),
202                    ErrorValue::InvalidEnumValue {
203                        expected: enum_vals.clone(),
204                    },
205                ));
206                Err(Errors(errors))
207            }
208        } else {
209            Ok(())
210        }
211    };
212    (str, $value:expr, $schema:expr, $span:expr) => {
213        if let Some(enum_vals) = &$schema.enum_values {
214            let mut enum_contains = false;
215            for val in enum_vals {
216                if let Some(v) = val.as_str() {
217                    if v == $value {
218                        enum_contains = true;
219                        break;
220                    }
221                }
222            }
223
224            if enum_contains {
225                Ok(())
226            } else {
227                let mut errors = ErrorsInner::new();
228                errors.push(Error::new(
229                    $schema.metadata.clone(),
230                    $span.clone(),
231                    ErrorValue::InvalidEnumValue {
232                        expected: enum_vals.clone(),
233                    },
234                ));
235                Err(Errors(errors))
236            }
237        } else {
238            Ok(())
239        }
240    };
241}
242
243macro_rules! check_number {
244    ($value:expr, $schema:expr, $span:expr) => {
245        if let Some(n) = &$schema.number {
246            let mut errors = ErrorsInner::new();
247
248            let mut number_err = false;
249
250            if let Some(m) = n.multiple_of {
251                if m != 0f64 && $value as f64 % m != 0f64 {
252                    errors.push(Error::new(
253                        $schema.metadata.clone(),
254                        $span.clone(),
255                        ErrorValue::NotMultipleOf { multiple_of: m },
256                    ));
257                    number_err = true;
258                }
259            }
260
261            if let Some(min) = n.minimum {
262                if ($value as f64) < min {
263                    errors.push(Error::new(
264                        $schema.metadata.clone(),
265                        $span.clone(),
266                        ErrorValue::LessThanExpected {
267                            min,
268                            exclusive: false,
269                        },
270                    ));
271                    number_err = true;
272                }
273            }
274
275            if let Some(min) = n.exclusive_minimum {
276                if ($value as f64) <= min {
277                    errors.push(Error::new(
278                        $schema.metadata.clone(),
279                        $span.clone(),
280                        ErrorValue::LessThanExpected {
281                            min,
282                            exclusive: true,
283                        },
284                    ));
285                    number_err = true;
286                }
287            }
288
289            if let Some(max) = n.maximum {
290                if ($value as f64) > max {
291                    errors.push(Error::new(
292                        $schema.metadata.clone(),
293                        $span.clone(),
294                        ErrorValue::MoreThanExpected {
295                            max,
296                            exclusive: false,
297                        },
298                    ));
299                    number_err = true;
300                }
301            }
302
303            if let Some(max) = n.exclusive_maximum {
304                if ($value as f64) >= max {
305                    errors.push(Error::new(
306                        $schema.metadata.clone(),
307                        $span.clone(),
308                        ErrorValue::MoreThanExpected {
309                            max,
310                            exclusive: true,
311                        },
312                    ));
313                    number_err = true;
314                }
315            }
316            if !number_err {
317                Ok(())
318            } else {
319                Err(Errors(errors))
320            }
321        } else {
322            Ok(())
323        };
324    };
325}
326
327// TODO format
328macro_rules! check_string {
329    ($value:expr, $schema:expr, $span:expr) => {
330        if let Some(s) = &$schema.string {
331            let mut errors = ErrorsInner::new();
332
333            let mut string_err = false;
334
335            if let Some(p) = &s.pattern {
336                let re = regex::Regex::new(&*p).map_err(|error| {
337                    Errors::one(Error::new(
338                        $schema.metadata.clone(),
339                        $span.clone(),
340                        ErrorValue::InvalidSchema(InvalidSchema::InvalidPattern {
341                            pattern: p.clone(),
342                            error,
343                        }),
344                    ))
345                })?;
346
347                if !re.is_match($value) {
348                    errors.push(Error::new(
349                        $schema.metadata.clone(),
350                        $span.clone(),
351                        ErrorValue::NoPatternMatch { pattern: p.clone() },
352                    ));
353                    string_err = true;
354                }
355
356                if let Some(max_length) = s.max_length {
357                    if $value.chars().count() > max_length as usize {
358                        errors.push(Error::new(
359                            $schema.metadata.clone(),
360                            $span.clone(),
361                            ErrorValue::TooLong { max_length },
362                        ));
363                        string_err = true;
364                    }
365                }
366
367                if let Some(min_length) = s.min_length {
368                    if $value.chars().count() < min_length as usize {
369                        errors.push(Error::new(
370                            $schema.metadata.clone(),
371                            $span.clone(),
372                            ErrorValue::TooShort { min_length },
373                        ));
374                        string_err = true;
375                    }
376                }
377            }
378
379            if !string_err {
380                Ok(())
381            } else {
382                Err(Errors(errors))
383            }
384        } else {
385            Ok(())
386        }
387    };
388}