fog_pack/validator/
time.rs

1use super::*;
2use crate::element::*;
3use crate::error::{Error, Result};
4use crate::Timestamp;
5use serde::{Deserialize, Serialize};
6use std::default::Default;
7
8#[inline]
9fn is_false(v: &bool) -> bool {
10    !v
11}
12
13const MIN_TIME: Timestamp = Timestamp::min_value();
14const MAX_TIME: Timestamp = Timestamp::max_value();
15
16#[inline]
17fn time_is_min(v: &Timestamp) -> bool {
18    *v == MIN_TIME
19}
20
21#[inline]
22fn time_is_max(v: &Timestamp) -> bool {
23    *v == MAX_TIME
24}
25
26/// Validator for timestamps.
27///
28/// This validator will only pass timestamps. Validation passes if:
29///
30/// - If the `in` list is not empty, the timestamp must be among the timestamp in the list.
31/// - The timestamp must not be among the timestamp in the `nin` list.
32/// - The timestamp is less than the maximum in `max`, or equal to it if `ex_max` is not set to true.
33/// - The timestamp is greater than the minimum in `min`, or equal to it if `ex_min` is not set to true.
34///
35/// # Defaults
36///
37/// Fields that aren't specified for the validator use their defaults instead. The defaults for
38/// each field are:
39///
40/// - comment: ""
41/// - max: maximum possible timestamp
42/// - min: minimum possible timestamp
43/// - ex_max: false
44/// - ex_min: false
45/// - in_list: empty
46/// - nin_list: empty
47/// - query: false
48/// - ord: false
49///
50#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
51#[serde(deny_unknown_fields, default)]
52pub struct TimeValidator {
53    /// An optional comment explaining the validator.
54    #[serde(skip_serializing_if = "String::is_empty")]
55    pub comment: String,
56    /// The maximum allowed timestamp.
57    #[serde(skip_serializing_if = "time_is_max")]
58    pub max: Timestamp,
59    /// The minimum allowed timestamp.
60    #[serde(skip_serializing_if = "time_is_min")]
61    pub min: Timestamp,
62    /// Changes `max` into an exclusive maximum.
63    #[serde(skip_serializing_if = "is_false")]
64    pub ex_max: bool,
65    /// Changes `min` into an exclusive maximum.
66    #[serde(skip_serializing_if = "is_false")]
67    pub ex_min: bool,
68    /// A vector of specific allowed values, stored under the `in` field. If empty, this vector is not checked against.
69    #[serde(rename = "in", skip_serializing_if = "Vec::is_empty")]
70    pub in_list: Vec<Timestamp>,
71    /// A vector of specific unallowed values, stored under the `nin` field.
72    #[serde(rename = "nin", skip_serializing_if = "Vec::is_empty")]
73    pub nin_list: Vec<Timestamp>,
74    /// If true, queries against matching spots may have values in the `in` or `nin` lists.
75    #[serde(skip_serializing_if = "is_false")]
76    pub query: bool,
77    /// If true, queries against matching spots may set the `max`, `min`, `ex_max`, and `ex_min`
78    /// values to non-defaults.
79    #[serde(skip_serializing_if = "is_false")]
80    pub ord: bool,
81}
82
83impl Default for TimeValidator {
84    fn default() -> Self {
85        Self {
86            comment: String::new(),
87            max: MAX_TIME,
88            min: MIN_TIME,
89            ex_max: false,
90            ex_min: false,
91            in_list: Vec::new(),
92            nin_list: Vec::new(),
93            query: false,
94            ord: false,
95        }
96    }
97}
98
99impl TimeValidator {
100    /// Make a new validator with the default configuration.
101    pub fn new() -> Self {
102        Self::default()
103    }
104
105    /// Set a comment for the validator.
106    pub fn comment(mut self, comment: impl Into<String>) -> Self {
107        self.comment = comment.into();
108        self
109    }
110
111    /// Set the maximum allowed value.
112    pub fn max(mut self, max: impl Into<Timestamp>) -> Self {
113        self.max = max.into();
114        self
115    }
116
117    /// Set the minimum allowed value.
118    pub fn min(mut self, min: impl Into<Timestamp>) -> Self {
119        self.min = min.into();
120        self
121    }
122
123    /// Set whether or or not `max` is an exclusive maximum.
124    pub fn ex_max(mut self, ex_max: bool) -> Self {
125        self.ex_max = ex_max;
126        self
127    }
128
129    /// Set whether or or not `min` is an exclusive maximum.
130    pub fn ex_min(mut self, ex_min: bool) -> Self {
131        self.ex_min = ex_min;
132        self
133    }
134
135    /// Add a value to the `in` list.
136    pub fn in_add(mut self, add: impl Into<Timestamp>) -> Self {
137        self.in_list.push(add.into());
138        self
139    }
140
141    /// Add a value to the `nin` list.
142    pub fn nin_add(mut self, add: impl Into<Timestamp>) -> Self {
143        self.nin_list.push(add.into());
144        self
145    }
146
147    /// Set whether or not queries can use the `in` and `nin` lists.
148    pub fn query(mut self, query: bool) -> Self {
149        self.query = query;
150        self
151    }
152
153    /// Set whether or not queries can use the `max`, `min`, `ex_max`, and `ex_min` values.
154    pub fn ord(mut self, ord: bool) -> Self {
155        self.ord = ord;
156        self
157    }
158
159    /// Build this into a [`Validator`] enum.
160    pub fn build(self) -> Validator {
161        Validator::Time(Box::new(self))
162    }
163
164    pub(crate) fn validate(&self, parser: &mut Parser) -> Result<()> {
165        let elem = parser
166            .next()
167            .ok_or_else(|| Error::FailValidate("Expected a timestamp".to_string()))??;
168        let val = if let Element::Timestamp(v) = elem {
169            v
170        } else {
171            return Err(Error::FailValidate(format!(
172                "Expected Time, got {}",
173                elem.name()
174            )));
175        };
176
177        // Range checks
178        let max_pass = if self.ex_max {
179            val < self.max
180        } else {
181            val <= self.max
182        };
183        let min_pass = if self.ex_min {
184            val > self.min
185        } else {
186            val >= self.min
187        };
188        if !max_pass {
189            return Err(Error::FailValidate(
190                "Timestamp greater than maximum allowed".to_string(),
191            ));
192        }
193        if !min_pass {
194            return Err(Error::FailValidate(
195                "Timestamp less than minimum allowed".to_string(),
196            ));
197        }
198
199        // in/nin checks
200        if !self.in_list.is_empty() && !self.in_list.iter().any(|v| *v == val) {
201            return Err(Error::FailValidate(
202                "Timestamp is not on `in` list".to_string(),
203            ));
204        }
205        if self.nin_list.iter().any(|v| *v == val) {
206            return Err(Error::FailValidate(
207                "Timestamp is on `nin` list".to_string(),
208            ));
209        }
210
211        Ok(())
212    }
213
214    fn query_check_self(&self, other: &Self) -> bool {
215        (self.query || (other.in_list.is_empty() && other.nin_list.is_empty()))
216            && (self.ord
217                || (!other.ex_min
218                    && !other.ex_max
219                    && time_is_min(&other.min)
220                    && time_is_max(&other.max)))
221    }
222
223    pub(crate) fn query_check(&self, other: &Validator) -> bool {
224        match other {
225            Validator::Time(other) => self.query_check_self(other),
226            Validator::Multi(list) => list.iter().all(|other| match other {
227                Validator::Time(other) => self.query_check_self(other),
228                _ => false,
229            }),
230            Validator::Any => true,
231            _ => false,
232        }
233    }
234}
235
236#[cfg(test)]
237mod test {
238    use super::*;
239    use crate::{de::FogDeserializer, ser::FogSerializer};
240
241    #[test]
242    fn default_ser() {
243        // Should be an empty map if we use the defaults
244        let schema = TimeValidator::default();
245        let mut ser = FogSerializer::default();
246        schema.serialize(&mut ser).unwrap();
247        let expected: Vec<u8> = vec![0x80];
248        let actual = ser.finish();
249        println!("expected: {:x?}", expected);
250        println!("actual:   {:x?}", actual);
251        assert_eq!(expected, actual);
252
253        let mut de = FogDeserializer::new(&actual);
254        let decoded = TimeValidator::deserialize(&mut de).unwrap();
255        assert_eq!(schema, decoded);
256    }
257
258    #[test]
259    fn example_ser() {
260        let schema = TimeValidator {
261            comment: "The year 2020".to_string(),
262            min: Timestamp::from_utc(1577854800, 0).unwrap(),
263            max: Timestamp::from_utc(1609477200, 0).unwrap(),
264            ex_min: false,
265            ex_max: true,
266            in_list: Vec::new(),
267            nin_list: Vec::new(),
268            query: true,
269            ord: true,
270        };
271        let mut ser = FogSerializer::default();
272        schema.serialize(&mut ser).unwrap();
273        let mut expected: Vec<u8> = vec![0x86];
274        serialize_elem(&mut expected, Element::Str("comment"));
275        serialize_elem(&mut expected, Element::Str("The year 2020"));
276        serialize_elem(&mut expected, Element::Str("ex_max"));
277        serialize_elem(&mut expected, Element::Bool(true));
278        serialize_elem(&mut expected, Element::Str("max"));
279        serialize_elem(
280            &mut expected,
281            Element::Timestamp(Timestamp::from_utc(1609477200, 0).unwrap()),
282        );
283        serialize_elem(&mut expected, Element::Str("min"));
284        serialize_elem(
285            &mut expected,
286            Element::Timestamp(Timestamp::from_utc(1577854800, 0).unwrap()),
287        );
288        serialize_elem(&mut expected, Element::Str("ord"));
289        serialize_elem(&mut expected, Element::Bool(true));
290        serialize_elem(&mut expected, Element::Str("query"));
291        serialize_elem(&mut expected, Element::Bool(true));
292        let actual = ser.finish();
293        println!("expected: {:x?}", expected);
294        println!("actual:   {:x?}", actual);
295        assert_eq!(expected, actual);
296
297        let mut de = FogDeserializer::with_debug(&actual, "    ".to_string());
298        match TimeValidator::deserialize(&mut de) {
299            Ok(decoded) => assert_eq!(schema, decoded),
300            Err(e) => {
301                println!("{}", de.get_debug().unwrap());
302                println!("Error: {}", e);
303                panic!("Couldn't decode");
304            }
305        }
306    }
307}