Skip to main content

yaml_schema/schemas/
numeric.rs

1use std::cmp::Ordering;
2
3use saphyr::MarkedYaml;
4
5use crate::Number;
6use crate::validation::Context;
7
8/// Shared numeric bound constraints used by both `IntegerSchema` and `NumberSchema`.
9#[derive(Debug, Default, PartialEq)]
10pub struct NumericBounds {
11    pub minimum: Option<Number>,
12    pub maximum: Option<Number>,
13    pub exclusive_minimum: Option<Number>,
14    pub exclusive_maximum: Option<Number>,
15    pub multiple_of: Option<Number>,
16}
17
18impl NumericBounds {
19    /// Validate `actual` against all configured bounds, reporting errors to `context`.
20    pub fn validate(&self, context: &Context, value: &MarkedYaml, actual: Number) {
21        if let Some(exclusive_min) = self.exclusive_minimum
22            && actual.partial_cmp(&exclusive_min) != Some(Ordering::Greater)
23        {
24            context.add_error(
25                value,
26                format!("Number must be greater than {exclusive_min}"),
27            );
28        }
29        if let Some(minimum) = self.minimum
30            && actual < minimum
31        {
32            context.add_error(
33                value,
34                format!("Number must be greater than or equal to {minimum}"),
35            );
36        }
37
38        if let Some(exclusive_max) = self.exclusive_maximum
39            && actual.partial_cmp(&exclusive_max) != Some(Ordering::Less)
40        {
41            context.add_error(value, format!("Number must be less than {exclusive_max}"));
42        }
43        if let Some(maximum) = self.maximum
44            && actual > maximum
45        {
46            context.add_error(
47                value,
48                format!("Number must be less than or equal to {maximum}"),
49            );
50        }
51
52        if let Some(multiple) = self.multiple_of
53            && !actual.is_multiple_of(multiple)
54        {
55            context.add_error(value, format!("Number is not a multiple of {multiple}!"));
56        }
57    }
58}