1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
use crate::{build_regex, utils::build_whole_word_pattern};

/// Trait with methods to filter arrays or vectors of strings by regular expression patterns
/// Only pattern_filter() method needs to be implemented.
/// Both implementations ensure the regex is compiled only once.
/// If the regex fails, filters will not be applied.
pub trait PatternFilter<'a, T> where T:Sized {
  /// Filter an array of strs by the pattern
  fn pattern_filter(&'a self, pattern: &str, case_insensitive: bool) -> Vec<T>;

  /// Filters strings in case-insensitive mode
  fn pattern_filter_ci(&'a self, pattern: &str) -> Vec<T> {
    self.pattern_filter(pattern, true)
  }

  /// Filters strings in case-sensitive mode
  fn pattern_filter_cs(&'a self, pattern: &str) -> Vec<T> {
    self.pattern_filter(pattern, false)
  }

  /// Filters strings by whole word regex patterns with case-insensitive flag
  fn pattern_filter_word(&'a self, pattern: &str, case_insensitive: bool) -> Vec<T> {
    let word_pattern = build_whole_word_pattern(pattern);
    self.pattern_filter(&word_pattern, case_insensitive)
  }

  /// Filters strings by whole word regex patterns in case-insensitive mode
  fn pattern_filter_word_ci(&'a self, pattern: &str) -> Vec<T> {
    self.pattern_filter_word(pattern, true)
  }

  /// Filters strings by whole word regex patterns in case-sensitive mode
  fn pattern_filter_word_cs(&'a self, pattern: &str) -> Vec<T> {
    self.pattern_filter_word(pattern, false)
  }
}

impl<'a> PatternFilter<'a, String> for [String] {
  /// Filter an array of strs by the pattern
  fn pattern_filter(&'a self, pattern: &str, case_insensitive: bool) -> Vec<String> {
    if let Ok(re) = build_regex(pattern, case_insensitive) {
      self.into_iter().filter(|s| re.is_match(s)).map(|s| s.to_owned()).collect::<Vec<String>>()
    } else {
      self.to_owned()
    }
  }
}

impl<'a> PatternFilter<'a, &'a str> for [&str] {
  /// Filter an array of strs by the pattern
  fn pattern_filter(&'a self, pattern: &str, case_insensitive: bool) -> Vec<&str> {
    if let Ok(re) = build_regex(pattern, case_insensitive) {
      self.into_iter().filter(|s| re.is_match(s)).map(|s| s.to_owned()).collect::<Vec<&str>>()
    } else {
      self.into_iter().map(|s| s.to_owned()).collect::<Vec<&str>>()
    }
  }
}