fog_pack/validator/
bin.rs

1use super::*;
2use crate::element::*;
3use crate::error::{Error, Result};
4use serde::{Deserialize, Serialize};
5use serde_bytes::ByteBuf;
6use std::default::Default;
7
8#[inline]
9fn is_false(v: &bool) -> bool {
10    !v
11}
12
13#[inline]
14fn bytes_empty(v: &ByteBuf) -> bool {
15    v.is_empty()
16}
17
18#[inline]
19fn u32_is_zero(v: &u32) -> bool {
20    *v == 0
21}
22
23#[inline]
24fn u32_is_max(v: &u32) -> bool {
25    *v == u32::MAX
26}
27
28/// Validator for byte sequences.
29///
30/// This validator type will only pass binary values (a sequence of bytes). A binary sequence can
31/// also be treated as a little-endian arbitrary-length unsigned integer. Validation passes if:
32///
33/// - The bits set in `bits_clr` are cleared in the byte sequence.
34/// - The bits set in `bits_set` are set in the byte sequence.
35/// - If `max` has 1 or more bytes, the value is less than the maximum in `max`, or equal to it if
36///     `ex_max` is not set to true.
37/// - The value is greater than the minimum in `min`, or equal to it if `ex_min` is not set to true.
38/// - The value's length in bytes is less than or equal to the value in `max_len`.
39/// - The value's length in bytes is greater than or equal to the value in `min_len`.
40/// - If the `in` list is not empty, the value must be among the values in the list.
41/// - The value must not be among the values in the `nin` list.
42///
43/// # Defaults
44///
45/// Fields that aren't specified for the validator use their defaults instead. The defaults for
46/// each field are:
47///
48/// - comment: ""
49/// - bits_clr: empty
50/// - bits_set: empty
51/// - max: empty
52/// - min: empty
53/// - ex_max: false
54/// - ex_min: false
55/// - max_len: u32::MAX
56/// - min_len: 0
57/// - in_list: empty
58/// - nin_list: empty
59/// - query: false
60/// - bit: false
61/// - ord: false
62/// - size: false
63///
64#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
65#[serde(deny_unknown_fields, default)]
66pub struct BinValidator {
67    /// An optional comment explaining the validator.
68    #[serde(skip_serializing_if = "String::is_empty")]
69    pub comment: String,
70    /// A byte sequence used as a bit field. Any bits set in it must be cleared in an allowed
71    /// value.
72    #[serde(skip_serializing_if = "bytes_empty")]
73    pub bits_clr: ByteBuf,
74    /// A byte sequence used as a bit field. Any bits set in it must be set in an allowed
75    /// value.
76    #[serde(skip_serializing_if = "bytes_empty")]
77    pub bits_set: ByteBuf,
78    /// The maximum allowed value, as a little-endian arbitrary-length unsigned integer. If no
79    /// bytes are present, there is no maximum.
80    #[serde(skip_serializing_if = "bytes_empty")]
81    pub max: ByteBuf,
82    /// The minimum allowed value, as a little-endian arbitrary-length unsigned integer.
83    #[serde(skip_serializing_if = "bytes_empty")]
84    pub min: ByteBuf,
85    /// Changes `max` into an exclusive maximum.
86    #[serde(skip_serializing_if = "is_false")]
87    pub ex_max: bool,
88    /// Changes `min` into an exclusive maximum.
89    #[serde(skip_serializing_if = "is_false")]
90    pub ex_min: bool,
91    /// Set the maximum allowed number of bytes.
92    #[serde(skip_serializing_if = "u32_is_max")]
93    pub max_len: u32,
94    /// Set the minimum allowed number of bytes.
95    #[serde(skip_serializing_if = "u32_is_zero")]
96    pub min_len: u32,
97    /// A vector of specific allowed values, stored under the `in` field. If empty, this vector is not checked against.
98    #[serde(rename = "in", skip_serializing_if = "Vec::is_empty")]
99    pub in_list: Vec<ByteBuf>,
100    /// A vector of specific unallowed values, stored under the `nin` field.
101    #[serde(rename = "nin", skip_serializing_if = "Vec::is_empty")]
102    pub nin_list: Vec<ByteBuf>,
103    /// If true, queries against matching spots may have values in the `in` or `nin` lists.
104    #[serde(skip_serializing_if = "is_false")]
105    pub query: bool,
106    /// If true, queries against matching spots may set the `bits_clr` and `bits_set` values to be
107    /// non-zero.
108    #[serde(skip_serializing_if = "is_false")]
109    pub bit: bool,
110    /// If true, queries against matching spots may set the `max`, `min`, `ex_max`, and `ex_min`
111    /// values to non-defaults.
112    #[serde(skip_serializing_if = "is_false")]
113    pub ord: bool,
114    /// If true, queries against matching spots may set the `min_len` and `max_len` values to
115    /// non-defaults.
116    #[serde(skip_serializing_if = "is_false")]
117    pub size: bool,
118}
119
120impl Default for BinValidator {
121    fn default() -> Self {
122        Self {
123            comment: String::new(),
124            bits_clr: ByteBuf::new(),
125            bits_set: ByteBuf::new(),
126            ex_max: false,
127            ex_min: false,
128            max: ByteBuf::new(),
129            min: ByteBuf::new(),
130            max_len: u32::MAX,
131            min_len: u32::MIN,
132            in_list: Vec::new(),
133            nin_list: Vec::new(),
134            query: false,
135            bit: false,
136            ord: false,
137            size: false,
138        }
139    }
140}
141
142impl BinValidator {
143    /// Make a new validator with the default configuration.
144    pub fn new() -> Self {
145        Self::default()
146    }
147
148    /// Set a comment for the validator.
149    pub fn comment(mut self, comment: impl Into<String>) -> Self {
150        self.comment = comment.into();
151        self
152    }
153
154    /// Choose which bits must be set.
155    pub fn bits_set(mut self, bits_set: impl Into<Vec<u8>>) -> Self {
156        self.bits_set = ByteBuf::from(bits_set);
157        self
158    }
159
160    /// Choose which bits must be cleared.
161    pub fn bits_clr(mut self, bits_clr: impl Into<Vec<u8>>) -> Self {
162        self.bits_clr = ByteBuf::from(bits_clr);
163        self
164    }
165
166    /// Set the maximum allowed value.
167    pub fn max(mut self, max: impl Into<Vec<u8>>) -> Self {
168        self.max = ByteBuf::from(max);
169        self
170    }
171
172    /// Set the minimum allowed value.
173    pub fn min(mut self, min: impl Into<Vec<u8>>) -> Self {
174        self.min = ByteBuf::from(min);
175        self
176    }
177
178    /// Set whether or or not `max` is an exclusive maximum.
179    pub fn ex_max(mut self, ex_max: bool) -> Self {
180        self.ex_max = ex_max;
181        self
182    }
183
184    /// Set whether or or not `min` is an exclusive maximum.
185    pub fn ex_min(mut self, ex_min: bool) -> Self {
186        self.ex_min = ex_min;
187        self
188    }
189
190    /// Set the maximum number of allowed bytes.
191    pub fn max_len(mut self, max_len: u32) -> Self {
192        self.max_len = max_len;
193        self
194    }
195
196    /// Set the minimum number of allowed bytes.
197    pub fn min_len(mut self, min_len: u32) -> Self {
198        self.min_len = min_len;
199        self
200    }
201
202    /// Add a value to the `in` list.
203    pub fn in_add(mut self, add: impl Into<Vec<u8>>) -> Self {
204        self.in_list.push(ByteBuf::from(add));
205        self
206    }
207
208    /// Add a value to the `nin` list.
209    pub fn nin_add(mut self, add: impl Into<Vec<u8>>) -> Self {
210        self.nin_list.push(ByteBuf::from(add));
211        self
212    }
213
214    /// Set whether or not queries can use the `in` and `nin` lists.
215    pub fn query(mut self, query: bool) -> Self {
216        self.query = query;
217        self
218    }
219
220    /// Set whether or not queries can use the `bits_clr` and `bits_set` values.
221    pub fn bit(mut self, bit: bool) -> Self {
222        self.bit = bit;
223        self
224    }
225
226    /// Set whether or not queries can use the `max`, `min`, `ex_max`, and `ex_min` values.
227    pub fn ord(mut self, ord: bool) -> Self {
228        self.ord = ord;
229        self
230    }
231
232    /// Set whether or not queries can use the `max_len` and `min_len` values.
233    pub fn size(mut self, size: bool) -> Self {
234        self.size = size;
235        self
236    }
237
238    /// Build this into a [`Validator`] enum.
239    pub fn build(self) -> Validator {
240        Validator::Bin(Box::new(self))
241    }
242
243    pub(crate) fn validate(&self, parser: &mut Parser) -> Result<()> {
244        use std::iter::repeat;
245
246        // Get element
247        let elem = parser
248            .next()
249            .ok_or_else(|| Error::FailValidate("expected binary data".to_string()))??;
250        let val = if let Element::Bin(v) = elem {
251            v
252        } else {
253            return Err(Error::FailValidate(format!(
254                "expected Bin, got {}",
255                elem.name()
256            )));
257        };
258
259        // Length checks
260        if (val.len() as u32) > self.max_len {
261            return Err(Error::FailValidate(
262                "Bin is longer than max_len".to_string(),
263            ));
264        }
265        if (val.len() as u32) < self.min_len {
266            return Err(Error::FailValidate(
267                "Bin is shorter than min_len".to_string(),
268            ));
269        }
270
271        // Bit checks
272        if self
273            .bits_set
274            .iter()
275            .zip(val.iter().chain(repeat(&0u8)))
276            .any(|(bit, val)| (bit & val) != *bit)
277        {
278            return Err(Error::FailValidate(
279                "Bin does not have all required bits set".to_string(),
280            ));
281        }
282        if self
283            .bits_clr
284            .iter()
285            .zip(val.iter().chain(repeat(&0u8)))
286            .any(|(bit, val)| (bit & val) != 0)
287        {
288            return Err(Error::FailValidate(
289                "Bin does not have all required bits cleared".to_string(),
290            ));
291        }
292
293        // Assist functions for comparison
294        use std::cmp::Ordering;
295        fn compare(lhs: &[u8], rhs: &[u8]) -> Ordering {
296            match lhs.len().cmp(&rhs.len()) {
297                Ordering::Equal => Iterator::cmp(lhs.iter().rev(), rhs.iter().rev()),
298                other => other,
299            }
300        }
301        fn trim(val: &[u8]) -> &[u8] {
302            let trim_amount = val.iter().rev().take_while(|v| **v == 0).count();
303            &val[0..(val.len() - trim_amount)]
304        }
305
306        // Range checks
307        if !self.max.is_empty() || !self.min.is_empty() || self.ex_min {
308            let trimmed_val = trim(val);
309            let max_pass = match (self.max.is_empty(), self.ex_max) {
310                (true, _) => true,
311                (false, true) => compare(trimmed_val, trim(&self.max)) == Ordering::Less,
312                (false, false) => compare(trimmed_val, trim(&self.max)) != Ordering::Greater,
313            };
314
315            let min_pass = match (self.min.is_empty(), self.ex_min) {
316                (true, true) => !trimmed_val.is_empty(), // at least zero
317                (true, false) => true,                   // Can be anything, 0 on up
318                (false, true) => compare(trimmed_val, trim(&self.min)) == Ordering::Greater,
319                (false, false) => compare(trimmed_val, trim(&self.min)) != Ordering::Less,
320            };
321
322            if !max_pass {
323                return Err(Error::FailValidate(
324                    "Bin greater than maximum allowed".to_string(),
325                ));
326            }
327            if !min_pass {
328                return Err(Error::FailValidate(
329                    "Bin less than minimum allowed".to_string(),
330                ));
331            }
332        }
333
334        // in/nin checks
335        if !self.in_list.is_empty() && !self.in_list.iter().any(|v| *v == val) {
336            return Err(Error::FailValidate("Bin is not on `in` list".to_string()));
337        }
338        if self.nin_list.iter().any(|v| *v == val) {
339            return Err(Error::FailValidate("Bin is on `nin` list".to_string()));
340        }
341
342        Ok(())
343    }
344
345    fn query_check_self(&self, other: &Self) -> bool {
346        (self.query || (other.in_list.is_empty() && other.nin_list.is_empty()))
347            && (self.bit || (other.bits_set.is_empty() && other.bits_clr.is_empty()))
348            && (self.ord
349                || (!other.ex_min && !other.ex_max && other.min.is_empty() && other.max.is_empty()))
350            && (self.size || (u32_is_max(&other.max_len) && u32_is_zero(&other.min_len)))
351    }
352
353    pub(crate) fn query_check(&self, other: &Validator) -> bool {
354        match other {
355            Validator::Bin(other) => self.query_check_self(other),
356            Validator::Multi(list) => list.iter().all(|other| match other {
357                Validator::Bin(other) => self.query_check_self(other),
358                _ => false,
359            }),
360            Validator::Any => true,
361            _ => false,
362        }
363    }
364}