tera/
filter_utils.rs

1use crate::errors::{Error, Result};
2use serde_json::Value;
3use std::cmp::Ordering;
4
5#[derive(PartialEq, Default, Copy, Clone)]
6pub struct OrderedF64(f64);
7
8impl OrderedF64 {
9    fn new(n: f64) -> Self {
10        OrderedF64(n)
11    }
12}
13
14impl Eq for OrderedF64 {}
15
16impl Ord for OrderedF64 {
17    fn cmp(&self, other: &OrderedF64) -> Ordering {
18        // unwrap is safe because self.0 is finite.
19        self.partial_cmp(other).unwrap()
20    }
21}
22
23impl PartialOrd for OrderedF64 {
24    fn partial_cmp(&self, other: &OrderedF64) -> Option<Ordering> {
25        Some(total_cmp(&self.0, &other.0))
26    }
27}
28
29/// Return the ordering between `self` and `other` f64.
30///
31/// https://doc.rust-lang.org/std/primitive.f64.html#method.total_cmp
32///
33/// Backported from Rust 1.62 to keep MSRV at 1.56
34///
35/// Unlike the standard partial comparison between floating point numbers,
36/// this comparison always produces an ordering in accordance to
37/// the `totalOrder` predicate as defined in the IEEE 754 (2008 revision)
38/// floating point standard. The values are ordered in the following sequence:
39///
40/// - negative quiet NaN
41/// - negative signaling NaN
42/// - negative infinity
43/// - negative numbers
44/// - negative subnormal numbers
45/// - negative zero
46/// - positive zero
47/// - positive subnormal numbers
48/// - positive numbers
49/// - positive infinity
50/// - positive signaling NaN
51/// - positive quiet NaN.
52///
53/// The ordering established by this function does not always agree with the
54/// [`PartialOrd`] and [`PartialEq`] implementations of `f64`. For example,
55/// they consider negative and positive zero equal, while `total_cmp`
56/// doesn't.
57///
58/// The interpretation of the signaling NaN bit follows the definition in
59/// the IEEE 754 standard, which may not match the interpretation by some of
60/// the older, non-conformant (e.g. MIPS) hardware implementations.
61///
62#[must_use]
63#[inline]
64fn total_cmp(a: &f64, b: &f64) -> Ordering {
65    let mut left = a.to_bits() as i64;
66    let mut right = b.to_bits() as i64;
67    left ^= (((left >> 63) as u64) >> 1) as i64;
68    right ^= (((right >> 63) as u64) >> 1) as i64;
69
70    left.cmp(&right)
71}
72
73#[derive(Default, Eq, PartialEq, Ord, PartialOrd, Copy, Clone)]
74pub struct ArrayLen(usize);
75
76pub trait GetValue: Ord + Sized + Clone {
77    fn get_value(val: &Value) -> Result<Self>;
78}
79
80impl GetValue for OrderedF64 {
81    fn get_value(val: &Value) -> Result<Self> {
82        let n = val.as_f64().ok_or_else(|| Error::msg(format!("expected number got {}", val)))?;
83        Ok(OrderedF64::new(n))
84    }
85}
86
87impl GetValue for i64 {
88    fn get_value(val: &Value) -> Result<Self> {
89        val.as_i64().ok_or_else(|| Error::msg(format!("expected number got {}", val)))
90    }
91}
92
93impl GetValue for bool {
94    fn get_value(val: &Value) -> Result<Self> {
95        val.as_bool().ok_or_else(|| Error::msg(format!("expected bool got {}", val)))
96    }
97}
98
99impl GetValue for String {
100    fn get_value(val: &Value) -> Result<Self> {
101        let str: Result<&str> =
102            val.as_str().ok_or_else(|| Error::msg(format!("expected string got {}", val)));
103        Ok(str?.to_owned())
104    }
105}
106
107impl GetValue for ArrayLen {
108    fn get_value(val: &Value) -> Result<Self> {
109        let arr =
110            val.as_array().ok_or_else(|| Error::msg(format!("expected array got {}", val)))?;
111        Ok(ArrayLen(arr.len()))
112    }
113}
114
115#[derive(Default)]
116pub struct SortPairs<K: Ord> {
117    pairs: Vec<(Value, K)>,
118}
119
120type SortNumbers = SortPairs<OrderedF64>;
121type SortBools = SortPairs<bool>;
122type SortStrings = SortPairs<String>;
123type SortArrays = SortPairs<ArrayLen>;
124
125impl<K: GetValue> SortPairs<K> {
126    fn try_add_pair(&mut self, val: &Value, key: &Value) -> Result<()> {
127        let key = K::get_value(key)?;
128        self.pairs.push((val.clone(), key));
129        Ok(())
130    }
131
132    fn sort(&mut self) -> Vec<Value> {
133        self.pairs.sort_by_key(|a| a.1.clone());
134        self.pairs.iter().map(|a| a.0.clone()).collect()
135    }
136}
137
138pub trait SortStrategy {
139    fn try_add_pair(&mut self, val: &Value, key: &Value) -> Result<()>;
140    fn sort(&mut self) -> Vec<Value>;
141}
142
143impl<K: GetValue> SortStrategy for SortPairs<K> {
144    fn try_add_pair(&mut self, val: &Value, key: &Value) -> Result<()> {
145        SortPairs::try_add_pair(self, val, key)
146    }
147
148    fn sort(&mut self) -> Vec<Value> {
149        SortPairs::sort(self)
150    }
151}
152
153pub fn get_sort_strategy_for_type(ty: &Value) -> Result<Box<dyn SortStrategy>> {
154    use crate::Value::*;
155    match *ty {
156        Null => Err(Error::msg("Null is not a sortable value")),
157        Bool(_) => Ok(Box::<SortBools>::default()),
158        Number(_) => Ok(Box::<SortNumbers>::default()),
159        String(_) => Ok(Box::<SortStrings>::default()),
160        Array(_) => Ok(Box::<SortArrays>::default()),
161        Object(_) => Err(Error::msg("Object is not a sortable value")),
162    }
163}
164
165#[derive(Default)]
166pub struct Unique<K: Eq + std::hash::Hash> {
167    unique: std::collections::HashSet<K>,
168}
169
170type UniqueNumbers = Unique<i64>;
171type UniqueBools = Unique<bool>;
172struct UniqueStrings {
173    u: Unique<String>,
174    case_sensitive: bool,
175}
176
177pub trait UniqueStrategy {
178    fn insert(&mut self, val: &Value) -> Result<bool>;
179}
180
181impl<K: GetValue + Eq + std::hash::Hash> UniqueStrategy for Unique<K> {
182    fn insert(&mut self, val: &Value) -> Result<bool> {
183        Ok(self.unique.insert(K::get_value(val)?))
184    }
185}
186
187impl UniqueStrings {
188    fn new(case_sensitive: bool) -> UniqueStrings {
189        UniqueStrings { u: Unique::<String>::default(), case_sensitive }
190    }
191}
192
193impl UniqueStrategy for UniqueStrings {
194    fn insert(&mut self, val: &Value) -> Result<bool> {
195        let mut key = String::get_value(val)?;
196        if !self.case_sensitive {
197            key = key.to_lowercase()
198        }
199        Ok(self.u.unique.insert(key))
200    }
201}
202
203pub fn get_unique_strategy_for_type(
204    ty: &Value,
205    case_sensitive: bool,
206) -> Result<Box<dyn UniqueStrategy>> {
207    use crate::Value::*;
208    match *ty {
209        Null => Err(Error::msg("Null is not a unique value")),
210        Bool(_) => Ok(Box::<UniqueBools>::default()),
211        Number(ref val) => {
212            if val.is_f64() {
213                Err(Error::msg("Unique floats are not implemented"))
214            } else {
215                Ok(Box::<UniqueNumbers>::default())
216            }
217        }
218        String(_) => Ok(Box::new(UniqueStrings::new(case_sensitive))),
219        Array(_) => Err(Error::msg("Unique arrays are not implemented")),
220        Object(_) => Err(Error::msg("Unique objects are not implemented")),
221    }
222}