eva_common/
logic.rs

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