eva_common/
logic.rs

1use crate::Error;
2use crate::tools::default_true;
3use crate::value::Value;
4use serde::de::{self, MapAccess, Visitor};
5use serde::{Deserialize, Deserializer, Serialize};
6use std::fmt;
7use std::marker::PhantomData;
8use std::str::FromStr;
9
10const ERR_INVALID_RANGE_CONDITION: &str = "Invalid range condition";
11
12#[derive(Debug, Serialize, Deserialize, Copy, Clone, PartialEq)]
13#[serde(deny_unknown_fields)]
14pub struct Range {
15    #[serde(default)]
16    pub min: Option<f64>,
17    #[serde(default)]
18    pub max: Option<f64>,
19    #[serde(default = "default_true")]
20    pub min_eq: bool,
21    #[serde(default = "default_true")]
22    pub max_eq: bool,
23}
24
25impl Default for Range {
26    fn default() -> Self {
27        Self {
28            min: None,
29            max: None,
30            min_eq: true,
31            max_eq: true,
32        }
33    }
34}
35
36impl Range {
37    #[inline]
38    pub fn matches_any(&self) -> bool {
39        self.min.is_none() && self.max.is_none()
40    }
41    pub fn matches_value(&self, val: &Value) -> bool {
42        if let Ok(v) = TryInto::<f64>::try_into(val) {
43            self.matches(v)
44        } else {
45            false
46        }
47    }
48    pub fn matches(&self, val: f64) -> bool {
49        if let Some(min) = self.min
50            && ((self.min_eq && val < min) || (!self.min_eq && val <= min))
51        {
52            return false;
53        }
54        if let Some(max) = self.max
55            && ((self.max_eq && val > max) || (!self.max_eq && val >= max))
56        {
57            return false;
58        }
59        true
60    }
61    #[inline]
62    fn min_eq_sym(&self) -> &'static str {
63        if self.min_eq { "<=" } else { "<" }
64    }
65    #[inline]
66    fn max_eq_sym(&self) -> &'static str {
67        if self.max_eq { "<=" } else { "<" }
68    }
69}
70
71impl fmt::Display for Range {
72    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
73        if let Some(min) = self.min {
74            if let Some(max) = self.max {
75                if (min - max).abs() < f64::EPSILON && self.min_eq && self.max_eq {
76                    write!(f, "x = {}", min)
77                } else {
78                    write!(
79                        f,
80                        "{} {} x {} {}",
81                        min,
82                        self.min_eq_sym(),
83                        self.max_eq_sym(),
84                        max
85                    )
86                }
87            } else {
88                write!(f, "{} {} x", min, self.min_eq_sym())
89            }
90        } else if let Some(max) = self.max {
91            write!(f, "x {} {}", self.max_eq_sym(), max)
92        } else {
93            write!(f, "*")
94        }
95    }
96}
97
98impl FromStr for Range {
99    type Err = Error;
100
101    fn from_str(s: &str) -> Result<Self, Self::Err> {
102        let condition = s.trim();
103        if condition.is_empty() || condition == "*" || condition == "#" {
104            Ok(Range::default())
105        } else {
106            let mut r_inspected_min: Option<f64> = None;
107            let mut r_inspected_max: Option<f64> = None;
108            let mut r_inspected_min_eq = false;
109            let mut r_inspected_max_eq = false;
110            let c = condition
111                .replace(' ', "")
112                .replace(">=", "}")
113                .replace("=>", "}")
114                .replace("<=", "{")
115                .replace("=<", "{")
116                .replace("===", "=")
117                .replace("==", "=");
118            let vals = c
119                .split(&['<', '>', '}', '{', '='][..])
120                .collect::<Vec<&str>>();
121            if vals.len() > 3 {
122                return Err(Error::invalid_data(ERR_INVALID_RANGE_CONDITION));
123            }
124            if vals.len() > 1 {
125                for (i, v) in vals.iter().enumerate() {
126                    if *v == "x" || *v == "X" {
127                        if vals.len() == 2 {
128                            if i > 1 {
129                                return Err(Error::invalid_data(ERR_INVALID_RANGE_CONDITION));
130                            }
131                            let s = c
132                                .chars()
133                                .nth(vals[0].len())
134                                .ok_or_else(|| Error::invalid_data(ERR_INVALID_RANGE_CONDITION))?;
135                            if s == '=' {
136                                r_inspected_min = Some(vals[1 - i].parse()?);
137                                r_inspected_max = r_inspected_min;
138                                r_inspected_min_eq = true;
139                                r_inspected_max_eq = true;
140                            } else if ((s == '}' || s == '>') && i == 0)
141                                || ((s == '{' || s == '<') && i == 1)
142                            {
143                                r_inspected_min = Some(vals[1 - i].parse()?);
144                                r_inspected_min_eq = s == '}' || s == '{';
145                            } else if ((s == '}' || s == '>') && i == 1)
146                                || ((s == '{' || s == '<') && i == 0)
147                            {
148                                r_inspected_max = Some(vals[1 - i].parse()?);
149                                r_inspected_max_eq = s == '}' || s == '{';
150                            }
151                        } else if vals.len() == 3 {
152                            if i != 1 {
153                                return Err(Error::invalid_data(ERR_INVALID_RANGE_CONDITION));
154                            }
155                            let s1_ch = c.chars().nth(vals[0].len());
156                            let s2_ch = c.chars().nth(vals[0].len() + 2);
157                            if let Some(s1) = s1_ch
158                                && let Some(s2) = s2_ch
159                            {
160                                if s2 == '}' || s2 == '>' {
161                                    r_inspected_max = Some(vals[i - 1].parse()?);
162                                    r_inspected_max_eq = s1 == '}';
163                                    r_inspected_min = Some(vals[i + 1].parse()?);
164                                    r_inspected_min_eq = s2 == '}';
165                                } else if s2 == '{' || s2 == '<' {
166                                    r_inspected_min = Some(vals[i - 1].parse()?);
167                                    r_inspected_min_eq = s1 == '{';
168                                    r_inspected_max = Some(vals[i + 1].parse()?);
169                                    r_inspected_max_eq = s2 == '{';
170                                }
171                            }
172                            if r_inspected_max.unwrap() <= r_inspected_min.unwrap() {
173                                return Err(Error::invalid_data(ERR_INVALID_RANGE_CONDITION));
174                            }
175                        }
176                        break;
177                    }
178                }
179            } else {
180                return Err(Error::invalid_data(ERR_INVALID_RANGE_CONDITION));
181            }
182            Ok(Self {
183                min: r_inspected_min,
184                max: r_inspected_max,
185                min_eq: r_inspected_min_eq,
186                max_eq: r_inspected_max_eq,
187            })
188        }
189    }
190}
191
192pub fn de_range<'de, T, D>(deserializer: D) -> Result<T, D::Error>
193where
194    T: Deserialize<'de> + FromStr<Err = Error>,
195    D: Deserializer<'de>,
196{
197    struct StringOrStruct<T>(PhantomData<fn() -> T>);
198
199    impl<'de, T> Visitor<'de> for StringOrStruct<T>
200    where
201        T: Deserialize<'de> + FromStr<Err = Error>,
202    {
203        type Value = T;
204
205        fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
206            formatter.write_str("string or map")
207        }
208
209        fn visit_str<E>(self, value: &str) -> Result<T, E>
210        where
211            E: de::Error,
212        {
213            Ok(FromStr::from_str(value).unwrap())
214        }
215        fn visit_string<E>(self, value: String) -> Result<T, E>
216        where
217            E: de::Error,
218        {
219            Ok(FromStr::from_str(&value).unwrap())
220        }
221        fn visit_map<M>(self, map: M) -> Result<T, M::Error>
222        where
223            M: MapAccess<'de>,
224        {
225            Deserialize::deserialize(de::value::MapAccessDeserializer::new(map))
226        }
227    }
228
229    deserializer.deserialize_any(StringOrStruct(PhantomData))
230}
231
232pub fn de_opt_range<'de, T, D>(deserializer: D) -> Result<Option<T>, D::Error>
233where
234    T: Deserialize<'de> + FromStr<Err = Error>,
235    D: Deserializer<'de>,
236{
237    struct StringOrStruct<T>(PhantomData<fn() -> Option<T>>);
238
239    impl<'de, T> Visitor<'de> for StringOrStruct<T>
240    where
241        T: Deserialize<'de> + FromStr<Err = Error>,
242    {
243        type Value = Option<T>;
244
245        fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
246            formatter.write_str("string or map")
247        }
248
249        fn visit_unit<E>(self) -> Result<Option<T>, E>
250        where
251            E: de::Error,
252        {
253            Ok(None)
254        }
255        fn visit_str<E>(self, value: &str) -> Result<Option<T>, E>
256        where
257            E: de::Error,
258        {
259            Ok(Some(FromStr::from_str(value).unwrap()))
260        }
261        fn visit_string<E>(self, value: String) -> Result<Option<T>, E>
262        where
263            E: de::Error,
264        {
265            Ok(Some(FromStr::from_str(&value).unwrap()))
266        }
267        fn visit_map<M>(self, map: M) -> Result<Option<T>, M::Error>
268        where
269            M: MapAccess<'de>,
270        {
271            let res = Deserialize::deserialize(de::value::MapAccessDeserializer::new(map))?;
272            Ok(Some(res))
273        }
274    }
275
276    deserializer.deserialize_any(StringOrStruct(PhantomData))
277}
278
279#[cfg(test)]
280mod test {
281    use super::{Range, de_opt_range, de_range};
282    use serde::Deserialize;
283
284    #[test]
285    fn test_de() {
286        #[derive(Deserialize)]
287        struct TestR {
288            #[serde(deserialize_with = "de_range")]
289            range: Range,
290        }
291        let range = Range {
292            min: Some(20.0),
293            max: Some(100.0),
294            min_eq: true,
295            max_eq: false,
296        };
297        let rs = r#"{ "range": {"min": 20, "max": 100, "min_eq": true, "max_eq": false }}"#;
298        let rdes: TestR = serde_json::from_str(rs).unwrap();
299        assert_eq!(rdes.range, range);
300        let rs = r#"{ "range": "20 <=x < 100" }"#;
301        let rdes: TestR = serde_json::from_str(rs).unwrap();
302        assert_eq!(rdes.range, range);
303    }
304
305    #[test]
306    fn test_opt_de() {
307        #[derive(Deserialize)]
308        struct TestR {
309            #[serde(default, deserialize_with = "de_opt_range")]
310            range: Option<Range>,
311        }
312        let range = Range {
313            min: Some(20.0),
314            max: Some(100.0),
315            min_eq: true,
316            max_eq: false,
317        };
318        let rs = r#"{ "range": {"min": 20, "max": 100, "min_eq": true, "max_eq": false }}"#;
319        let rdes: TestR = serde_json::from_str(rs).unwrap();
320        assert_eq!(rdes.range.unwrap(), range);
321        let rs = r#"{ "range": "20 <=x < 100" }"#;
322        let rdes: TestR = serde_json::from_str(rs).unwrap();
323        assert_eq!(rdes.range.unwrap(), range);
324        let rs = r#"{ "range": null }"#;
325        let rdes: TestR = serde_json::from_str(rs).unwrap();
326        assert!(rdes.range.is_none());
327        let rs = r"{}";
328        let rdes: TestR = serde_json::from_str(rs).unwrap();
329        assert!(rdes.range.is_none());
330    }
331
332    #[test]
333    fn test_range() {
334        let r = Range::default();
335        let r2 = Range::default();
336        assert_eq!(r, r2);
337        assert!(r.matches(111.0));
338        assert_eq!(r.to_string(), "*");
339        assert_eq!(r, "*".parse().unwrap());
340        let mut r = Range {
341            min: Some(0.0),
342            max: None,
343            min_eq: true,
344            max_eq: false,
345        };
346        let r2 = r;
347        assert_eq!(r, r2);
348        assert!(r.matches(1.0));
349        assert!(r.matches(0.0));
350        assert!(!r.matches(-1.0));
351        assert_eq!(r.to_string(), "0 <= x");
352        assert_eq!(r, "0 <= x".parse().unwrap());
353        assert_eq!(r, "x >= 0".parse().unwrap());
354        assert_eq!(r, "x => 0".parse().unwrap());
355        r.min_eq = false;
356        assert!(r.matches(1.0));
357        assert!(!r.matches(0.0));
358        assert!(!r.matches(-1.0));
359        assert_eq!(r.to_string(), "0 < x");
360        assert_eq!(r, "0 < x".parse().unwrap());
361        assert_eq!(r, "x>0".parse().unwrap());
362        r.max = Some(100.0);
363        assert!(r.matches(1.0));
364        assert!(!r.matches(0.0));
365        assert!(!r.matches(-1.0));
366        assert!(r.matches(99.0));
367        assert!(!r.matches(100.0));
368        assert!(!r.matches(101.0));
369        assert_eq!(r.to_string(), "0 < x < 100");
370        assert_eq!(r, "0 < x < 100".parse().unwrap());
371        assert_eq!(r, "100>x > 0".parse().unwrap());
372        r.max_eq = true;
373        assert!(r.matches(1.0));
374        assert!(!r.matches(0.0));
375        assert!(!r.matches(-1.0));
376        assert!(r.matches(99.0));
377        assert!(r.matches(100.0));
378        assert!(!r.matches(101.0));
379        assert_eq!(r.to_string(), "0 < x <= 100");
380        assert_eq!(r, "0 < x <= 100".parse().unwrap());
381        assert_eq!(r, "100=>x > 0".parse().unwrap());
382        r.min_eq = true;
383        assert_eq!(r.to_string(), "0 <= x <= 100");
384        assert_eq!(r, "0 <= x <= 100".parse().unwrap());
385        assert_eq!(r, "100=>x=> 0".parse().unwrap());
386        let r = Range {
387            min: None,
388            max: Some(100.0),
389            min_eq: false,
390            max_eq: true,
391        };
392        assert!(r.matches(1.0));
393        assert!(r.matches(0.0));
394        assert!(r.matches(-1.0));
395        assert!(r.matches(99.0));
396        assert!(r.matches(100.0));
397        assert!(!r.matches(101.0));
398        assert_eq!(r.to_string(), "x <= 100");
399        assert_eq!(r, "x <= 100".parse().unwrap());
400        assert_eq!(r, "100>=x".parse().unwrap());
401    }
402}