select/
predicate.rs

1use crate::node::{self, Node};
2
3/// A trait implemented by all `Node` matchers.
4pub trait Predicate {
5    fn matches(&self, node: &Node) -> bool;
6    fn or<T: Predicate>(self, other: T) -> Or<Self, T>
7    where
8        Self: Sized,
9    {
10        Or(self, other)
11    }
12    fn and<T: Predicate>(self, other: T) -> And<Self, T>
13    where
14        Self: Sized,
15    {
16        And(self, other)
17    }
18    fn not(self) -> Not<Self>
19    where
20        Self: Sized,
21    {
22        Not(self)
23    }
24    fn child<T: Predicate>(self, other: T) -> Child<Self, T>
25    where
26        Self: Sized,
27    {
28        Child(self, other)
29    }
30    fn descendant<T: Predicate>(self, other: T) -> Descendant<Self, T>
31    where
32        Self: Sized,
33    {
34        Descendant(self, other)
35    }
36}
37
38/// Matches any Node.
39#[derive(Copy, Clone, Debug, PartialEq, Eq)]
40pub struct Any;
41
42impl Predicate for Any {
43    fn matches(&self, _: &Node) -> bool {
44        true
45    }
46}
47
48/// Matches Element Node with name `T`.
49#[derive(Copy, Clone, Debug, PartialEq, Eq)]
50pub struct Name<T>(pub T);
51
52impl<'a> Predicate for Name<&'a str> {
53    fn matches(&self, node: &Node) -> bool {
54        node.name() == Some(self.0)
55    }
56}
57
58/// Matches Element Node containing class `T`.
59#[derive(Copy, Clone, Debug, PartialEq, Eq)]
60pub struct Class<T>(pub T);
61
62impl<'a> Predicate for Class<&'a str> {
63    fn matches(&self, node: &Node) -> bool {
64        node.attr("class").map_or(false, |classes| {
65            classes.split_whitespace().any(|class| class == self.0)
66        })
67    }
68}
69
70/// Matches if the Predicate `T` does not match.
71#[derive(Copy, Clone, Debug, PartialEq, Eq)]
72pub struct Not<T>(pub T);
73
74impl<T: Predicate> Predicate for Not<T> {
75    fn matches(&self, node: &Node) -> bool {
76        !self.0.matches(node)
77    }
78}
79
80/// Matches Element Node containing attribute `N` with value `V` if `V` is an
81/// `&str`, or any value if `V` is `()`.
82#[derive(Copy, Clone, Debug, PartialEq, Eq)]
83pub struct Attr<N, V>(pub N, pub V);
84
85impl<'a> Predicate for Attr<&'a str, &'a str> {
86    fn matches(&self, node: &Node) -> bool {
87        node.attr(self.0) == Some(self.1)
88    }
89}
90
91impl<'a> Predicate for Attr<&'a str, ()> {
92    fn matches(&self, node: &Node) -> bool {
93        node.attr(self.0).is_some()
94    }
95}
96
97/// Matches if the function returns true.
98impl<F: Fn(&Node) -> bool> Predicate for F {
99    fn matches(&self, node: &Node) -> bool {
100        self(node)
101    }
102}
103
104/// Matches any Element Node.
105#[derive(Copy, Clone, Debug, PartialEq, Eq)]
106pub struct Element;
107
108impl Predicate for Element {
109    fn matches(&self, node: &Node) -> bool {
110        matches!(*node.data(), node::Data::Element(..))
111    }
112}
113
114/// Matches any Text Node.
115#[derive(Copy, Clone, Debug, PartialEq, Eq)]
116pub struct Text;
117
118impl Predicate for Text {
119    fn matches(&self, node: &Node) -> bool {
120        matches!(*node.data(), node::Data::Text(..))
121    }
122}
123
124/// Matches any Comment Node.
125#[derive(Copy, Clone, Debug, PartialEq, Eq)]
126pub struct Comment;
127
128impl Predicate for Comment {
129    fn matches(&self, node: &Node) -> bool {
130        matches!(*node.data(), node::Data::Comment(..))
131    }
132}
133
134/// Matches if either inner Predicate `A` or `B` matches the Node.
135#[derive(Copy, Clone, Debug, PartialEq, Eq)]
136pub struct Or<A, B>(pub A, pub B);
137
138impl<A: Predicate, B: Predicate> Predicate for Or<A, B> {
139    fn matches(&self, node: &Node) -> bool {
140        self.0.matches(node) || self.1.matches(node)
141    }
142}
143
144/// Matches if the inner Predicate `A` and `B` both match the Node.
145#[derive(Copy, Clone, Debug, PartialEq, Eq)]
146pub struct And<A, B>(pub A, pub B);
147
148impl<A: Predicate, B: Predicate> Predicate for And<A, B> {
149    fn matches(&self, node: &Node) -> bool {
150        self.0.matches(node) && self.1.matches(node)
151    }
152}
153
154/// Matches if inner Predicate `B` matches the node and `A` matches the parent
155/// of the node.
156#[derive(Copy, Clone, Debug, PartialEq, Eq)]
157pub struct Child<A, B>(pub A, pub B);
158
159impl<A: Predicate, B: Predicate> Predicate for Child<A, B> {
160    fn matches(&self, node: &Node) -> bool {
161        if let Some(parent) = node.parent() {
162            self.1.matches(node) && self.0.matches(&parent)
163        } else {
164            false
165        }
166    }
167}
168
169/// Matches if inner Predicate `B` matches the node and `A` matches any of the
170/// parents of node.
171#[derive(Copy, Clone, Debug, PartialEq, Eq)]
172pub struct Descendant<A, B>(pub A, pub B);
173
174impl<A: Predicate, B: Predicate> Predicate for Descendant<A, B> {
175    fn matches(&self, node: &Node) -> bool {
176        if self.1.matches(node) {
177            let mut node = *node;
178            while let Some(parent) = node.parent() {
179                if self.0.matches(&parent) {
180                    return true;
181                }
182                node = parent;
183            }
184        }
185        false
186    }
187}