1use crate::pred::cmp::parser::{OpParser, OpParserError};
20use crate::pred::cmp::{Comparison, Operator, Symbol};
21use std::fmt::Display;
22use std::str::FromStr;
23
24#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
25pub struct FieldComparison<K, V, S = Symbol> {
26 key: K,
27 inner: Comparison<V, S>,
28}
29
30impl<K, V, S> FieldComparison<K, V, S>
31where
32 V: PartialOrd,
33{
34 pub fn test(&self, value: V) -> bool {
35 self.inner.test(value)
36 }
37}
38
39impl<K, V, S> FieldComparison<K, V, S> {
40 pub fn new(key: K, operator: Operator, value: V) -> Self {
41 Self {
42 key,
43 inner: Comparison::new(operator, value),
44 }
45 }
46
47 fn new_with_inner(key: K, inner: Comparison<V, S>) -> Self {
48 Self { key, inner }
49 }
50
51 pub fn key(&self) -> &K {
52 &self.key
53 }
54
55 pub fn operator(&self) -> Operator {
56 self.inner.operator()
57 }
58
59 pub fn value(&self) -> &V {
60 self.inner.value()
61 }
62
63 pub fn into_inner(self) -> (K, Comparison<V, S>) {
64 (self.key, self.inner)
65 }
66}
67
68impl<K, V> FromStr for FieldComparison<K, V, Symbol>
69where
70 K: FromStr,
71 V: FromStr,
72 <K as FromStr>::Err: Display,
73 <V as FromStr>::Err: Display,
74 Comparison<V, Symbol>: FromStr<Err = String>,
75{
76 type Err = String;
77
78 fn from_str(s: &str) -> Result<Self, Self::Err> {
79 match OpParser::simple_op_parser(s) {
87 Ok((op, text)) => {
88 let op = match op {
89 Operator::Ne => "≠",
90 Operator::Eq => "=",
91 Operator::Gt => ">",
92 Operator::Lt => "<",
93 Operator::Gte => ">=",
94 Operator::Lte => "<=",
95 };
96
97 Err(format!(
98 "missing key in expression `{s}`, should be in the form `key{op}{text}`"
99 ))
100 }
101 Err(OpParserError::InvalidCharsBeforeOp {
102 text_before_op,
103 op_index: before_op_index,
104 ..
105 }) => {
106 let key = text_before_op
107 .trim_end_matches(' ')
108 .parse::<K>()
109 .map_err(|e| e.to_string())?;
110
111 let text_after = &s[before_op_index..];
112 let inner = text_after.parse::<Comparison<V, Symbol>>()?;
113 Ok(Self::new_with_inner(key, inner))
114 }
115 Err(OpParserError::Other(s)) => Err(s),
116 }
117 }
118}
119
120#[cfg(test)]
121mod tests {
122 use crate::pred::field_cmp::FieldComparison;
123 use crate::pred::Operator;
124
125 macro_rules! test_cases {
126 (
127 key_type = $key_type:ty;
128 value_type = $value_type:ty;
129 $($operator:expr => [$($input:literal),+] = ($expected_key:literal, $expected_value:literal),)+
130 ) => {$($(
131 {
132 let input = $input;
133 let pred = input.parse::<FieldComparison<$key_type, $value_type>>().unwrap();
134 assert_eq!(pred.key(), &$expected_key, "input: {input}");
135 assert_eq!(pred.operator(), $operator, "input: {input}");
136 assert_eq!(pred.value(), &$expected_value, "input: {input}");
137 }
138 )+)+};
139 }
140
141 #[test]
142 fn test_field_comparison() {
143 test_cases!(
144 key_type = String;
145 value_type = usize;
146 Operator::Eq => ["size=1024", "size =1024", "size = 1024"] = ("size", 1024),
147 Operator::Ne => ["size≠1024", "size ≠ 1024", "size!1024", "size ! 1024"] = ("size", 1024),
148 Operator::Gt => ["size>1024", "size >1024", "size >1024"] = ("size", 1024),
149 Operator::Gte => ["size>=1024", "size >=1024", "size >= 1024"] = ("size", 1024),
150 Operator::Lt => ["size<1024", "size <1024", "size <1024"] = ("size", 1024),
151 Operator::Lte => ["size<=1024", "size <=1024", "size <= 1024"] = ("size", 1024),
152 );
153 }
154
155 #[test]
157 fn test_case_in_comment() {
158 let field_comparison = "size1024".parse::<FieldComparison<String, usize>>();
159 assert_eq!(
160 field_comparison,
161 Err(String::from(
162 "missing key in expression `size1024`, should be in the form `key=size1024`"
163 ))
164 );
165 }
166}