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),
29 NotRe(Regex),
30}
31
32impl fmt::Display for MatchOp {
33 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
34 match self {
35 MatchOp::Equal => write!(f, "="),
36 MatchOp::NotEqual => write!(f, "!="),
37 MatchOp::Re(_reg) => write!(f, "=~"),
38 MatchOp::NotRe(_reg) => write!(f, "!~"),
39 }
40 }
41}
42
43impl PartialEq for MatchOp {
44 fn eq(&self, other: &Self) -> bool {
45 match (self, other) {
46 (MatchOp::Equal, MatchOp::Equal) => true,
47 (MatchOp::NotEqual, MatchOp::NotEqual) => true,
48 (MatchOp::Re(s), MatchOp::Re(o)) => s.as_str().eq(o.as_str()),
49 (MatchOp::NotRe(s), MatchOp::NotRe(o)) => s.as_str().eq(o.as_str()),
50 _ => false,
51 }
52 }
53}
54
55impl Eq for MatchOp {}
56
57impl Hash for MatchOp {
58 fn hash<H: Hasher>(&self, state: &mut H) {
59 match self {
60 MatchOp::Equal => "eq".hash(state),
61 MatchOp::NotEqual => "ne".hash(state),
62 MatchOp::Re(s) => format!("re:{}", s.as_str()).hash(state),
63 MatchOp::NotRe(s) => format!("nre:{}", s.as_str()).hash(state),
64 }
65 }
66}
67
68#[cfg(feature = "ser")]
69impl serde::Serialize for MatchOp {
70 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
71 where
72 S: serde::Serializer,
73 {
74 serializer.serialize_str(&self.to_string())
75 }
76}
77
78#[derive(Debug, Clone, PartialEq, Eq, Hash)]
80#[cfg_attr(feature = "ser", derive(serde::Serialize))]
81pub struct Matcher {
82 #[cfg_attr(feature = "ser", serde(rename = "type"))]
83 pub op: MatchOp,
84 pub name: String,
85 pub value: String,
86}
87
88impl Matcher {
89 pub fn new(op: MatchOp, name: &str, value: &str) -> Self {
90 Self {
91 op,
92 name: name.into(),
93 value: value.into(),
94 }
95 }
96
97 pub fn is_match(&self, s: &str) -> bool {
99 match &self.op {
100 MatchOp::Equal => self.value.eq(s),
101 MatchOp::NotEqual => self.value.ne(s),
102 MatchOp::Re(r) => r.is_match(s),
103 MatchOp::NotRe(r) => !r.is_match(s),
104 }
105 }
106
107 fn try_parse_re(original_re: &str) -> Result<Regex, String> {
116 let re = format!(
117 "^(?:{})$",
118 unescaper::unescape(original_re).map_err(|e| format!("Invalid regex pattern, {e}"))?
119 );
120 Regex::new(&re)
121 .or_else(|_| Regex::new(&try_escape_for_repeat_re(&re)))
122 .map_err(|_| format!("illegal regex for {original_re}",))
123 }
124
125 pub fn new_matcher(id: TokenId, name: String, value: String) -> Result<Matcher, String> {
126 let op = Self::find_matcher_op(id, &value)?;
127 op.map(|op| Matcher::new(op, name.as_str(), value.as_str()))
128 }
129
130 fn find_matcher_op(id: TokenId, value: &str) -> Result<Result<MatchOp, String>, String> {
131 let op = match id {
132 T_EQL => Ok(MatchOp::Equal),
133 T_NEQ => Ok(MatchOp::NotEqual),
134 T_EQL_REGEX => Ok(MatchOp::Re(Matcher::try_parse_re(value)?)),
135 T_NEQ_REGEX => Ok(MatchOp::NotRe(Matcher::try_parse_re(value)?)),
136 _ => Err(format!("invalid match op {}", token_display(id))),
137 };
138 Ok(op)
139 }
140}
141
142impl fmt::Display for Matcher {
143 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
144 write!(f, "{}{}\"{}\"", self.name, self.op, self.value)
145 }
146}
147
148fn try_escape_for_repeat_re(re: &str) -> String {
153 fn is_repeat(chars: &mut std::str::Chars<'_>) -> (bool, String) {
154 let mut buf = String::new();
155 let mut comma_seen = false;
156 for c in chars.by_ref() {
157 buf.push(c);
158 match c {
159 ',' if comma_seen => {
160 return (false, buf); }
162 ',' if buf == "," => {
163 return (false, buf); }
165 ',' if !comma_seen => comma_seen = true,
166 '}' if buf == "}" => {
167 return (false, buf); }
169 '}' => {
170 return (true, buf);
171 }
172 _ if c.is_ascii_digit() => continue,
173 _ => {
174 return (false, buf); }
176 }
177 }
178 (false, buf) }
180
181 let mut result = String::with_capacity(re.len() + 1);
182 let mut chars = re.chars();
183
184 while let Some(c) = chars.next() {
185 match c {
186 '\\' => {
187 if let Some(cc) = chars.next() {
188 result.push(c);
189 result.push(cc);
190 }
191 }
192 '{' => {
193 let (is, s) = is_repeat(&mut chars);
194 if !is {
195 result.push('\\');
196 }
197 result.push(c);
198 result.push_str(&s);
199 }
200 _ => result.push(c),
201 }
202 }
203 result
204}
205
206#[derive(Debug, Clone, PartialEq, Eq)]
207#[cfg_attr(feature = "ser", derive(serde::Serialize))]
208pub struct Matchers {
209 pub matchers: Vec<Matcher>,
210 #[cfg_attr(feature = "ser", serde(skip_serializing_if = "<[_]>::is_empty"))]
211 pub or_matchers: Vec<Vec<Matcher>>,
212}
213
214impl Matchers {
215 pub fn empty() -> Self {
216 Self {
217 matchers: vec![],
218 or_matchers: vec![],
219 }
220 }
221
222 pub fn one(matcher: Matcher) -> Self {
223 let matchers = vec![matcher];
224 Self {
225 matchers,
226 or_matchers: vec![],
227 }
228 }
229
230 pub fn new(matchers: Vec<Matcher>) -> Self {
231 Self {
232 matchers,
233 or_matchers: vec![],
234 }
235 }
236
237 pub fn with_or_matchers(mut self, or_matchers: Vec<Vec<Matcher>>) -> Self {
238 self.or_matchers = or_matchers;
239 self
240 }
241
242 pub fn append(mut self, matcher: Matcher) -> Self {
243 let last_or_matcher = self.or_matchers.last_mut();
246 if let Some(last_or_matcher) = last_or_matcher {
247 last_or_matcher.push(matcher);
248 } else {
249 self.matchers.push(matcher);
250 }
251 self
252 }
253
254 pub fn append_or(mut self, matcher: Matcher) -> Self {
255 if !self.matchers.is_empty() {
256 let last_matchers = std::mem::take(&mut self.matchers);
259 self.or_matchers.push(last_matchers);
260 }
261 let new_or_matchers = vec![matcher];
262 self.or_matchers.push(new_or_matchers);
263 self
264 }
265
266 pub fn is_empty_matchers(&self) -> bool {
272 (self.matchers.is_empty() && self.or_matchers.is_empty())
273 || self
274 .matchers
275 .iter()
276 .chain(self.or_matchers.iter().flatten())
277 .all(|m| m.is_match(""))
278 }
279
280 pub(crate) fn find_matcher_value(&self, name: &str) -> Option<String> {
283 self.matchers
284 .iter()
285 .chain(self.or_matchers.iter().flatten())
286 .find(|m| m.name.eq(name))
287 .map(|m| m.value.clone())
288 }
289
290 pub fn find_matchers(&self, name: &str) -> Vec<Matcher> {
292 self.matchers
293 .iter()
294 .chain(self.or_matchers.iter().flatten())
295 .filter(|m| m.name.eq(name))
296 .cloned()
297 .collect()
298 }
299}
300
301impl fmt::Display for Matchers {
302 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
303 let simple_matchers = &self.matchers;
304 let or_matchers = &self.or_matchers;
305 if or_matchers.is_empty() {
306 write!(f, "{}", join_vector(simple_matchers, ",", true))
307 } else {
308 let or_matchers_string =
309 self.or_matchers
310 .iter()
311 .fold(String::new(), |or_matchers_str, pair| {
312 format!("{} or {}", or_matchers_str, join_vector(pair, ", ", false))
313 });
314 let or_matchers_string = or_matchers_string.trim_start_matches(" or").trim();
315 write!(f, "{or_matchers_string}")
316 }
317 }
318}
319
320#[cfg(test)]
321mod tests {
322 use super::*;
323 use crate::parser::token;
324 use std::collections::hash_map::DefaultHasher;
325
326 fn hash<H>(op: H) -> u64
327 where
328 H: Hash,
329 {
330 let mut hasher = DefaultHasher::new();
331 op.hash(&mut hasher);
332 hasher.finish()
333 }
334
335 #[test]
336 fn test_new_matcher() {
337 assert_eq!(
338 Matcher::new_matcher(token::T_ADD, "".into(), "".into()),
339 Err(format!("invalid match op {}", token_display(token::T_ADD)))
340 )
341 }
342
343 #[test]
344 fn test_matcher_op_eq() {
345 assert_eq!(MatchOp::Equal, MatchOp::Equal);
346 assert_eq!(MatchOp::NotEqual, MatchOp::NotEqual);
347 assert_eq!(
348 MatchOp::Re(Regex::new("\\s+").unwrap()),
349 MatchOp::Re(Regex::new("\\s+").unwrap())
350 );
351 assert_eq!(
352 MatchOp::NotRe(Regex::new("\\s+").unwrap()),
353 MatchOp::NotRe(Regex::new("\\s+").unwrap())
354 );
355
356 assert_ne!(MatchOp::Equal, MatchOp::NotEqual);
357 assert_ne!(
358 MatchOp::NotEqual,
359 MatchOp::NotRe(Regex::new("\\s+").unwrap())
360 );
361 assert_ne!(
362 MatchOp::Re(Regex::new("\\s+").unwrap()),
363 MatchOp::NotRe(Regex::new("\\s+").unwrap())
364 );
365 }
366
367 #[test]
368 fn test_matchop_hash() {
369 assert_eq!(hash(MatchOp::Equal), hash(MatchOp::Equal));
370 assert_eq!(hash(MatchOp::NotEqual), hash(MatchOp::NotEqual));
371 assert_eq!(
372 hash(MatchOp::Re(Regex::new("\\s+").unwrap())),
373 hash(MatchOp::Re(Regex::new("\\s+").unwrap()))
374 );
375 assert_eq!(
376 hash(MatchOp::NotRe(Regex::new("\\s+").unwrap())),
377 hash(MatchOp::NotRe(Regex::new("\\s+").unwrap()))
378 );
379
380 assert_ne!(hash(MatchOp::Equal), hash(MatchOp::NotEqual));
381 assert_ne!(
382 hash(MatchOp::NotEqual),
383 hash(MatchOp::NotRe(Regex::new("\\s+").unwrap()))
384 );
385 assert_ne!(
386 hash(MatchOp::Re(Regex::new("\\s+").unwrap())),
387 hash(MatchOp::NotRe(Regex::new("\\s+").unwrap()))
388 );
389 }
390
391 #[test]
392 fn test_matcher_hash() {
393 assert_eq!(
394 hash(Matcher::new(MatchOp::Equal, "name", "value")),
395 hash(Matcher::new(MatchOp::Equal, "name", "value")),
396 );
397
398 assert_eq!(
399 hash(Matcher::new(MatchOp::NotEqual, "name", "value")),
400 hash(Matcher::new(MatchOp::NotEqual, "name", "value")),
401 );
402
403 assert_eq!(
404 hash(Matcher::new(
405 MatchOp::Re(Regex::new("\\s+").unwrap()),
406 "name",
407 "\\s+"
408 )),
409 hash(Matcher::new(
410 MatchOp::Re(Regex::new("\\s+").unwrap()),
411 "name",
412 "\\s+"
413 )),
414 );
415
416 assert_eq!(
417 hash(Matcher::new(
418 MatchOp::NotRe(Regex::new("\\s+").unwrap()),
419 "name",
420 "\\s+"
421 )),
422 hash(Matcher::new(
423 MatchOp::NotRe(Regex::new("\\s+").unwrap()),
424 "name",
425 "\\s+"
426 )),
427 );
428
429 assert_ne!(
430 hash(Matcher::new(MatchOp::Equal, "name", "value")),
431 hash(Matcher::new(MatchOp::NotEqual, "name", "value")),
432 );
433
434 assert_ne!(
435 hash(Matcher::new(
436 MatchOp::Re(Regex::new("\\s+").unwrap()),
437 "name",
438 "\\s+"
439 )),
440 hash(Matcher::new(
441 MatchOp::NotRe(Regex::new("\\s+").unwrap()),
442 "name",
443 "\\s+"
444 )),
445 );
446 }
447
448 #[test]
449 fn test_matcher_eq_ne() {
450 let op = MatchOp::Equal;
451 let matcher = Matcher::new(op, "name", "up");
452 assert!(matcher.is_match("up"));
453 assert!(!matcher.is_match("down"));
454
455 let op = MatchOp::NotEqual;
456 let matcher = Matcher::new(op, "name", "up");
457 assert!(matcher.is_match("foo"));
458 assert!(matcher.is_match("bar"));
459 assert!(!matcher.is_match("up"));
460 }
461
462 #[test]
463 fn test_matcher_re() {
464 let value = "api/v1/.*";
465 let re = Regex::new(value).unwrap();
466 let op = MatchOp::Re(re);
467 let matcher = Matcher::new(op, "name", value);
468 assert!(matcher.is_match("api/v1/query"));
469 assert!(matcher.is_match("api/v1/range_query"));
470 assert!(!matcher.is_match("api/v2"));
471 }
472
473 #[test]
474 fn test_eq_matcher_equality() {
475 assert_eq!(
476 Matcher::new(MatchOp::Equal, "code", "200"),
477 Matcher::new(MatchOp::Equal, "code", "200")
478 );
479
480 assert_ne!(
481 Matcher::new(MatchOp::Equal, "code", "200"),
482 Matcher::new(MatchOp::Equal, "code", "201")
483 );
484
485 assert_ne!(
486 Matcher::new(MatchOp::Equal, "code", "200"),
487 Matcher::new(MatchOp::NotEqual, "code", "200")
488 );
489 }
490
491 #[test]
492 fn test_ne_matcher_equality() {
493 assert_eq!(
494 Matcher::new(MatchOp::NotEqual, "code", "200"),
495 Matcher::new(MatchOp::NotEqual, "code", "200")
496 );
497
498 assert_ne!(
499 Matcher::new(MatchOp::NotEqual, "code", "200"),
500 Matcher::new(MatchOp::NotEqual, "code", "201")
501 );
502
503 assert_ne!(
504 Matcher::new(MatchOp::NotEqual, "code", "200"),
505 Matcher::new(MatchOp::Equal, "code", "200")
506 );
507 }
508
509 #[test]
510 fn test_re_matcher_equality() {
511 assert_eq!(
512 Matcher::new(MatchOp::Re(Regex::new("2??").unwrap()), "code", "2??",),
513 Matcher::new(MatchOp::Re(Regex::new("2??").unwrap()), "code", "2??",)
514 );
515
516 assert_ne!(
517 Matcher::new(MatchOp::Re(Regex::new("2??").unwrap()), "code", "2??",),
518 Matcher::new(MatchOp::Re(Regex::new("2??").unwrap()), "code", "2*?",)
519 );
520
521 assert_ne!(
522 Matcher::new(MatchOp::Re(Regex::new("2??").unwrap()), "code", "2??",),
523 Matcher::new(MatchOp::Equal, "code", "2??")
524 );
525
526 let matcher = Matcher::new(
528 MatchOp::Re(Matcher::try_parse_re("abc.*").unwrap()),
529 "code",
530 "abc.*",
531 );
532 assert!(matcher.is_match("abc123"));
533 assert!(!matcher.is_match("xabc123"));
534
535 let matcher = Matcher::new(
536 MatchOp::Re(Matcher::try_parse_re(".*xyz$").unwrap()),
537 "code",
538 ".*xyz",
539 );
540 assert!(matcher.is_match("123xyz"));
541 assert!(!matcher.is_match("123xyzx"));
542
543 let matcher = Matcher::new(
544 MatchOp::Re(Matcher::try_parse_re("abc").unwrap()),
545 "code",
546 "abc",
547 );
548 assert!(matcher.is_match("abc"));
549 assert!(!matcher.is_match("xabc"));
550 assert!(!matcher.is_match("abcx"));
551
552 let matcher = Matcher::new(
553 MatchOp::Re(Matcher::try_parse_re("127.0.0.1").unwrap()),
554 "code",
555 "127.0.0.1",
556 );
557 assert!(matcher.is_match("127.0.0.1"));
558 assert!(!matcher.is_match("x127.0.0.1"));
559 assert!(!matcher.is_match("127.0.0.2"));
560
561 let raw_input = r#"127\\.0\\.0\\.1"#;
562 let matcher = Matcher::new(
563 MatchOp::Re(Matcher::try_parse_re(raw_input).unwrap()),
564 "code",
565 raw_input,
566 );
567 assert!(matcher.is_match("127.0.0.1"));
568 assert!(!matcher.is_match("x127.0.0.1"));
569 assert!(!matcher.is_match("127.0.0.2"));
570 let re = Matcher::try_parse_re(raw_input).unwrap();
572 let new_re = Regex::new(re.as_str()).unwrap();
573 assert_eq!(re.as_str(), new_re.as_str());
574 }
575
576 #[test]
577 fn test_not_re_matcher_equality() {
578 assert_eq!(
579 Matcher::new(MatchOp::NotRe(Regex::new("2??").unwrap()), "code", "2??",),
580 Matcher::new(MatchOp::NotRe(Regex::new("2??").unwrap()), "code", "2??",)
581 );
582
583 assert_ne!(
584 Matcher::new(MatchOp::NotRe(Regex::new("2??").unwrap()), "code", "2??",),
585 Matcher::new(MatchOp::NotRe(Regex::new("2?*").unwrap()), "code", "2*?",)
586 );
587
588 assert_ne!(
589 Matcher::new(MatchOp::NotRe(Regex::new("2??").unwrap()), "code", "2??",),
590 Matcher::new(MatchOp::Equal, "code", "2??")
591 );
592
593 let matcher = Matcher::new(
595 MatchOp::NotRe(Matcher::try_parse_re("abc.*").unwrap()),
596 "code",
597 "abc.*",
598 );
599 assert!(!matcher.is_match("abc123"));
600 assert!(matcher.is_match("xabc123")); let matcher = Matcher::new(
603 MatchOp::NotRe(Matcher::try_parse_re(".*xyz$").unwrap()),
604 "code",
605 ".*xyz",
606 );
607 assert!(!matcher.is_match("123xyz"));
608 assert!(matcher.is_match("123xyzx")); }
610
611 #[test]
612 fn test_matchers_equality() {
613 assert_eq!(
614 Matchers::empty()
615 .append(Matcher::new(MatchOp::Equal, "name1", "val1"))
616 .append(Matcher::new(MatchOp::Equal, "name2", "val2")),
617 Matchers::empty()
618 .append(Matcher::new(MatchOp::Equal, "name1", "val1"))
619 .append(Matcher::new(MatchOp::Equal, "name2", "val2"))
620 );
621
622 assert_ne!(
623 Matchers::empty().append(Matcher::new(MatchOp::Equal, "name1", "val1")),
624 Matchers::empty().append(Matcher::new(MatchOp::Equal, "name2", "val2"))
625 );
626
627 assert_ne!(
628 Matchers::empty().append(Matcher::new(MatchOp::Equal, "name1", "val1")),
629 Matchers::empty().append(Matcher::new(MatchOp::NotEqual, "name1", "val1"))
630 );
631
632 assert_eq!(
633 Matchers::empty()
634 .append(Matcher::new(MatchOp::Equal, "name1", "val1"))
635 .append(Matcher::new(MatchOp::NotEqual, "name2", "val2"))
636 .append(Matcher::new(
637 MatchOp::Re(Regex::new("\\d+").unwrap()),
638 "name2",
639 "\\d+"
640 ))
641 .append(Matcher::new(
642 MatchOp::NotRe(Regex::new("\\d+").unwrap()),
643 "name2",
644 "\\d+"
645 )),
646 Matchers::empty()
647 .append(Matcher::new(MatchOp::Equal, "name1", "val1"))
648 .append(Matcher::new(MatchOp::NotEqual, "name2", "val2"))
649 .append(Matcher::new(
650 MatchOp::Re(Regex::new("\\d+").unwrap()),
651 "name2",
652 "\\d+"
653 ))
654 .append(Matcher::new(
655 MatchOp::NotRe(Regex::new("\\d+").unwrap()),
656 "name2",
657 "\\d+"
658 ))
659 );
660 }
661
662 #[test]
663 fn test_find_matchers() {
664 let matchers = Matchers::empty()
665 .append(Matcher::new(MatchOp::Equal, "foo", "bar"))
666 .append(Matcher::new(MatchOp::NotEqual, "foo", "bar"))
667 .append(Matcher::new_matcher(T_EQL_REGEX, "foo".into(), "bar".into()).unwrap())
668 .append(Matcher::new_matcher(T_NEQ_REGEX, "foo".into(), "bar".into()).unwrap())
669 .append(Matcher::new(MatchOp::Equal, "FOO", "bar"))
670 .append(Matcher::new(MatchOp::NotEqual, "bar", "bar"));
671
672 let ms = matchers.find_matchers("foo");
673 assert_eq!(4, ms.len());
674 }
675
676 #[test]
677 fn test_convert_re() {
678 assert_eq!(try_escape_for_repeat_re("abc{}"), r"abc\{}");
679 assert_eq!(try_escape_for_repeat_re("abc{def}"), r"abc\{def}");
680 assert_eq!(try_escape_for_repeat_re("abc{def"), r"abc\{def");
681 assert_eq!(try_escape_for_repeat_re("abc{1}"), "abc{1}");
682 assert_eq!(try_escape_for_repeat_re("abc{1,}"), "abc{1,}");
683 assert_eq!(try_escape_for_repeat_re("abc{1,2}"), "abc{1,2}");
684 assert_eq!(try_escape_for_repeat_re("abc{,2}"), r"abc\{,2}");
685 assert_eq!(try_escape_for_repeat_re("abc{{1,2}}"), r"abc\{{1,2}}");
686 assert_eq!(try_escape_for_repeat_re(r"abc\{abc"), r"abc\{abc");
687 assert_eq!(try_escape_for_repeat_re("abc{1a}"), r"abc\{1a}");
688 assert_eq!(try_escape_for_repeat_re("abc{1,a}"), r"abc\{1,a}");
689 assert_eq!(try_escape_for_repeat_re("abc{1,2a}"), r"abc\{1,2a}");
690 assert_eq!(try_escape_for_repeat_re("abc{1,2,3}"), r"abc\{1,2,3}");
691 assert_eq!(try_escape_for_repeat_re("abc{1,,2}"), r"abc\{1,,2}");
692 }
693}