1use std::fmt;
16use std::hash::{Hash, Hasher};
17
18use regex::Regex;
19
20use crate::parser::token::{token_display, TokenId, T_EQL, T_EQL_REGEX, T_NEQ, T_NEQ_REGEX};
21use crate::util::join_vector;
22
23#[derive(Debug, Clone)]
24pub enum MatchOp {
25 Equal,
26 NotEqual,
27 Re(Regex),
28 NotRe(Regex),
29}
30
31impl fmt::Display for MatchOp {
32 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
33 match self {
34 MatchOp::Equal => write!(f, "="),
35 MatchOp::NotEqual => write!(f, "!="),
36 MatchOp::Re(_reg) => write!(f, "=~"),
37 MatchOp::NotRe(_reg) => write!(f, "!~"),
38 }
39 }
40}
41
42impl PartialEq for MatchOp {
43 fn eq(&self, other: &Self) -> bool {
44 match (self, other) {
45 (MatchOp::Equal, MatchOp::Equal) => true,
46 (MatchOp::NotEqual, MatchOp::NotEqual) => true,
47 (MatchOp::Re(s), MatchOp::Re(o)) => s.as_str().eq(o.as_str()),
48 (MatchOp::NotRe(s), MatchOp::NotRe(o)) => s.as_str().eq(o.as_str()),
49 _ => false,
50 }
51 }
52}
53
54impl Eq for MatchOp {}
55
56impl Hash for MatchOp {
57 fn hash<H: Hasher>(&self, state: &mut H) {
58 match self {
59 MatchOp::Equal => "eq".hash(state),
60 MatchOp::NotEqual => "ne".hash(state),
61 MatchOp::Re(s) => format!("re:{}", s.as_str()).hash(state),
62 MatchOp::NotRe(s) => format!("nre:{}", s.as_str()).hash(state),
63 }
64 }
65}
66
67#[derive(Debug, Clone, PartialEq, Eq, Hash)]
69pub struct Matcher {
70 pub op: MatchOp,
71 pub name: String,
72 pub value: String,
73}
74
75impl Matcher {
76 pub fn new(op: MatchOp, name: &str, value: &str) -> Self {
77 Self {
78 op,
79 name: name.into(),
80 value: value.into(),
81 }
82 }
83
84 pub fn is_match(&self, s: &str) -> bool {
86 match &self.op {
87 MatchOp::Equal => self.value.eq(s),
88 MatchOp::NotEqual => self.value.ne(s),
89 MatchOp::Re(r) => r.is_match(s),
90 MatchOp::NotRe(r) => !r.is_match(s),
91 }
92 }
93
94 fn try_parse_re(re: &str) -> Result<Regex, String> {
99 Regex::new(re)
100 .or_else(|_| Regex::new(&try_escape_for_repeat_re(re)))
101 .map_err(|_| format!("illegal regex for {re}",))
102 }
103
104 pub fn new_matcher(id: TokenId, name: String, value: String) -> Result<Matcher, String> {
105 let op = match id {
106 T_EQL => Ok(MatchOp::Equal),
107 T_NEQ => Ok(MatchOp::NotEqual),
108 T_EQL_REGEX => Ok(MatchOp::Re(Matcher::try_parse_re(&value)?)),
109 T_NEQ_REGEX => Ok(MatchOp::NotRe(Matcher::try_parse_re(&value)?)),
110 _ => Err(format!("invalid match op {}", token_display(id))),
111 };
112
113 op.map(|op| Matcher { op, name, value })
114 }
115}
116
117impl fmt::Display for Matcher {
118 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
119 write!(f, "{}{}\"{}\"", self.name, self.op, self.value)
120 }
121}
122
123fn try_escape_for_repeat_re(re: &str) -> String {
128 fn is_repeat(chars: &mut std::str::Chars<'_>) -> (bool, String) {
129 let mut buf = String::new();
130 let mut comma_seen = false;
131 for c in chars.by_ref() {
132 buf.push(c);
133 match c {
134 ',' if comma_seen => {
135 return (false, buf); }
137 ',' if buf == "," => {
138 return (false, buf); }
140 ',' if !comma_seen => comma_seen = true,
141 '}' if buf == "}" => {
142 return (false, buf); }
144 '}' => {
145 return (true, buf);
146 }
147 _ if c.is_ascii_digit() => continue,
148 _ => {
149 return (false, buf); }
151 }
152 }
153 (false, buf) }
155
156 let mut result = String::with_capacity(re.len() + 1);
157 let mut chars = re.chars();
158
159 while let Some(c) = chars.next() {
160 match c {
161 '\\' => {
162 if let Some(cc) = chars.next() {
163 result.push(c);
164 result.push(cc);
165 }
166 }
167 '{' => {
168 let (is, s) = is_repeat(&mut chars);
169 if !is {
170 result.push('\\');
171 }
172 result.push(c);
173 result.push_str(&s);
174 }
175 _ => result.push(c),
176 }
177 }
178 result
179}
180
181#[derive(Debug, Clone, PartialEq, Eq)]
182pub struct Matchers {
183 pub matchers: Vec<Matcher>,
184}
185
186impl Matchers {
187 pub fn empty() -> Self {
188 Self { matchers: vec![] }
189 }
190
191 pub fn one(matcher: Matcher) -> Self {
192 let matchers = vec![matcher];
193 Self { matchers }
194 }
195
196 pub fn new(matchers: Vec<Matcher>) -> Self {
197 Self { matchers }
198 }
199
200 pub fn append(mut self, matcher: Matcher) -> Self {
201 self.matchers.push(matcher);
202 self
203 }
204
205 pub fn is_empty_matchers(&self) -> bool {
211 self.matchers.is_empty() || self.matchers.iter().all(|m| m.is_match(""))
212 }
213
214 pub(crate) fn find_matcher_value(&self, name: &str) -> Option<String> {
217 for m in &self.matchers {
218 if m.name.eq(name) {
219 return Some(m.value.clone());
220 }
221 }
222 None
223 }
224
225 pub fn find_matchers(&self, name: &str) -> Vec<Matcher> {
227 self.matchers
228 .iter()
229 .filter(|m| m.name.eq(name))
230 .cloned()
231 .collect()
232 }
233}
234
235impl fmt::Display for Matchers {
236 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
237 write!(f, "{}", join_vector(&self.matchers, ",", true))
238 }
239}
240
241#[cfg(test)]
242mod tests {
243 use super::*;
244 use crate::parser::token;
245 use std::collections::hash_map::DefaultHasher;
246
247 fn hash<H>(op: H) -> u64
248 where
249 H: Hash,
250 {
251 let mut hasher = DefaultHasher::new();
252 op.hash(&mut hasher);
253 hasher.finish()
254 }
255
256 #[test]
257 fn test_new_matcher() {
258 assert_eq!(
259 Matcher::new_matcher(token::T_ADD, "".into(), "".into()),
260 Err(format!("invalid match op {}", token_display(token::T_ADD)))
261 )
262 }
263
264 #[test]
265 fn test_matcher_op_eq() {
266 assert_eq!(MatchOp::Equal, MatchOp::Equal);
267 assert_eq!(MatchOp::NotEqual, MatchOp::NotEqual);
268 assert_eq!(
269 MatchOp::Re(Regex::new("\\s+").unwrap()),
270 MatchOp::Re(Regex::new("\\s+").unwrap())
271 );
272 assert_eq!(
273 MatchOp::NotRe(Regex::new("\\s+").unwrap()),
274 MatchOp::NotRe(Regex::new("\\s+").unwrap())
275 );
276
277 assert_ne!(MatchOp::Equal, MatchOp::NotEqual);
278 assert_ne!(
279 MatchOp::NotEqual,
280 MatchOp::NotRe(Regex::new("\\s+").unwrap())
281 );
282 assert_ne!(
283 MatchOp::Re(Regex::new("\\s+").unwrap()),
284 MatchOp::NotRe(Regex::new("\\s+").unwrap())
285 );
286 }
287
288 #[test]
289 fn test_matchop_hash() {
290 assert_eq!(hash(MatchOp::Equal), hash(MatchOp::Equal));
291 assert_eq!(hash(MatchOp::NotEqual), hash(MatchOp::NotEqual));
292 assert_eq!(
293 hash(MatchOp::Re(Regex::new("\\s+").unwrap())),
294 hash(MatchOp::Re(Regex::new("\\s+").unwrap()))
295 );
296 assert_eq!(
297 hash(MatchOp::NotRe(Regex::new("\\s+").unwrap())),
298 hash(MatchOp::NotRe(Regex::new("\\s+").unwrap()))
299 );
300
301 assert_ne!(hash(MatchOp::Equal), hash(MatchOp::NotEqual));
302 assert_ne!(
303 hash(MatchOp::NotEqual),
304 hash(MatchOp::NotRe(Regex::new("\\s+").unwrap()))
305 );
306 assert_ne!(
307 hash(MatchOp::Re(Regex::new("\\s+").unwrap())),
308 hash(MatchOp::NotRe(Regex::new("\\s+").unwrap()))
309 );
310 }
311
312 #[test]
313 fn test_matcher_hash() {
314 assert_eq!(
315 hash(Matcher::new(MatchOp::Equal, "name", "value")),
316 hash(Matcher::new(MatchOp::Equal, "name", "value")),
317 );
318
319 assert_eq!(
320 hash(Matcher::new(MatchOp::NotEqual, "name", "value")),
321 hash(Matcher::new(MatchOp::NotEqual, "name", "value")),
322 );
323
324 assert_eq!(
325 hash(Matcher::new(
326 MatchOp::Re(Regex::new("\\s+").unwrap()),
327 "name",
328 "\\s+"
329 )),
330 hash(Matcher::new(
331 MatchOp::Re(Regex::new("\\s+").unwrap()),
332 "name",
333 "\\s+"
334 )),
335 );
336
337 assert_eq!(
338 hash(Matcher::new(
339 MatchOp::NotRe(Regex::new("\\s+").unwrap()),
340 "name",
341 "\\s+"
342 )),
343 hash(Matcher::new(
344 MatchOp::NotRe(Regex::new("\\s+").unwrap()),
345 "name",
346 "\\s+"
347 )),
348 );
349
350 assert_ne!(
351 hash(Matcher::new(MatchOp::Equal, "name", "value")),
352 hash(Matcher::new(MatchOp::NotEqual, "name", "value")),
353 );
354
355 assert_ne!(
356 hash(Matcher::new(
357 MatchOp::Re(Regex::new("\\s+").unwrap()),
358 "name",
359 "\\s+"
360 )),
361 hash(Matcher::new(
362 MatchOp::NotRe(Regex::new("\\s+").unwrap()),
363 "name",
364 "\\s+"
365 )),
366 );
367 }
368
369 #[test]
370 fn test_matcher_eq_ne() {
371 let op = MatchOp::Equal;
372 let matcher = Matcher::new(op, "name", "up");
373 assert!(matcher.is_match("up"));
374 assert!(!matcher.is_match("down"));
375
376 let op = MatchOp::NotEqual;
377 let matcher = Matcher::new(op, "name", "up");
378 assert!(matcher.is_match("foo"));
379 assert!(matcher.is_match("bar"));
380 assert!(!matcher.is_match("up"));
381 }
382
383 #[test]
384 fn test_matcher_re() {
385 let value = "api/v1/.*";
386 let re = Regex::new(value).unwrap();
387 let op = MatchOp::Re(re);
388 let matcher = Matcher::new(op, "name", value);
389 assert!(matcher.is_match("api/v1/query"));
390 assert!(matcher.is_match("api/v1/range_query"));
391 assert!(!matcher.is_match("api/v2"));
392 }
393
394 #[test]
395 fn test_eq_matcher_equality() {
396 assert_eq!(
397 Matcher::new(MatchOp::Equal, "code", "200"),
398 Matcher::new(MatchOp::Equal, "code", "200")
399 );
400
401 assert_ne!(
402 Matcher::new(MatchOp::Equal, "code", "200"),
403 Matcher::new(MatchOp::Equal, "code", "201")
404 );
405
406 assert_ne!(
407 Matcher::new(MatchOp::Equal, "code", "200"),
408 Matcher::new(MatchOp::NotEqual, "code", "200")
409 );
410 }
411
412 #[test]
413 fn test_ne_matcher_equality() {
414 assert_eq!(
415 Matcher::new(MatchOp::NotEqual, "code", "200"),
416 Matcher::new(MatchOp::NotEqual, "code", "200")
417 );
418
419 assert_ne!(
420 Matcher::new(MatchOp::NotEqual, "code", "200"),
421 Matcher::new(MatchOp::NotEqual, "code", "201")
422 );
423
424 assert_ne!(
425 Matcher::new(MatchOp::NotEqual, "code", "200"),
426 Matcher::new(MatchOp::Equal, "code", "200")
427 );
428 }
429
430 #[test]
431 fn test_re_matcher_equality() {
432 assert_eq!(
433 Matcher::new(MatchOp::Re(Regex::new("2??").unwrap()), "code", "2??",),
434 Matcher::new(MatchOp::Re(Regex::new("2??").unwrap()), "code", "2??",)
435 );
436
437 assert_ne!(
438 Matcher::new(MatchOp::Re(Regex::new("2??").unwrap()), "code", "2??",),
439 Matcher::new(MatchOp::Re(Regex::new("2??").unwrap()), "code", "2*?",)
440 );
441
442 assert_ne!(
443 Matcher::new(MatchOp::Re(Regex::new("2??").unwrap()), "code", "2??",),
444 Matcher::new(MatchOp::Equal, "code", "2??")
445 );
446 }
447
448 #[test]
449 fn test_not_re_matcher_equality() {
450 assert_eq!(
451 Matcher::new(MatchOp::NotRe(Regex::new("2??").unwrap()), "code", "2??",),
452 Matcher::new(MatchOp::NotRe(Regex::new("2??").unwrap()), "code", "2??",)
453 );
454
455 assert_ne!(
456 Matcher::new(MatchOp::NotRe(Regex::new("2??").unwrap()), "code", "2??",),
457 Matcher::new(MatchOp::NotRe(Regex::new("2?*").unwrap()), "code", "2*?",)
458 );
459
460 assert_ne!(
461 Matcher::new(MatchOp::NotRe(Regex::new("2??").unwrap()), "code", "2??",),
462 Matcher::new(MatchOp::Equal, "code", "2??")
463 );
464 }
465
466 #[test]
467 fn test_matchers_equality() {
468 assert_eq!(
469 Matchers::empty()
470 .append(Matcher::new(MatchOp::Equal, "name1", "val1"))
471 .append(Matcher::new(MatchOp::Equal, "name2", "val2")),
472 Matchers::empty()
473 .append(Matcher::new(MatchOp::Equal, "name1", "val1"))
474 .append(Matcher::new(MatchOp::Equal, "name2", "val2"))
475 );
476
477 assert_ne!(
478 Matchers::empty().append(Matcher::new(MatchOp::Equal, "name1", "val1")),
479 Matchers::empty().append(Matcher::new(MatchOp::Equal, "name2", "val2"))
480 );
481
482 assert_ne!(
483 Matchers::empty().append(Matcher::new(MatchOp::Equal, "name1", "val1")),
484 Matchers::empty().append(Matcher::new(MatchOp::NotEqual, "name1", "val1"))
485 );
486
487 assert_eq!(
488 Matchers::empty()
489 .append(Matcher::new(MatchOp::Equal, "name1", "val1"))
490 .append(Matcher::new(MatchOp::NotEqual, "name2", "val2"))
491 .append(Matcher::new(
492 MatchOp::Re(Regex::new("\\d+").unwrap()),
493 "name2",
494 "\\d+"
495 ))
496 .append(Matcher::new(
497 MatchOp::NotRe(Regex::new("\\d+").unwrap()),
498 "name2",
499 "\\d+"
500 )),
501 Matchers::empty()
502 .append(Matcher::new(MatchOp::Equal, "name1", "val1"))
503 .append(Matcher::new(MatchOp::NotEqual, "name2", "val2"))
504 .append(Matcher::new(
505 MatchOp::Re(Regex::new("\\d+").unwrap()),
506 "name2",
507 "\\d+"
508 ))
509 .append(Matcher::new(
510 MatchOp::NotRe(Regex::new("\\d+").unwrap()),
511 "name2",
512 "\\d+"
513 ))
514 );
515 }
516
517 #[test]
518 fn test_find_matchers() {
519 let matchers = Matchers::empty()
520 .append(Matcher::new(MatchOp::Equal, "foo", "bar"))
521 .append(Matcher::new(MatchOp::NotEqual, "foo", "bar"))
522 .append(Matcher::new_matcher(T_EQL_REGEX, "foo".into(), "bar".into()).unwrap())
523 .append(Matcher::new_matcher(T_NEQ_REGEX, "foo".into(), "bar".into()).unwrap())
524 .append(Matcher::new(MatchOp::Equal, "FOO", "bar"))
525 .append(Matcher::new(MatchOp::NotEqual, "bar", "bar"));
526
527 let ms = matchers.find_matchers("foo");
528 assert_eq!(4, ms.len());
529 }
530
531 #[test]
532 fn test_convert_re() {
533 assert_eq!(try_escape_for_repeat_re("abc{}"), r"abc\{}");
534 assert_eq!(try_escape_for_repeat_re("abc{def}"), r"abc\{def}");
535 assert_eq!(try_escape_for_repeat_re("abc{def"), r"abc\{def");
536 assert_eq!(try_escape_for_repeat_re("abc{1}"), "abc{1}");
537 assert_eq!(try_escape_for_repeat_re("abc{1,}"), "abc{1,}");
538 assert_eq!(try_escape_for_repeat_re("abc{1,2}"), "abc{1,2}");
539 assert_eq!(try_escape_for_repeat_re("abc{,2}"), r"abc\{,2}");
540 assert_eq!(try_escape_for_repeat_re("abc{{1,2}}"), r"abc\{{1,2}}");
541 assert_eq!(try_escape_for_repeat_re(r"abc\{abc"), r"abc\{abc");
542 assert_eq!(try_escape_for_repeat_re("abc{1a}"), r"abc\{1a}");
543 assert_eq!(try_escape_for_repeat_re("abc{1,a}"), r"abc\{1,a}");
544 assert_eq!(try_escape_for_repeat_re("abc{1,2a}"), r"abc\{1,2a}");
545 assert_eq!(try_escape_for_repeat_re("abc{1,2,3}"), r"abc\{1,2,3}");
546 assert_eq!(try_escape_for_repeat_re("abc{1,,2}"), r"abc\{1,,2}");
547 }
548}