use crate::{enums::StringBounds, utils::{pairs_to_string_bounds, strs_to_string_bounds}, BoundsBuilder, BoundsPosition, CaseMatchMode, CharType, StripCharacters};
pub trait SimpleMatch {
fn starts_with_ci(&self, pattern: &str) -> bool;
fn starts_with_ci_alphanum(&self, pattern: &str) -> bool;
fn ends_with_ci(&self, pattern: &str) -> bool;
fn ends_with_ci_alphanum(&self, pattern: &str) -> bool;
fn contains_ci(&self, pattern: &str) -> bool;
fn contains_ci_alphanum(&self, pattern: &str) -> bool;
}
impl SimpleMatch for str {
fn starts_with_ci(&self, pattern: &str) -> bool {
self.to_lowercase().starts_with(&pattern.to_lowercase())
}
fn starts_with_ci_alphanum(&self, pattern: &str) -> bool {
self.to_lowercase().strip_non_alphanum().starts_with(&pattern.to_lowercase())
}
fn ends_with_ci(&self, pattern: &str) -> bool {
self.to_lowercase().ends_with(&pattern.to_lowercase())
}
fn ends_with_ci_alphanum(&self, pattern: &str) -> bool {
self.to_lowercase().strip_non_alphanum().ends_with(&pattern.to_lowercase())
}
fn contains_ci(&self, pattern: &str) -> bool {
self.to_lowercase().contains(&pattern.to_lowercase())
}
fn contains_ci_alphanum(&self, pattern: &str) -> bool {
self.to_lowercase().strip_non_alphanum().contains(&pattern.to_lowercase())
}
}
pub trait MatchOccurrences {
fn find_matched_indices(&self, pat: &str) -> Vec<usize>;
fn find_char_indices(&self, pat: char) -> Vec<usize>;
}
impl MatchOccurrences for str {
fn find_matched_indices(&self, pat: &str) -> Vec<usize> {
self.match_indices(pat).into_iter().map(|pair| pair.0).collect::<Vec<usize>>()
}
fn find_char_indices(&self, pat: char) -> Vec<usize> {
self.match_indices(pat).into_iter().map(|pair| pair.0).collect::<Vec<usize>>()
}
}
pub trait SimpleMatchesMany where Self:SimpleMatch {
fn matched_conditional(&self, pattern_sets: &[StringBounds]) -> Vec<bool>;
fn matched_by_rules(&self, rules: &BoundsBuilder) -> Vec<bool> {
self.matched_conditional(&rules.as_vec())
}
fn contains_conditional(&self, pattern_sets: &[(&str, bool)]) -> Vec<bool> {
let pattern_sets: Vec<StringBounds> = pairs_to_string_bounds(pattern_sets, BoundsPosition::Contains);
self.matched_conditional(&pattern_sets)
}
fn contains_conditional_ci(&self, patterns: &[&str]) -> Vec<bool> {
let pattern_sets: Vec<StringBounds> = strs_to_string_bounds(patterns, CaseMatchMode::Insensitive, BoundsPosition::Contains);
self.matched_conditional(&pattern_sets)
}
fn contains_conditional_cs(&self, patterns: &[&str]) -> Vec<bool> {
let pattern_sets: Vec<StringBounds> = strs_to_string_bounds(patterns, CaseMatchMode::Sensitive, BoundsPosition::Contains);
self.matched_conditional(&pattern_sets)
}
}
pub(crate) fn match_bounds_rule(txt: &str, item: &StringBounds) -> bool {
let cm = item.case_mode();
let ci = item.case_insensitive();
let base = if ci {
match cm {
CaseMatchMode::AlphanumInsensitive => txt.to_lowercase().strip_non_alphanum(),
_ => txt.to_lowercase()
}
} else {
txt.to_owned()
};
let pattern = if ci {
item.pattern().to_lowercase()
} else {
item.pattern().to_owned()
};
let is_matched = if item.starts_with() {
base.starts_with(&pattern)
} else if item.ends_with() {
base.ends_with(&pattern)
} else if item.matches_whole() {
base == pattern
} else {
base.contains(&pattern)
} == item.is_positive();
is_matched
}
pub(crate) fn match_bound_rule_set(txt: &str, item: &StringBounds) -> bool {
match item {
StringBounds::And(inner_rules) => txt.matched_conditional(&inner_rules).into_iter().all(|result| result),
StringBounds::Or(inner_rules) => txt.matched_conditional(&inner_rules).into_iter().any(|result| result),
_ => match_bounds_rule(txt, item)
}
}
impl SimpleMatchesMany for str {
fn matched_conditional(&self, pattern_sets: &[StringBounds]) -> Vec<bool> {
let mut matched_items: Vec<bool> = Vec::with_capacity(pattern_sets.len());
for item in pattern_sets {
matched_items.push(match_bound_rule_set(self, item));
}
matched_items
}
}
pub trait SimpleMatchAll where Self:SimpleMatchesMany {
fn match_all_conditional(&self, pattern_sets: &[StringBounds]) -> bool;
fn contains_all_conditional(&self, pattern_sets: &[(&str, bool)]) -> bool {
let pattern_sets: Vec<StringBounds> = pairs_to_string_bounds(pattern_sets, BoundsPosition::Contains);
self.match_all_conditional(&pattern_sets)
}
fn contains_all_conditional_ci(&self, patterns: &[&str]) -> bool {
let pattern_sets: Vec<StringBounds> = strs_to_string_bounds(patterns, CaseMatchMode::Insensitive, BoundsPosition::Contains);
self.match_all_conditional(&pattern_sets)
}
fn contains_all_conditional_cs(&self, patterns: &[&str]) -> bool {
let pattern_sets: Vec<StringBounds> = strs_to_string_bounds(patterns, CaseMatchMode::Sensitive, BoundsPosition::Contains);
self.match_all_conditional(&pattern_sets)
}
}
impl SimpleMatchAll for str {
fn match_all_conditional(&self, pattern_sets: &[StringBounds]) -> bool {
if pattern_sets.len() > 0 {
for item in pattern_sets {
if !match_bound_rule_set(self, item) {
return false;
}
}
true
} else {
false
}
}
}
pub trait SimpleMatchAny where Self:SimpleMatchesMany {
fn match_any_conditional(&self, pattern_sets: &[StringBounds]) -> bool;
fn contains_any_conditional(&self, pattern_sets: &[(&str, bool)]) -> bool {
let pattern_sets: Vec<StringBounds> = pairs_to_string_bounds(pattern_sets, BoundsPosition::Contains);
self.match_any_conditional(&pattern_sets)
}
fn contains_any_conditional_ci(&self, patterns: &[&str]) -> bool {
let pattern_sets: Vec<StringBounds> = strs_to_string_bounds(patterns, CaseMatchMode::Insensitive, BoundsPosition::Contains);
self.match_any_conditional(&pattern_sets)
}
fn contains_any_conditional_cs(&self, patterns: &[&str]) -> bool {
let pattern_sets: Vec<StringBounds> = strs_to_string_bounds(patterns, CaseMatchMode::Sensitive, BoundsPosition::Contains);
self.match_any_conditional(&pattern_sets)
}
}
impl SimpleMatchAny for str {
fn match_any_conditional(&self, pattern_sets: &[StringBounds]) -> bool {
for item in pattern_sets {
if match_bound_rule_set(self, item) {
return true;
}
}
false
}
}
pub trait SimplContainsType where Self:SimpleMatch {
fn contains_type(&self, char_type: CharType) -> bool;
fn contains_types(&self, char_types: &[CharType]) -> bool;
fn starts_with_type(&self, char_type: CharType) -> bool;
fn starts_with_types(&self, char_types: &[CharType]) -> bool;
fn ends_with_type(&self, char_type: CharType) -> bool;
fn ends_with_types(&self, char_types: &[CharType]) -> bool;
}
impl SimplContainsType for str {
fn contains_type(&self, char_type: CharType) -> bool {
self.chars().any(|ch| char_type.is_in_range(&ch))
}
fn contains_types(&self, char_types: &[CharType]) -> bool {
self.chars().any(|ch| char_types.into_iter().any(|ct| ct.is_in_range(&ch)))
}
fn starts_with_type(&self, char_type: CharType) -> bool {
if let Some(first) = self.chars().nth(0) {
char_type.is_in_range(&first)
} else {
false
}
}
fn starts_with_types(&self, char_types: &[CharType]) -> bool {
if let Some(first) = self.chars().nth(0) {
char_types.into_iter().any(|ct| ct.is_in_range(&first))
} else {
false
}
}
fn ends_with_type(&self, char_type: CharType) -> bool {
if let Some(first) = self.chars().last() {
char_type.is_in_range(&first)
} else {
false
}
}
fn ends_with_types(&self, char_types: &[CharType]) -> bool {
if let Some(first) = self.chars().last() {
char_types.into_iter().any(|ct| ct.is_in_range(&first))
} else {
false
}
}
}
pub trait SimpleFilterAll<'a, T> {
fn filter_all_conditional(&'a self, pattern_sets: &[StringBounds]) -> Vec<T>;
fn filter_all_rules(&'a self, rules: &BoundsBuilder) -> Vec<T> {
self.filter_all_conditional(&rules.as_vec())
}
}
impl<'a> SimpleFilterAll<'a, &'a str> for [&str] {
fn filter_all_conditional(&'a self, pattern_sets: &[StringBounds]) -> Vec<&'a str> {
self.into_iter().map(|s| s.to_owned()).filter(|s| s.match_all_conditional(pattern_sets)).collect::<Vec<&'a str>>()
}
}
impl<'a> SimpleFilterAll<'a, String> for [String] {
fn filter_all_conditional(&'a self, pattern_sets: &[StringBounds]) -> Vec<String> {
self.into_iter().filter(|s| s.match_all_conditional(pattern_sets)).map(|s| s.to_owned()).collect::<Vec<String>>()
}
}
pub trait SimpleFilterAny<'a, T> {
fn filter_any_conditional(&'a self, pattern_sets: &[StringBounds]) -> Vec<T>;
fn filter_any_rules(&'a self, rules: &BoundsBuilder) -> Vec<T> {
self.filter_any_conditional(&rules.as_vec())
}
}
impl<'a> SimpleFilterAny<'a, &'a str> for [&str] {
fn filter_any_conditional(&'a self, pattern_sets: &[StringBounds]) -> Vec<&'a str> {
self.into_iter().map(|s| s.to_owned()).filter(|s| s.match_any_conditional(pattern_sets)).collect::<Vec<&'a str>>()
}
}
impl<'a> SimpleFilterAny<'a, String> for [String] {
fn filter_any_conditional(&'a self, pattern_sets: &[StringBounds]) -> Vec<String> {
self.into_iter().filter(|s| s.match_any_conditional(pattern_sets)).map(|s| s.to_owned()).collect::<Vec<String>>()
}
}