use regex::Regex;
use crate::util::split_vec::SplitVec;
pub(crate) enum Filter {
Regex(Regex),
Exact(String),
}
impl Filter {
fn is_match(&self, s: &str) -> bool {
match self {
Self::Regex(regex) => regex.is_match(s),
Self::Exact(exact) => exact == s,
}
}
}
#[derive(Default)]
pub(crate) struct FilterSet {
filters: SplitVec<Filter>,
}
impl FilterSet {
#[inline]
pub fn reserve_exact(&mut self, additional: usize) {
self.filters.reserve_exact(additional);
}
pub fn insert(&mut self, filter: Filter, positive: bool) {
self.filters.insert(filter, positive);
}
pub fn is_match(&self, entry_path: &str) -> bool {
let filters = self.filters.all();
let positive_start = self.filters.split_index();
if let Some(index) = filters.iter().position(|f| f.is_match(entry_path)) {
return index >= positive_start;
}
filters.len() == positive_start
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn empty() {
let filters = FilterSet::default();
assert!(filters.is_match("abc"));
assert!(filters.is_match("123"));
}
mod single {
use super::*;
#[test]
fn positive_exact() {
let mut filters = FilterSet::default();
filters.insert(Filter::Exact("abc".into()), true);
assert!(filters.is_match("abc"));
assert!(!filters.is_match("ab"));
assert!(!filters.is_match("abcd"));
}
#[test]
fn negative_exact() {
let mut filters = FilterSet::default();
filters.insert(Filter::Exact("abc".into()), false);
assert!(!filters.is_match("abc"));
assert!(filters.is_match("ab"));
assert!(filters.is_match("abcd"));
}
#[test]
fn positive_regex() {
let mut filters = FilterSet::default();
let regex = Regex::new("abc.*123").unwrap();
filters.insert(Filter::Regex(regex), true);
assert!(!filters.is_match("abc"));
assert!(filters.is_match("abc123"));
assert!(filters.is_match("abc::123"));
}
#[test]
fn negative_regex() {
let mut filters = FilterSet::default();
let regex = Regex::new("abc.*123").unwrap();
filters.insert(Filter::Regex(regex), false);
assert!(filters.is_match("abc"));
assert!(!filters.is_match("abc123"));
assert!(!filters.is_match("abc::123"));
}
}
mod multi {
use super::*;
#[test]
fn exact() {
let mut filters = FilterSet::default();
filters.insert(Filter::Exact("abc".into()), true);
filters.insert(Filter::Exact("123".into()), true);
assert!(filters.is_match("abc"));
assert!(filters.is_match("123"));
assert!(!filters.is_match("xyz"));
}
}
mod overridden {
use super::*;
#[test]
fn exact() {
let mut filters = FilterSet::default();
filters.insert(Filter::Exact("abc".into()), true);
filters.insert(Filter::Exact("abc".into()), false);
assert!(!filters.is_match("abc"));
}
#[test]
fn regex() {
let mut filters = FilterSet::default();
let regex = Regex::new("abc.*123").unwrap();
filters.insert(Filter::Regex(regex.clone()), true);
filters.insert(Filter::Regex(regex), false);
assert!(!filters.is_match("abc::123"));
assert!(!filters.is_match("123::abc"));
}
}
}