1use crate::Error;
6use std::{
7 borrow::Borrow,
8 fmt,
9 str::FromStr,
10};
11
12
13
14#[derive(Debug, Clone, Copy, Eq, Hash, Ord, PartialEq, PartialOrd)]
15#[cfg_attr(feature = "serde", doc = include_str!("../skel/serde.txt"))]
55pub enum ComparisonOperator {
56 Ne,
58
59 Lt,
61
62 Le,
64
65 Eq,
67
68 Ge,
70
71 Gt,
73}
74
75impl AsRef<[u8]> for ComparisonOperator {
76 #[inline]
77 fn as_ref(&self) -> &[u8] { self.as_bytes() }
78}
79
80impl AsRef<str> for ComparisonOperator {
81 #[inline]
82 fn as_ref(&self) -> &str { self.as_str() }
83}
84
85impl Borrow<str> for ComparisonOperator {
86 #[inline]
87 fn borrow(&self) -> &str { self.as_str() }
88}
89
90impl fmt::Display for ComparisonOperator {
91 #[inline]
92 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
93 <str as fmt::Display>::fmt(self.as_str(), f)
94 }
95}
96
97#[cfg(feature = "serde")]
98#[cfg_attr(docsrs, doc(cfg(feature = "serde")))]
99impl<'de> ::serde_core::Deserialize<'de> for ComparisonOperator {
100 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
101 where D: ::serde_core::de::Deserializer<'de> {
102 struct Visitor;
104
105 impl ::serde_core::de::Visitor<'_> for Visitor {
106 type Value = ComparisonOperator;
107
108 #[inline]
109 fn expecting(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
110 f.write_str("string")
111 }
112
113 #[inline]
114 fn visit_str<S>(self, src: &str) -> Result<ComparisonOperator, S>
115 where S: ::serde_core::de::Error {
116 <ComparisonOperator>::try_from(src).map_err(::serde_core::de::Error::custom)
117 }
118
119 #[inline]
120 fn visit_bytes<S>(self, src: &[u8]) -> Result<ComparisonOperator, S>
121 where S: ::serde_core::de::Error {
122 <ComparisonOperator>::try_from(src).map_err(::serde_core::de::Error::custom)
123 }
124 }
125
126 deserializer.deserialize_str(Visitor)
127 }
128}
129
130impl FromStr for ComparisonOperator {
131 type Err = Error;
132
133 #[inline]
134 fn from_str(src: &str) -> Result<Self, Self::Err> {
135 Self::try_from(src.as_bytes())
136 }
137}
138
139impl PartialEq<str> for ComparisonOperator {
140 #[inline]
141 fn eq(&self, other: &str) -> bool { self.as_str() == other }
142}
143
144impl PartialEq<ComparisonOperator> for str {
145 #[inline]
146 fn eq(&self, other: &ComparisonOperator) -> bool { self == other.as_str() }
147}
148
149#[cfg(feature = "serde")]
150#[cfg_attr(docsrs, doc(cfg(feature = "serde")))]
151impl ::serde_core::Serialize for ComparisonOperator {
152 #[inline]
153 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
154 where S: ::serde_core::ser::Serializer { self.as_str().serialize(serializer) }
155}
156
157impl TryFrom<&[u8]> for ComparisonOperator {
158 type Error = Error;
159
160 #[inline]
161 fn try_from(src: &[u8]) -> Result<Self, Self::Error> {
162 match src.trim_ascii() {
163 b"!=" => Ok(Self::Ne),
164 b"<" => Ok(Self::Lt),
165 b"<=" => Ok(Self::Le),
166 b"==" | b"=" => Ok(Self::Eq),
167 b">=" => Ok(Self::Ge),
168 b">" => Ok(Self::Gt),
169 _ => Err(Error),
170 }
171 }
172}
173
174impl TryFrom<&str> for ComparisonOperator {
175 type Error = Error;
176
177 #[inline]
178 fn try_from(src: &str) -> Result<Self, Self::Error> { Self::try_from(src.as_bytes()) }
179}
180
181impl ComparisonOperator {
182 #[must_use]
183 pub const fn as_bytes(self) -> &'static [u8] {
195 match self {
196 Self::Lt => b"<",
197 Self::Le => b"<=",
198 Self::Eq => b"==",
199 Self::Ge => b">=",
200 Self::Gt => b">",
201 Self::Ne => b"!=",
202 }
203 }
204
205 #[must_use]
206 pub const fn as_str(self) -> &'static str {
218 match self {
219 Self::Lt => "<",
220 Self::Le => "<=",
221 Self::Eq => "==",
222 Self::Ge => ">=",
223 Self::Gt => ">",
224 Self::Ne => "!=",
225 }
226 }
227
228 #[must_use]
229 pub const fn is_empty(self) -> bool { false }
233
234 #[must_use]
235 pub const fn len(self) -> usize {
239 match self {
240 Self::Lt | Self::Gt => 1,
241 _ => 2,
242 }
243 }
244}
245
246macro_rules! is {
248 ($name:literal, $fn:ident, $ty:ident) => (
249 #[must_use]
250 #[doc = concat!("# Is ", $name, "?")]
251 #[doc = ""]
252 #[doc = concat!("Returns `true` for [`ComparisonOperator::", stringify!($ty), "`].")]
253 pub const fn $fn(self) -> bool { matches!(self, Self::$ty) }
254 );
255}
256
257impl ComparisonOperator {
258 is!("Not Equal", is_ne, Ne);
259 is!("Less Than", is_lt, Lt);
260 is!("Less Than/Equal To", is_le, Le);
261 is!("Equal", is_eq, Eq);
262 is!("Greater Than/Equal To", is_ge, Ge);
263 is!("Greater Than", is_gt, Gt);
264}
265
266impl ComparisonOperator {
267 pub fn compare<T: PartialOrd>(self, lhs: &T, rhs: &T) -> bool {
287 match self {
288 Self::Ne => lhs != rhs,
289 Self::Lt => lhs < rhs,
290 Self::Le => lhs <= rhs,
291 Self::Eq => lhs == rhs,
292 Self::Ge => lhs >= rhs,
293 Self::Gt => lhs > rhs,
294 }
295 }
296}
297
298
299
300#[cfg(test)]
301mod tests {
302 use super::*;
303 use serde as _; use serde_json as _;
305
306 #[test]
307 fn t_parse() {
308 macro_rules! test {
309 ($ty:ident, $val:literal) => (
310 assert_eq!(
312 Ok(ComparisonOperator::$ty),
313 ComparisonOperator::try_from($val)
314 );
315
316 assert_eq!(
318 Ok(ComparisonOperator::$ty),
319 ComparisonOperator::from_str($val)
320 );
321
322 assert_eq!(
324 Ok(ComparisonOperator::$ty),
325 ComparisonOperator::try_from($val.as_bytes())
326 );
327
328 assert_eq!(
330 Ok(ComparisonOperator::$ty),
331 ComparisonOperator::try_from(concat!(" ", $val, " "))
332 );
333 assert_eq!(
334 Ok(ComparisonOperator::$ty),
335 ComparisonOperator::try_from(concat!(" ", $val, " ").as_bytes())
336 );
337 )
338 }
339
340 test!(Ne, "!=");
341 test!(Lt, "<");
342 test!(Le, "<=");
343 test!(Eq, "==");
344 test!(Eq, "=");
345 test!(Ge, ">=");
346 test!(Gt, ">");
347 }
348
349 #[test]
350 fn t_as() {
351 for (op, v) in [
353 (ComparisonOperator::Ne, "!="),
354 (ComparisonOperator::Lt, "<"),
355 (ComparisonOperator::Le, "<="),
356 (ComparisonOperator::Eq, "=="),
357 (ComparisonOperator::Ge, ">="),
358 (ComparisonOperator::Gt, ">"),
359 ] {
360 assert_eq!(op.as_str(), v);
361 assert_eq!(op.as_bytes(), v.as_bytes());
362 assert_eq!(op.as_bytes().len(), op.len());
363 }
364 }
365
366 #[cfg(feature = "serde")]
367 #[test]
368 fn t_serde() {
369 for op in [
370 ComparisonOperator::Ne,
371 ComparisonOperator::Lt,
372 ComparisonOperator::Le,
373 ComparisonOperator::Eq,
374 ComparisonOperator::Ge,
375 ComparisonOperator::Gt,
376 ] {
377 let s = serde_json::to_string(&op).expect("Serialization failed.");
379 assert_eq!(s, format!("{:?}", op.as_str()));
380
381 let d: ComparisonOperator = serde_json::from_str(&s).expect("Deserialization failed.");
383 assert_eq!(op, d);
384 }
385 }
386
387 #[test]
388 fn t_compare() {
389 const SET: [u8; 7] = [0, 1, 2, 3, 4, 5, 6];
390
391 macro_rules! count {
392 ($op:ident, $lhs:literal) => (
393 SET.iter().filter(|v| ComparisonOperator::$op.compare(&$lhs, v)).count()
394 );
395 }
396
397 assert_eq!(count!(Ne, 3), 6);
399 assert_eq!(count!(Lt, 3), 3);
400 assert_eq!(count!(Le, 3), 4);
401 assert_eq!(count!(Eq, 3), 1);
402 assert_eq!(count!(Ge, 3), 4);
403 assert_eq!(count!(Gt, 3), 3);
404
405 assert_eq!(count!(Lt, 0), 6);
408 assert_eq!(count!(Le, 0), 7);
409 assert_eq!(count!(Ge, 6), 7);
410 assert_eq!(count!(Gt, 6), 6);
411 }
412}
413