libmagic_rs/evaluator/operators/
comparison.rs1use std::cmp::Ordering;
7
8use crate::parser::ast::Value;
9
10#[must_use]
29pub fn compare_values(left: &Value, right: &Value) -> Option<Ordering> {
30 match (left, right) {
31 (Value::Uint(a), Value::Uint(b)) => Some(a.cmp(b)),
32 (Value::Int(a), Value::Int(b)) => Some(a.cmp(b)),
33 (Value::Uint(a), Value::Int(b)) => Some(i128::from(*a).cmp(&i128::from(*b))),
34 (Value::Int(a), Value::Uint(b)) => Some(i128::from(*a).cmp(&i128::from(*b))),
35 (Value::Float(a), Value::Float(b)) => a.partial_cmp(b),
36 (Value::String(a), Value::String(b)) => Some(a.cmp(b)),
37 (Value::Bytes(a), Value::Bytes(b)) => Some(a.cmp(b)),
38 _ => None,
39 }
40}
41
42#[must_use]
55pub fn apply_less_than(left: &Value, right: &Value) -> bool {
56 compare_values(left, right) == Some(Ordering::Less)
57}
58
59#[must_use]
72pub fn apply_greater_than(left: &Value, right: &Value) -> bool {
73 compare_values(left, right) == Some(Ordering::Greater)
74}
75
76#[must_use]
89pub fn apply_less_equal(left: &Value, right: &Value) -> bool {
90 matches!(
91 compare_values(left, right),
92 Some(Ordering::Less | Ordering::Equal)
93 )
94}
95
96#[must_use]
109pub fn apply_greater_equal(left: &Value, right: &Value) -> bool {
110 matches!(
111 compare_values(left, right),
112 Some(Ordering::Greater | Ordering::Equal)
113 )
114}
115
116#[cfg(test)]
117mod tests {
118 use super::*;
119
120 #[test]
121 fn test_compare_values_ordering() {
122 use std::cmp::Ordering::*;
123
124 assert_eq!(
126 compare_values(&Value::Uint(5), &Value::Uint(10)),
127 Some(Less)
128 );
129 assert_eq!(
130 compare_values(&Value::Uint(10), &Value::Uint(10)),
131 Some(Equal)
132 );
133 assert_eq!(
134 compare_values(&Value::Uint(10), &Value::Uint(5)),
135 Some(Greater)
136 );
137 assert_eq!(
138 compare_values(&Value::Int(-10), &Value::Int(-5)),
139 Some(Less)
140 );
141 assert_eq!(
142 compare_values(&Value::Int(i64::MIN), &Value::Int(0)),
143 Some(Less)
144 );
145
146 assert_eq!(compare_values(&Value::Int(-1), &Value::Uint(0)), Some(Less));
148 assert_eq!(
149 compare_values(&Value::Uint(42), &Value::Int(42)),
150 Some(Equal)
151 );
152 assert_eq!(
153 compare_values(&Value::Uint(u64::MAX), &Value::Int(-1)),
154 Some(Greater)
155 );
156
157 assert_eq!(
159 compare_values(&Value::String("abc".into()), &Value::String("abd".into())),
160 Some(Less)
161 );
162 assert_eq!(
163 compare_values(&Value::String("abc".into()), &Value::String("abc".into())),
164 Some(Equal)
165 );
166
167 assert_eq!(
169 compare_values(&Value::Bytes(vec![1]), &Value::Bytes(vec![2])),
170 Some(Less)
171 );
172 assert_eq!(
173 compare_values(&Value::Bytes(vec![1]), &Value::Bytes(vec![1])),
174 Some(Equal)
175 );
176 assert_eq!(
177 compare_values(&Value::Bytes(vec![1]), &Value::Bytes(vec![1, 2])),
178 Some(Less)
179 );
180 assert_eq!(
181 compare_values(&Value::Bytes(vec![]), &Value::Bytes(vec![1])),
182 Some(Less)
183 );
184
185 assert_eq!(
187 compare_values(&Value::Uint(1), &Value::String("1".into())),
188 None
189 );
190 assert_eq!(compare_values(&Value::Int(1), &Value::Bytes(vec![1])), None);
191 }
192
193 #[test]
194 fn test_compare_values_float_ordering() {
195 use std::cmp::Ordering::*;
196
197 assert_eq!(
198 compare_values(&Value::Float(1.0), &Value::Float(2.0)),
199 Some(Less)
200 );
201 assert_eq!(
202 compare_values(&Value::Float(2.0), &Value::Float(2.0)),
203 Some(Equal)
204 );
205 assert_eq!(
206 compare_values(&Value::Float(3.0), &Value::Float(2.0)),
207 Some(Greater)
208 );
209 assert_eq!(
210 compare_values(&Value::Float(-1.0), &Value::Float(1.0)),
211 Some(Less)
212 );
213
214 assert_eq!(
216 compare_values(&Value::Float(1.0), &Value::Float(f64::INFINITY)),
217 Some(Less)
218 );
219 assert_eq!(
220 compare_values(&Value::Float(f64::NEG_INFINITY), &Value::Float(1.0)),
221 Some(Less)
222 );
223 assert_eq!(
224 compare_values(&Value::Float(f64::INFINITY), &Value::Float(f64::INFINITY)),
225 Some(Equal)
226 );
227
228 assert_eq!(
230 compare_values(&Value::Float(f64::NAN), &Value::Float(1.0)),
231 None
232 );
233 assert_eq!(
234 compare_values(&Value::Float(1.0), &Value::Float(f64::NAN)),
235 None
236 );
237 assert_eq!(
238 compare_values(&Value::Float(f64::NAN), &Value::Float(f64::NAN)),
239 None
240 );
241
242 assert_eq!(compare_values(&Value::Float(1.0), &Value::Uint(1)), None);
244 assert_eq!(compare_values(&Value::Int(1), &Value::Float(1.0)), None);
245 }
246
247 #[test]
248 fn test_comparison_operators_float() {
249 assert!(apply_less_than(&Value::Float(1.0), &Value::Float(2.0)));
251 assert!(!apply_less_than(&Value::Float(2.0), &Value::Float(2.0)));
252 assert!(apply_greater_than(&Value::Float(3.0), &Value::Float(2.0)));
253 assert!(!apply_greater_than(&Value::Float(2.0), &Value::Float(2.0)));
254 assert!(apply_less_equal(&Value::Float(2.0), &Value::Float(2.0)));
255 assert!(apply_less_equal(&Value::Float(1.0), &Value::Float(2.0)));
256 assert!(apply_greater_equal(&Value::Float(2.0), &Value::Float(2.0)));
257 assert!(apply_greater_equal(&Value::Float(3.0), &Value::Float(2.0)));
258
259 assert!(!apply_less_than(
261 &Value::Float(f64::NAN),
262 &Value::Float(1.0)
263 ));
264 assert!(!apply_greater_than(
265 &Value::Float(f64::NAN),
266 &Value::Float(1.0)
267 ));
268 assert!(!apply_less_equal(
269 &Value::Float(f64::NAN),
270 &Value::Float(1.0)
271 ));
272 assert!(!apply_greater_equal(
273 &Value::Float(f64::NAN),
274 &Value::Float(1.0)
275 ));
276 }
277
278 #[test]
279 fn test_comparison_operators_consistency() {
280 let pairs = vec![
282 (Value::Uint(5), Value::Uint(10)),
283 (Value::Uint(10), Value::Uint(10)),
284 (Value::Uint(10), Value::Uint(5)),
285 (Value::Int(-10), Value::Int(-5)),
286 (Value::Int(-1), Value::Uint(0)),
287 (Value::Uint(u64::MAX), Value::Int(-1)),
288 (Value::String("abc".into()), Value::String("abd".into())),
289 (Value::Bytes(vec![1, 2]), Value::Bytes(vec![1, 3])),
290 (Value::Bytes(vec![1]), Value::Bytes(vec![1, 2])),
291 (Value::Uint(1), Value::String("1".into())), ];
293
294 for (left, right) in &pairs {
295 let ord = compare_values(left, right);
296 assert_eq!(
297 apply_less_than(left, right),
298 ord == Some(Ordering::Less),
299 "< for {left:?}, {right:?}"
300 );
301 assert_eq!(
302 apply_greater_than(left, right),
303 ord == Some(Ordering::Greater),
304 "> for {left:?}, {right:?}"
305 );
306 assert_eq!(
307 apply_less_equal(left, right),
308 matches!(ord, Some(Ordering::Less | Ordering::Equal)),
309 "<= for {left:?}, {right:?}"
310 );
311 assert_eq!(
312 apply_greater_equal(left, right),
313 matches!(ord, Some(Ordering::Greater | Ordering::Equal)),
314 ">= for {left:?}, {right:?}"
315 );
316 }
317 }
318}