fog_pack/validator/
float64.rs

1use super::*;
2use crate::element::*;
3use crate::error::{Error, Result};
4use serde::{Deserialize, Serialize};
5
6#[inline]
7fn is_false(v: &bool) -> bool {
8    !v
9}
10#[inline]
11fn is_nan(v: &f64) -> bool {
12    v.is_nan()
13}
14
15/// Validator for 64-bit floating-point values.
16///
17/// This validator will only pass f64 values. Validation passes if:
18///
19/// - If `max` is a number, that the value is less than the maximum in `max`, or equal to it if
20///     `ex_max` is not set to true.
21/// - If `min` is a number, that the value is greater than the minimum in `min`, or equal to it if
22///     `ex_min` is not set to true.
23/// - If the `in` list is not empty, the value must be among the values in it. This performs an
24///     exact bit-wise match.
25/// - The value must not be among the values in the `nin` list. This performas an exact bit-wise
26///     match.
27///
28/// # Defaults
29///
30/// Fields that aren't specified for the validator use their defaults instead. The defaults for
31/// each field are:
32///
33/// - comment: ""
34/// - max: NaN
35/// - min: NaN
36/// - ex_max: false
37/// - ex_min: false
38/// - in_list: empty
39/// - nin_list: empty
40/// - query: false
41/// - ord: false
42///
43#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
44#[serde(deny_unknown_fields, default)]
45pub struct F64Validator {
46    /// An optional comment explaining the validator.
47    #[serde(skip_serializing_if = "String::is_empty")]
48    pub comment: String,
49    /// The maximum allowed f64 value. If NaN, it is ignored.
50    #[serde(skip_serializing_if = "is_nan")]
51    pub max: f64,
52    /// The minimum allowed f64 value. If NaN, it is ignored.
53    #[serde(skip_serializing_if = "is_nan")]
54    pub min: f64,
55    /// Changes `max` into an exclusive maximum.
56    #[serde(skip_serializing_if = "is_false")]
57    pub ex_max: bool,
58    /// Changes `min` into an exclusive maximum.
59    #[serde(skip_serializing_if = "is_false")]
60    pub ex_min: bool,
61    /// A vector of specific allowed values, stored under the `in` field. If empty, this vector is not checked against.
62    #[serde(rename = "in", skip_serializing_if = "Vec::is_empty")]
63    pub in_list: Vec<f64>,
64    #[serde(rename = "nin", skip_serializing_if = "Vec::is_empty")]
65    /// A vector of specific unallowed values, stored under the `nin` field.
66    pub nin_list: Vec<f64>,
67    /// If true, queries against matching spots may have values in the `in` or `nin` lists.
68    #[serde(skip_serializing_if = "is_false")]
69    pub query: bool,
70    /// If true, queries against matching spots may set the `max`, `min`, `ex_max`, and `ex_min`
71    /// values to non-defaults.
72    #[serde(skip_serializing_if = "is_false")]
73    pub ord: bool,
74}
75
76impl std::default::Default for F64Validator {
77    fn default() -> Self {
78        Self {
79            comment: String::new(),
80            max: f64::NAN,
81            min: f64::NAN,
82            ex_max: false,
83            ex_min: false,
84            in_list: Vec::new(),
85            nin_list: Vec::new(),
86            query: false,
87            ord: false,
88        }
89    }
90}
91
92impl F64Validator {
93    /// Make a new validator with the default configuration.
94    pub fn new() -> Self {
95        Self::default()
96    }
97
98    /// Set a comment for the validator.
99    pub fn comment(mut self, comment: impl Into<String>) -> Self {
100        self.comment = comment.into();
101        self
102    }
103
104    /// Set the maximum allowed value.
105    pub fn max(mut self, max: f64) -> Self {
106        self.max = max;
107        self
108    }
109
110    /// Set the minimum allowed value.
111    pub fn min(mut self, min: f64) -> Self {
112        self.min = min;
113        self
114    }
115
116    /// Set whether or or not `max` is an exclusive maximum.
117    pub fn ex_max(mut self, ex_max: bool) -> Self {
118        self.ex_max = ex_max;
119        self
120    }
121
122    /// Set whether or or not `min` is an exclusive maximum.
123    pub fn ex_min(mut self, ex_min: bool) -> Self {
124        self.ex_min = ex_min;
125        self
126    }
127
128    /// Add a value to the `in` list.
129    pub fn in_add(mut self, add: f64) -> Self {
130        self.in_list.push(add);
131        self
132    }
133
134    /// Add a value to the `nin` list.
135    pub fn nin_add(mut self, add: f64) -> Self {
136        self.nin_list.push(add);
137        self
138    }
139
140    /// Set whether or not queries can use the `in` and `nin` lists.
141    pub fn query(mut self, query: bool) -> Self {
142        self.query = query;
143        self
144    }
145
146    /// Set whether or not queries can use the `max`, `min`, `ex_max`, and `ex_min` values.
147    pub fn ord(mut self, ord: bool) -> Self {
148        self.ord = ord;
149        self
150    }
151
152    /// Build this into a [`Validator`] enum.
153    pub fn build(self) -> Validator {
154        Validator::F64(Box::new(self))
155    }
156
157    pub(crate) fn validate(&self, parser: &mut Parser) -> Result<()> {
158        let elem = parser
159            .next()
160            .ok_or_else(|| Error::FailValidate("Expected a f64".to_string()))??;
161        let elem = if let Element::F64(v) = elem {
162            v
163        } else {
164            return Err(Error::FailValidate(format!(
165                "Expected F64, got {}",
166                elem.name()
167            )));
168        };
169        let bytes = elem.to_ne_bytes();
170        if !self.in_list.is_empty() && !self.in_list.iter().any(|v| v.to_ne_bytes() == bytes) {
171            return Err(Error::FailValidate("F64 is not on `in` list".to_string()));
172        }
173        if self.nin_list.iter().any(|v| v.to_ne_bytes() == bytes) {
174            return Err(Error::FailValidate("F64 is on `nin` list".to_string()));
175        }
176        if !self.max.is_nan() && ((self.ex_max && elem >= self.max) || (elem > self.max)) {
177            return Err(Error::FailValidate(
178                "F64 greater than maximum allowed".to_string(),
179            ));
180        }
181        if !self.min.is_nan() && ((self.ex_min && elem <= self.min) || (elem < self.min)) {
182            return Err(Error::FailValidate(
183                "F64 less than maximum allowed".to_string(),
184            ));
185        }
186        Ok(())
187    }
188
189    fn query_check_f64(&self, other: &Self) -> bool {
190        (self.query || (other.in_list.is_empty() && other.nin_list.is_empty()))
191            && (self.ord
192                || (!other.ex_min && !other.ex_max && other.min.is_nan() && other.max.is_nan()))
193    }
194
195    pub(crate) fn query_check(&self, other: &Validator) -> bool {
196        match other {
197            Validator::F64(other) => self.query_check_f64(other),
198            Validator::Multi(list) => list.iter().all(|other| match other {
199                Validator::F64(other) => self.query_check_f64(other),
200                _ => false,
201            }),
202            Validator::Any => true,
203            _ => false,
204        }
205    }
206}