1use crate::node::{self, Node};
2
3pub 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#[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#[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#[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#[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#[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
97impl<F: Fn(&Node) -> bool> Predicate for F {
99 fn matches(&self, node: &Node) -> bool {
100 self(node)
101 }
102}
103
104#[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#[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#[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#[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#[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#[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#[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}