1use crate::Error;
2use regex::Regex;
3use serde::de::Error as DeError;
4use serde::{Deserialize, Deserializer, Serialize, Serializer};
5use std::fmt::{Display, Formatter, Write};
6use std::str::FromStr;
7use std::sync::Arc;
8
9#[derive(Debug, Clone)]
10pub enum Expression {
11 Equals(Value),
12 NotEquals(Value),
13 StartsWith(Value),
14 NotStartsWith(Value),
15 EndsWith(Value),
16 NotEndsWith(Value),
17 Contains(Value),
18 NotContains(Value),
19 Exists,
20 NotExists,
21 Regex(Regex),
22}
23
24impl Expression {
25 pub fn equals(value: impl AsRef<str>, sensitive: bool) -> Self {
26 Expression::Equals(Value::new(value, sensitive))
27 }
28
29 pub fn not_equals(value: impl AsRef<str>, sensitive: bool) -> Self {
30 Expression::NotEquals(Value::new(value, sensitive))
31 }
32
33 pub fn starts_with(value: impl AsRef<str>, sensitive: bool) -> Self {
34 Expression::StartsWith(Value::new(value, sensitive))
35 }
36
37 pub fn not_starts_with(value: impl AsRef<str>, sensitive: bool) -> Self {
38 Expression::NotStartsWith(Value::new(value, sensitive))
39 }
40
41 pub fn ends_with(value: impl AsRef<str>, sensitive: bool) -> Self {
42 Expression::EndsWith(Value::new(value, sensitive))
43 }
44
45 pub fn not_ends_with(value: impl AsRef<str>, sensitive: bool) -> Self {
46 Expression::NotEndsWith(Value::new(value, sensitive))
47 }
48
49 pub fn contains(value: impl AsRef<str>, sensitive: bool) -> Self {
50 Expression::Contains(Value::new(value, sensitive))
51 }
52
53 pub fn not_contains(value: impl AsRef<str>, sensitive: bool) -> Self {
54 Expression::NotContains(Value::new(value, sensitive))
55 }
56
57 pub fn regex(value: impl AsRef<str>) -> Result<Self, Error> {
58 Regex::from_str(value.as_ref())
59 .map(Expression::Regex)
60 .map_err(Error::new)
61 }
62
63 pub fn exists() -> Self {
64 Self::Exists
65 }
66
67 pub fn not_exists() -> Self {
68 Self::NotExists
69 }
70
71 pub fn matches(&self, text: Option<&str>) -> bool {
72 match self {
73 Expression::Equals(value) => value.equals(text),
74 Expression::NotEquals(value) => value.not_equals(text),
75 Expression::StartsWith(value) => value.starts_with(text),
76 Expression::NotStartsWith(value) => value.not_starts_with(text),
77 Expression::EndsWith(value) => value.ends_with(text),
78 Expression::NotEndsWith(value) => value.not_ends_with(text),
79 Expression::Contains(value) => value.contains(text),
80 Expression::NotContains(value) => value.not_contains(text),
81 Expression::Exists => text.is_some(),
82 Expression::NotExists => text.is_none(),
83 Expression::Regex(regex) => match text {
84 Some(text) => regex.is_match(text),
85 None => false,
86 },
87 }
88 }
89}
90
91impl Display for Expression {
92 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
93 match self {
94 Expression::Equals(value) => {
95 f.write_str("Equals")?;
96 <Value as Display>::fmt(value, f)
97 }
98 Expression::NotEquals(value) => {
99 f.write_str("NotEquals")?;
100 <Value as Display>::fmt(value, f)
101 }
102 Expression::StartsWith(value) => {
103 f.write_str("StartsWith")?;
104 <Value as Display>::fmt(value, f)
105 }
106 Expression::NotStartsWith(value) => {
107 f.write_str("NotStartWith")?;
108 <Value as Display>::fmt(value, f)
109 }
110 Expression::EndsWith(value) => {
111 f.write_str("EndsWith")?;
112 <Value as Display>::fmt(value, f)
113 }
114 Expression::NotEndsWith(value) => {
115 f.write_str("NotEndsWith")?;
116 <Value as Display>::fmt(value, f)
117 }
118 Expression::Contains(value) => {
119 f.write_str("Contains")?;
120 <Value as Display>::fmt(value, f)
121 }
122 Expression::NotContains(value) => {
123 f.write_str("NotContains")?;
124 <Value as Display>::fmt(value, f)
125 }
126 Expression::Exists => f.write_str("Exists"),
127 Expression::NotExists => f.write_str("NotExists"),
128 Expression::Regex(regex) => f.write_str(regex.as_str()),
129 }
130 }
131}
132
133impl FromStr for Expression {
134 type Err = Error;
135
136 fn from_str(value: &str) -> Result<Self, Self::Err> {
137 let value = value.trim();
138 match value {
139 "Exists" => Ok(Expression::Exists),
140 "NotExists" => Ok(Expression::NotExists),
141 _ => match value.find('(').zip(value.rfind(')')) {
142 Some((open, close)) => {
143 let r#type = value[..open].trim();
144 let value = &value[open + 1..close];
145 match r#type {
146 "Equals" => Ok(Expression::equals(value, true)),
147 "?Equals" => Ok(Expression::equals(value, false)),
148 "NotEquals" => Ok(Expression::not_equals(value, true)),
149 "?NotEquals" => Ok(Expression::not_equals(value, false)),
150 "StartsWith" => Ok(Expression::starts_with(value, true)),
151 "?StartsWith" => Ok(Expression::starts_with(value, false)),
152 "NotStartsWith" => Ok(Expression::not_starts_with(value, true)),
153 "?NotStartsWith" => Ok(Expression::not_starts_with(value, false)),
154 "EndsWith" => Ok(Expression::ends_with(value, true)),
155 "?EndsWith" => Ok(Expression::ends_with(value, false)),
156 "NotEndsWith" => Ok(Expression::not_ends_with(value, true)),
157 "?NotEndsWith" => Ok(Expression::not_ends_with(value, false)),
158 "Contains" => Ok(Expression::contains(value, true)),
159 "?Contains" => Ok(Expression::contains(value, false)),
160 "NotContains" => Ok(Expression::not_contains(value, true)),
161 "?NotContains" => Ok(Expression::not_contains(value, false)),
162 "Regex" => Expression::regex(value),
163 _ => Err(Error::new(format!("invalid expression type: {}", r#type))),
164 }
165 }
166 None => Err(Error::new(format!("invalid expression: {}", value))),
167 },
168 }
169 }
170}
171
172impl<'de> Deserialize<'de> for Expression {
173 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
174 where
175 D: Deserializer<'de>,
176 {
177 let text = String::deserialize(deserializer)?;
178 Expression::from_str(&text).map_err(D::Error::custom)
179 }
180}
181
182impl Serialize for Expression {
183 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
184 where
185 S: Serializer,
186 {
187 self.to_string().serialize(serializer)
188 }
189}
190
191#[derive(Debug, Clone)]
192pub struct Value {
193 raw: Arc<str>,
194 sensitive: bool,
195}
196
197impl Display for Value {
198 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
199 let (value, enabled) = match self.sensitive {
200 true => (self.raw.as_ref(), true),
201 false => (self.raw.as_ref(), false),
202 };
203 f.write_char('(')?;
204 f.write_str(value)?;
205 f.write_char(',')?;
206 f.write_str(if enabled { "true" } else { "false" })?;
207 f.write_char(')')
208 }
209}
210
211impl Value {
212 pub fn new(value: impl AsRef<str>, sensitive: bool) -> Self {
213 let raw = if sensitive {
214 Arc::from(value.as_ref())
215 } else {
216 Arc::from(value.as_ref().to_lowercase())
217 };
218 Self { raw, sensitive }
219 }
220
221 pub fn equals(&self, value: Option<&str>) -> bool {
222 match value {
223 Some(value) => {
224 if self.sensitive {
225 self.raw.as_ref() == value
226 } else {
227 self.raw.as_ref().eq_ignore_ascii_case(value)
228 }
229 }
230 None => false,
231 }
232 }
233
234 pub fn not_equals(&self, value: Option<&str>) -> bool {
235 !self.equals(value)
236 }
237
238 pub fn starts_with(&self, value: Option<&str>) -> bool {
239 match value {
240 Some(value) => {
241 if self.sensitive {
242 value.starts_with(self.raw.as_ref())
243 } else {
244 value.to_lowercase().starts_with(self.raw.as_ref())
245 }
246 }
247 None => false,
248 }
249 }
250
251 pub fn not_starts_with(&self, value: Option<&str>) -> bool {
252 !self.starts_with(value)
253 }
254
255 pub fn ends_with(&self, value: Option<&str>) -> bool {
256 match value {
257 Some(value) => {
258 if self.sensitive {
259 value.ends_with(self.raw.as_ref())
260 } else {
261 value.to_lowercase().ends_with(self.raw.as_ref())
262 }
263 }
264 None => false,
265 }
266 }
267
268 pub fn not_ends_with(&self, value: Option<&str>) -> bool {
269 !self.ends_with(value)
270 }
271
272 pub fn contains(&self, value: Option<&str>) -> bool {
273 match value {
274 Some(value) => {
275 if self.sensitive {
276 value.contains(self.raw.as_ref())
277 } else {
278 value.to_lowercase().contains(self.raw.as_ref())
279 }
280 }
281 None => false,
282 }
283 }
284
285 pub fn not_contains(&self, value: Option<&str>) -> bool {
286 !self.contains(value)
287 }
288}