use crate::{
Node,
Pattern,
};
pub trait Filter<N> {
fn matches(&self, node: &N) -> bool;
}
impl<N> Filter<N> for () {
fn matches(&self, _: &N) -> bool {
true
}
}
pub struct And<A, B>(pub A, pub B);
impl<N, A, B> Filter<N> for And<A, B>
where
A: Filter<N>,
B: Filter<N>,
{
fn matches(&self, node: &N) -> bool {
self.0.matches(node) && self.1.matches(node)
}
}
pub struct Or<A, B>(pub A, pub B);
impl<N, A, B> Filter<N> for Or<A, B>
where
A: Filter<N>,
B: Filter<N>,
{
fn matches(&self, node: &N) -> bool {
self.0.matches(node) || self.1.matches(node)
}
}
pub struct Attr<N, V> {
pub name: N,
pub value: V,
}
impl<T, N, V> Filter<T> for Attr<N, V>
where
T: Node,
T::Text: Ord,
N: Pattern<T::Text>,
V: Pattern<T::Text>,
{
fn matches(&self, node: &T) -> bool {
if let Some(attrs) = node.attrs() {
if let Some(name) = self.name.value() {
if let Some(value) = attrs.get(&name) {
self.value.matches(value)
} else {
false
}
} else {
for (name, value) in attrs {
if self.name.matches(name) && self.value.matches(value) {
return true;
}
}
false
}
} else {
false
}
}
}
pub struct Tag<P> {
pub tag: P,
}
impl<N, P> Filter<N> for Tag<P>
where
N: Node,
P: Pattern<N::Text>,
{
fn matches(&self, node: &N) -> bool {
if let Some(name) = node.name() {
self.tag.matches(name)
} else {
false
}
}
}