elasticsearch_dsl/search/params/
number.rs

1use std::cmp::Ordering;
2
3/// Numeric enum
4#[derive(Clone, Copy, Serialize, Deserialize, PartialEq, Eq, PartialOrd)]
5pub struct Number(N);
6
7#[derive(Clone, Copy, Serialize, Deserialize)]
8#[serde(untagged)]
9enum N {
10    /// Non-negative integers
11    Pos(u64),
12
13    /// Negative integers
14    Neg(i64),
15
16    /// 32-bit floats
17    F32(f32),
18
19    /// 64-bit floats
20    F64(f64),
21}
22
23impl std::fmt::Debug for Number {
24    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
25        match self.0 {
26            N::Pos(value) => value.fmt(f),
27            N::Neg(value) => value.fmt(f),
28            N::F32(value) => value.fmt(f),
29            N::F64(value) => value.fmt(f),
30        }
31    }
32}
33
34impl std::fmt::Display for Number {
35    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
36        match self.0 {
37            N::Pos(value) => value.fmt(f),
38            N::Neg(value) => value.fmt(f),
39            N::F32(value) => value.fmt(f),
40            N::F64(value) => value.fmt(f),
41        }
42    }
43}
44
45impl From<u8> for Number {
46    fn from(value: u8) -> Self {
47        Self(N::Pos(value as u64))
48    }
49}
50
51impl From<u16> for Number {
52    fn from(value: u16) -> Self {
53        Self(N::Pos(value as u64))
54    }
55}
56
57impl From<u32> for Number {
58    fn from(value: u32) -> Self {
59        Self(N::Pos(value as u64))
60    }
61}
62
63impl From<u64> for Number {
64    fn from(value: u64) -> Self {
65        Self(N::Pos(value))
66    }
67}
68
69impl From<i8> for Number {
70    fn from(value: i8) -> Self {
71        if value < 0 {
72            Self(N::Neg(value as i64))
73        } else {
74            Self(N::Pos(value as u64))
75        }
76    }
77}
78
79impl From<i16> for Number {
80    fn from(value: i16) -> Self {
81        if value < 0 {
82            Self(N::Neg(value as i64))
83        } else {
84            Self(N::Pos(value as u64))
85        }
86    }
87}
88
89impl From<i32> for Number {
90    fn from(value: i32) -> Self {
91        if value < 0 {
92            Self(N::Neg(value as i64))
93        } else {
94            Self(N::Pos(value as u64))
95        }
96    }
97}
98
99impl From<i64> for Number {
100    fn from(value: i64) -> Self {
101        if value < 0 {
102            Self(N::Neg(value))
103        } else {
104            Self(N::Pos(value as u64))
105        }
106    }
107}
108
109impl From<f32> for Number {
110    fn from(value: f32) -> Self {
111        Self(N::F32(value))
112    }
113}
114
115impl From<f64> for Number {
116    fn from(value: f64) -> Self {
117        Self(N::F64(value))
118    }
119}
120
121impl From<&u8> for Number {
122    fn from(value: &u8) -> Self {
123        Self(N::Pos(*value as u64))
124    }
125}
126
127impl From<&u16> for Number {
128    fn from(value: &u16) -> Self {
129        Self(N::Pos(*value as u64))
130    }
131}
132
133impl From<&u32> for Number {
134    fn from(value: &u32) -> Self {
135        Self(N::Pos(*value as u64))
136    }
137}
138
139impl From<&u64> for Number {
140    fn from(value: &u64) -> Self {
141        Self(N::Pos(*value))
142    }
143}
144
145impl From<&i8> for Number {
146    fn from(value: &i8) -> Self {
147        let value = *value;
148        if value < 0 {
149            Self(N::Neg(value as i64))
150        } else {
151            Self(N::Pos(value as u64))
152        }
153    }
154}
155
156impl From<&i16> for Number {
157    fn from(value: &i16) -> Self {
158        let value = *value;
159        if value < 0 {
160            Self(N::Neg(value as i64))
161        } else {
162            Self(N::Pos(value as u64))
163        }
164    }
165}
166
167impl From<&i32> for Number {
168    fn from(value: &i32) -> Self {
169        let value = *value;
170        if value < 0 {
171            Self(N::Neg(value as i64))
172        } else {
173            Self(N::Pos(value as u64))
174        }
175    }
176}
177
178impl From<&i64> for Number {
179    fn from(value: &i64) -> Self {
180        let value = *value;
181        if value < 0 {
182            Self(N::Neg(value))
183        } else {
184            Self(N::Pos(value as u64))
185        }
186    }
187}
188
189impl From<&f32> for Number {
190    fn from(value: &f32) -> Self {
191        Self(N::F32(*value))
192    }
193}
194
195impl From<&f64> for Number {
196    fn from(value: &f64) -> Self {
197        Self(N::F64(*value))
198    }
199}
200
201impl PartialEq for N {
202    fn eq(&self, other: &Self) -> bool {
203        match (self, other) {
204            // Positive
205            (N::Pos(value), N::Pos(other)) => value.eq(other),
206            (N::Pos(_), N::Neg(_)) => false,
207            (N::Pos(value), N::F32(other)) => (*value as f32).eq(other),
208            (N::Pos(value), N::F64(other)) => (*value as f64).eq(other),
209
210            // Negative
211            (N::Neg(_), N::Pos(_)) => false,
212            (N::Neg(value), N::Neg(other)) => value.eq(other),
213            (N::Neg(value), N::F32(other)) => (*value as f32).eq(other),
214            (N::Neg(value), N::F64(other)) => (*value as f64).eq(other),
215
216            // 32-bit floats
217            (N::F32(value), N::Pos(other)) => value.eq(&(*other as f32)),
218            (N::F32(value), N::Neg(other)) => value.eq(&(*other as f32)),
219            (N::F32(value), N::F32(other)) => value.eq(other),
220            (N::F32(value), N::F64(other)) => value.eq(&(*other as f32)),
221
222            // 64-bit floats
223            (N::F64(value), N::Pos(other)) => value.eq(&(*other as f64)),
224            (N::F64(value), N::Neg(other)) => value.eq(&(*other as f64)),
225            (N::F64(value), N::F32(other)) => (*value as f32).eq(other),
226            (N::F64(value), N::F64(other)) => value.eq(other),
227        }
228    }
229}
230
231impl Eq for N {}
232
233impl PartialOrd for N {
234    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
235        match (self, other) {
236            // Positive
237            (N::Pos(value), N::Pos(other)) => value.partial_cmp(other),
238            (N::Pos(_), N::Neg(_)) => Some(Ordering::Greater),
239            (N::Pos(value), N::F32(other)) => (*value as f32).partial_cmp(other),
240            (N::Pos(value), N::F64(other)) => (*value as f64).partial_cmp(other),
241
242            // Negative
243            (N::Neg(_), N::Pos(_)) => Some(Ordering::Less),
244            (N::Neg(value), N::Neg(other)) => value.partial_cmp(other),
245            (N::Neg(value), N::F32(other)) => (*value as f32).partial_cmp(other),
246            (N::Neg(value), N::F64(other)) => (*value as f64).partial_cmp(other),
247
248            // 32-bit floats
249            (N::F32(value), N::Pos(other)) => value.partial_cmp(&(*other as f32)),
250            (N::F32(value), N::Neg(other)) => value.partial_cmp(&(*other as f32)),
251            (N::F32(value), N::F32(other)) => value.partial_cmp(other),
252            (N::F32(value), N::F64(other)) => value.partial_cmp(&(*other as f32)),
253
254            // 64-bit floats
255            (N::F64(value), N::Pos(other)) => value.partial_cmp(&(*other as f64)),
256            (N::F64(value), N::Neg(other)) => value.partial_cmp(&(*other as f64)),
257            (N::F64(value), N::F32(other)) => (*value as f32).partial_cmp(other),
258            (N::F64(value), N::F64(other)) => value.partial_cmp(other),
259        }
260    }
261}
262
263#[cfg(test)]
264mod tests {
265    use super::*;
266    use crate::util::*;
267
268    #[test]
269    fn serialization() {
270        assert_serialize(
271            [
272                Number::from(2),
273                Number::from(-2),
274                Number::from(2.2f32),
275                Number::from(2.2f64),
276            ],
277            json!([2, -2, 2.2, 2.2]),
278        )
279    }
280
281    #[test]
282    fn partial_eq() {
283        assert_eq!(Number::from(2f32), Number::from(2));
284        assert_eq!(Number::from(2f64), Number::from(2));
285        assert_eq!(Number::from(2), Number::from(2));
286        assert_eq!(Number::from(-2), Number::from(-2));
287    }
288
289    #[test]
290    fn partial_ord() {
291        assert!(Number::from(2) > Number::from(1));
292        assert!(Number::from(2) > Number::from(-1));
293        assert!(Number::from(2) > Number::from(1f32));
294        assert!(Number::from(2) > Number::from(1f64));
295
296        assert!(Number::from(-2) < Number::from(1));
297        assert!(Number::from(-2) < Number::from(-1));
298        assert!(Number::from(-2) < Number::from(1f32));
299        assert!(Number::from(-2) < Number::from(1f64));
300
301        assert!(Number::from(2f32) > Number::from(1));
302        assert!(Number::from(2f32) > Number::from(-1));
303        assert!(Number::from(2f32) > Number::from(1f32));
304        assert!(Number::from(2f32) > Number::from(1f64));
305
306        assert!(Number::from(2f64) > Number::from(1));
307        assert!(Number::from(2f64) > Number::from(-1));
308        assert!(Number::from(2f64) > Number::from(1f32));
309        assert!(Number::from(2f64) > Number::from(1f64));
310    }
311}