whereexpr 0.1.4

A fast, expressive rule-based filtering engine for Rust that evaluates boolean expressions over any data structure
Documentation
use aho_corasick::{AhoCorasick, AhoCorasickBuilder, MatchKind};
use crate::{Error, Operation, Value, ValueKind};

use super::lower_case_builder::LowerCaseBuilder;

#[derive(Debug)]
pub(crate) struct ContainsOneOf {
    ac: AhoCorasick,
    ignore_case: bool,
}

impl ContainsOneOf {
    pub(crate) fn with_str_list(list: &[&str], ignore_case: bool) -> Result<Self, Error> {
        let ac = if ignore_case {
            // Normalize patterns to lowercase once at build time
            let lowered: Vec<String> = list.iter().map(|s| s.to_lowercase()).collect();
            AhoCorasickBuilder::new().match_kind(MatchKind::LeftmostFirst).build(&lowered)
        } else {
            AhoCorasickBuilder::new().match_kind(MatchKind::LeftmostFirst).build(list)
        };
        match ac {
            Ok(ac) => Ok(Self { ac, ignore_case }),
            Err(e) => Err(Error::FailToBuildInternalDataStructure(Operation::ContainsOneOf, ValueKind::String, e.to_string())),
        }
    }
    pub(crate) fn with_value_list(list: &[Value<'_>]) -> Result<Self, Error>
    {
        let mut input_list: Vec<&str> = Vec::with_capacity(list.len());
        for value in list {
            match value {
                Value::String(s) => input_list.push(s),
                _ => return Err(Error::ExpectingADifferentValueKind(value.kind(), ValueKind::String)),
            }
        }
        match AhoCorasickBuilder::new().match_kind(MatchKind::LeftmostFirst).build(input_list) {
            Ok(ac) => Ok(Self { ac, ignore_case: false }),
            Err(e) => Err(Error::FailToBuildInternalDataStructure(Operation::ContainsOneOf, ValueKind::String, e.to_string())),
        }
    }
    pub(crate) fn evaluate(&self, value: &str) -> bool {
        if self.ignore_case {
            let lower_case = LowerCaseBuilder::<2048>::new(value);
            self.ac.is_match(lower_case.as_str())
        } else {
            self.ac.is_match(value)
        }
    }
}