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::String(a), Value::String(b)) => Some(a.cmp(b)),
36 (Value::Bytes(a), Value::Bytes(b)) => Some(a.cmp(b)),
37 _ => None,
38 }
39}
40
41#[must_use]
54pub fn apply_less_than(left: &Value, right: &Value) -> bool {
55 compare_values(left, right) == Some(Ordering::Less)
56}
57
58#[must_use]
71pub fn apply_greater_than(left: &Value, right: &Value) -> bool {
72 compare_values(left, right) == Some(Ordering::Greater)
73}
74
75#[must_use]
88pub fn apply_less_equal(left: &Value, right: &Value) -> bool {
89 matches!(
90 compare_values(left, right),
91 Some(Ordering::Less | Ordering::Equal)
92 )
93}
94
95#[must_use]
108pub fn apply_greater_equal(left: &Value, right: &Value) -> bool {
109 matches!(
110 compare_values(left, right),
111 Some(Ordering::Greater | Ordering::Equal)
112 )
113}
114
115#[cfg(test)]
116mod tests {
117 use super::*;
118
119 #[test]
120 fn test_compare_values_ordering() {
121 use std::cmp::Ordering::*;
122
123 assert_eq!(
125 compare_values(&Value::Uint(5), &Value::Uint(10)),
126 Some(Less)
127 );
128 assert_eq!(
129 compare_values(&Value::Uint(10), &Value::Uint(10)),
130 Some(Equal)
131 );
132 assert_eq!(
133 compare_values(&Value::Uint(10), &Value::Uint(5)),
134 Some(Greater)
135 );
136 assert_eq!(
137 compare_values(&Value::Int(-10), &Value::Int(-5)),
138 Some(Less)
139 );
140 assert_eq!(
141 compare_values(&Value::Int(i64::MIN), &Value::Int(0)),
142 Some(Less)
143 );
144
145 assert_eq!(compare_values(&Value::Int(-1), &Value::Uint(0)), Some(Less));
147 assert_eq!(
148 compare_values(&Value::Uint(42), &Value::Int(42)),
149 Some(Equal)
150 );
151 assert_eq!(
152 compare_values(&Value::Uint(u64::MAX), &Value::Int(-1)),
153 Some(Greater)
154 );
155
156 assert_eq!(
158 compare_values(&Value::String("abc".into()), &Value::String("abd".into())),
159 Some(Less)
160 );
161 assert_eq!(
162 compare_values(&Value::String("abc".into()), &Value::String("abc".into())),
163 Some(Equal)
164 );
165
166 assert_eq!(
168 compare_values(&Value::Bytes(vec![1]), &Value::Bytes(vec![2])),
169 Some(Less)
170 );
171 assert_eq!(
172 compare_values(&Value::Bytes(vec![1]), &Value::Bytes(vec![1])),
173 Some(Equal)
174 );
175 assert_eq!(
176 compare_values(&Value::Bytes(vec![1]), &Value::Bytes(vec![1, 2])),
177 Some(Less)
178 );
179 assert_eq!(
180 compare_values(&Value::Bytes(vec![]), &Value::Bytes(vec![1])),
181 Some(Less)
182 );
183
184 assert_eq!(
186 compare_values(&Value::Uint(1), &Value::String("1".into())),
187 None
188 );
189 assert_eq!(compare_values(&Value::Int(1), &Value::Bytes(vec![1])), None);
190 }
191
192 #[test]
193 fn test_comparison_operators_consistency() {
194 let pairs = vec![
196 (Value::Uint(5), Value::Uint(10)),
197 (Value::Uint(10), Value::Uint(10)),
198 (Value::Uint(10), Value::Uint(5)),
199 (Value::Int(-10), Value::Int(-5)),
200 (Value::Int(-1), Value::Uint(0)),
201 (Value::Uint(u64::MAX), Value::Int(-1)),
202 (Value::String("abc".into()), Value::String("abd".into())),
203 (Value::Bytes(vec![1, 2]), Value::Bytes(vec![1, 3])),
204 (Value::Bytes(vec![1]), Value::Bytes(vec![1, 2])),
205 (Value::Uint(1), Value::String("1".into())), ];
207
208 for (left, right) in &pairs {
209 let ord = compare_values(left, right);
210 assert_eq!(
211 apply_less_than(left, right),
212 ord == Some(Ordering::Less),
213 "< for {left:?}, {right:?}"
214 );
215 assert_eq!(
216 apply_greater_than(left, right),
217 ord == Some(Ordering::Greater),
218 "> for {left:?}, {right:?}"
219 );
220 assert_eq!(
221 apply_less_equal(left, right),
222 matches!(ord, Some(Ordering::Less | Ordering::Equal)),
223 "<= for {left:?}, {right:?}"
224 );
225 assert_eq!(
226 apply_greater_equal(left, right),
227 matches!(ord, Some(Ordering::Greater | Ordering::Equal)),
228 ">= for {left:?}, {right:?}"
229 );
230 }
231 }
232}