use std::{fmt, marker::PhantomData};
use super::{BooleanType, Filter, QueryNode, Resolver};
use crate::path::PathParseError;
use dyn_clone::{DynClone, clone_trait_object};
pub trait Matcher<V>: DynClone + fmt::Debug + Send + Sync {
fn run(&self, value: &V) -> bool;
}
clone_trait_object!(<V>Matcher<V>);
impl<V> Matcher<V> for bool {
fn run(&self, _value: &V) -> bool {
*self
}
}
#[derive(Clone)]
pub struct Run<V, T>
where
V: fmt::Debug + Send + Sync + Clone,
T: Fn(&V) -> bool + Send + Sync + Clone,
{
func: T,
_phantom: PhantomData<V>, }
impl<V, T> Run<V, T>
where
V: fmt::Debug + Send + Sync + Clone,
T: Fn(&V) -> bool + Send + Sync + Clone,
{
pub fn boxed(func: T) -> Box<Self> {
Box::new(Self {
func,
_phantom: PhantomData,
})
}
}
impl<V, T> Matcher<V> for Run<V, T>
where
V: fmt::Debug + Send + Sync + Clone,
T: Fn(&V) -> bool + Send + Sync + Clone,
{
fn run(&self, obj: &V) -> bool {
(self.func)(obj)
}
}
impl<V, T> fmt::Debug for Run<V, T>
where
V: fmt::Debug + Send + Sync + Clone,
T: Fn(&V) -> bool + Send + Sync + Clone,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "Datadog matcher fn")
}
}
fn not<V>(matcher: Box<dyn Matcher<V>>) -> Box<dyn Matcher<V>>
where
V: fmt::Debug + Send + Sync + Clone + 'static,
{
Run::boxed(move |value| !matcher.run(value))
}
fn any<V>(matchers: Vec<Box<dyn Matcher<V>>>) -> Box<dyn Matcher<V>>
where
V: fmt::Debug + Send + Sync + Clone + 'static,
{
Run::boxed(move |value| matchers.iter().any(|func| func.run(value)))
}
fn all<V>(matchers: Vec<Box<dyn Matcher<V>>>) -> Box<dyn Matcher<V>>
where
V: fmt::Debug + Send + Sync + Clone + 'static,
{
Run::boxed(move |value| matchers.iter().all(|func| func.run(value)))
}
pub fn build_matcher<V, F>(
node: &QueryNode,
filter: &F,
) -> Result<Box<dyn Matcher<V>>, PathParseError>
where
V: fmt::Debug + Send + Sync + Clone + 'static,
F: Filter<V> + Resolver,
{
node.build_matcher(filter)
}
impl QueryNode {
#[allow(clippy::module_name_repetitions)] pub fn build_matcher<V, F>(&self, filter: &F) -> Result<Box<dyn Matcher<V>>, PathParseError>
where
V: fmt::Debug + Send + Sync + Clone + 'static,
F: Filter<V> + Resolver,
{
match self {
Self::MatchNoDocs => Ok(Box::new(false)),
Self::MatchAllDocs => Ok(Box::new(true)),
Self::AttributeExists { attr } => {
let matchers: Result<Vec<_>, _> = filter
.build_fields(attr)
.into_iter()
.map(|field| filter.exists(field))
.collect();
Ok(any(matchers?))
}
Self::AttributeMissing { attr } => {
let matchers: Result<Vec<_>, _> = filter
.build_fields(attr)
.into_iter()
.map(|field| filter.exists(field).map(|matcher| not(matcher)))
.collect();
Ok(all(matchers?))
}
Self::AttributeTerm { attr, value }
| Self::QuotedAttribute {
attr,
phrase: value,
} => {
let matchers: Result<Vec<_>, _> = filter
.build_fields(attr)
.into_iter()
.map(|field| filter.equals(field, value))
.collect();
Ok(any(matchers?))
}
Self::AttributePrefix { attr, prefix } => {
let matchers: Result<Vec<_>, _> = filter
.build_fields(attr)
.into_iter()
.map(|field| filter.prefix(field, prefix))
.collect();
Ok(any(matchers?))
}
Self::AttributeWildcard { attr, wildcard } => {
let matchers: Result<Vec<_>, _> = filter
.build_fields(attr)
.into_iter()
.map(|field| filter.wildcard(field, wildcard))
.collect();
Ok(any(matchers?))
}
Self::AttributeComparison {
attr,
comparator,
value,
} => {
let matchers: Result<Vec<_>, _> = filter
.build_fields(attr)
.into_iter()
.map(|field| filter.compare(field, *comparator, value.clone()))
.collect();
Ok(any(matchers?))
}
Self::AttributeRange {
attr,
lower,
lower_inclusive,
upper,
upper_inclusive,
} => {
let matchers: Result<Vec<_>, _> = filter
.build_fields(attr)
.into_iter()
.map(|field| {
filter.range(
field,
lower.clone(),
*lower_inclusive,
upper.clone(),
*upper_inclusive,
)
})
.collect();
Ok(any(matchers?))
}
Self::NegatedNode { node } => Ok(not(node.build_matcher(filter)?)),
Self::Boolean { oper, nodes } => {
let funcs: Result<Vec<_>, _> = nodes
.iter()
.map(|node| node.build_matcher(filter))
.collect();
match oper {
BooleanType::And => Ok(all(funcs?)),
BooleanType::Or => Ok(any(funcs?)),
}
}
}
}
}