1use rustc_hash::FxHashSet;
4
5use crate::{
6 node::{
7 ElementNode,
8 FromAnyValue,
9 NodeType,
10 OwnedAttributeView,
11 },
12 prelude::AttributeName,
13 tags::TagName,
14 NodeId,
15};
16
17#[derive(Debug)]
19pub struct NodeView<'a, V: FromAnyValue = ()> {
20 id: NodeId,
21 inner: &'a NodeType<V>,
22 mask: &'a NodeMask,
23 height: u16,
24}
25
26impl<'a, V: FromAnyValue> NodeView<'a, V> {
27 pub fn new(id: NodeId, node: &'a NodeType<V>, view: &'a NodeMask, height: u16) -> Self {
29 Self {
30 inner: node,
31 mask: view,
32 id,
33 height,
34 }
35 }
36
37 pub fn node_type(&self) -> &'a NodeType<V> {
38 self.inner
39 }
40
41 pub fn node_id(&self) -> NodeId {
43 self.id
44 }
45
46 pub fn height(&self) -> u16 {
48 self.height
49 }
50
51 pub fn tag(&self) -> Option<&'a TagName> {
53 self.mask
54 .tag
55 .then_some(match &self.inner {
56 NodeType::Element(ElementNode { tag, .. }) => Some(tag),
57 _ => None,
58 })
59 .flatten()
60 }
61
62 pub fn attributes<'b>(
64 &'b self,
65 ) -> Option<impl Iterator<Item = OwnedAttributeView<'a, V>> + 'b> {
66 match &self.inner {
67 NodeType::Element(ElementNode { attributes, .. }) => Some(
68 attributes
69 .iter()
70 .filter(move |(attr, _)| self.mask.attritutes.contains(attr))
71 .map(|(attr, val)| OwnedAttributeView {
72 attribute: attr,
73 value: val,
74 }),
75 ),
76 _ => None,
77 }
78 }
79
80 pub fn text(&self) -> Option<&str> {
82 self.mask.text.then_some(self.inner.text()).flatten()
83 }
84}
85
86#[derive(PartialEq, Eq, Clone, Debug)]
88pub enum AttributeMask {
89 All,
91 Some(FxHashSet<AttributeName>),
93}
94
95impl AttributeMask {
96 pub fn contains(&self, attr: &AttributeName) -> bool {
98 match self {
99 AttributeMask::All => true,
100 AttributeMask::Some(attrs) => attrs.contains(attr),
101 }
102 }
103
104 pub fn union(&self, other: &Self) -> Self {
106 match (self, other) {
107 (AttributeMask::Some(s), AttributeMask::Some(o)) => {
108 AttributeMask::Some(s.union(o).cloned().collect())
109 }
110 _ => AttributeMask::All,
111 }
112 }
113
114 fn overlaps(&self, other: &Self) -> bool {
116 match (self, other) {
117 (AttributeMask::All, AttributeMask::Some(attrs)) => !attrs.is_empty(),
118 (AttributeMask::Some(attrs), AttributeMask::All) => !attrs.is_empty(),
119 (AttributeMask::Some(attrs1), AttributeMask::Some(attrs2)) => {
120 !attrs1.is_disjoint(attrs2)
121 }
122 _ => true,
123 }
124 }
125}
126
127impl Default for AttributeMask {
128 fn default() -> Self {
129 AttributeMask::Some(FxHashSet::default())
130 }
131}
132
133#[derive(Default, PartialEq, Eq, Clone, Debug)]
135pub struct NodeMask {
136 attritutes: AttributeMask,
137 tag: bool,
138 text: bool,
139 listeners: bool,
140}
141
142impl NodeMask {
143 pub fn overlaps(&self, other: &Self) -> bool {
145 (self.tag && other.tag)
146 || self.attritutes.overlaps(&other.attritutes)
147 || (self.text && other.text)
148 || (self.listeners && other.listeners)
149 }
150
151 pub fn union(&self, other: &Self) -> Self {
153 Self {
154 attritutes: self.attritutes.union(&other.attritutes),
155 tag: self.tag | other.tag,
156 text: self.text | other.text,
157 listeners: self.listeners | other.listeners,
158 }
159 }
160
161 pub fn add_attributes(&mut self, attributes: AttributeMask) {
163 self.attritutes = self.attritutes.union(&attributes);
164 }
165
166 pub fn attributes(&self) -> &AttributeMask {
168 &self.attritutes
169 }
170
171 pub fn set_tag(&mut self) {
173 self.tag = true;
174 }
175
176 pub fn tag(&self) -> bool {
178 self.tag
179 }
180
181 pub fn set_text(&mut self) {
183 self.text = true;
184 }
185
186 pub fn text(&self) -> bool {
188 self.text
189 }
190
191 pub fn set_listeners(&mut self) {
193 self.listeners = true;
194 }
195
196 pub fn listeners(&self) -> bool {
198 self.listeners
199 }
200}
201
202#[derive(PartialEq, Eq, Clone, Debug)]
204pub enum AttributeMaskBuilder<'a> {
205 All,
207 Some(&'a [AttributeName]),
209}
210
211impl Default for AttributeMaskBuilder<'_> {
212 fn default() -> Self {
213 AttributeMaskBuilder::Some(&[])
214 }
215}
216
217#[derive(Default, PartialEq, Eq, Clone, Debug)]
219pub struct NodeMaskBuilder<'a> {
220 attritutes: AttributeMaskBuilder<'a>,
221 tag: bool,
222 text: bool,
223 listeners: bool,
224}
225
226impl<'a> NodeMaskBuilder<'a> {
227 pub const NONE: Self = Self::new();
229 pub const ALL: Self = Self::new()
231 .with_attrs(AttributeMaskBuilder::All)
232 .with_text()
233 .with_tag()
234 .with_listeners();
235
236 pub const fn new() -> Self {
238 Self {
239 attritutes: AttributeMaskBuilder::Some(&[]),
240 tag: false,
241 text: false,
242 listeners: false,
243 }
244 }
245
246 pub const fn with_attrs(mut self, attritutes: AttributeMaskBuilder<'a>) -> Self {
248 self.attritutes = attritutes;
249 self
250 }
251
252 pub const fn with_tag(mut self) -> Self {
254 self.tag = true;
255 self
256 }
257
258 pub const fn with_text(mut self) -> Self {
260 self.text = true;
261 self
262 }
263
264 pub const fn with_listeners(mut self) -> Self {
266 self.listeners = true;
267 self
268 }
269
270 pub fn build(self) -> NodeMask {
272 NodeMask {
273 attritutes: match self.attritutes {
274 AttributeMaskBuilder::All => AttributeMask::All,
275 AttributeMaskBuilder::Some(attrs) => {
276 AttributeMask::Some(FxHashSet::from_iter(attrs.iter().copied()))
277 }
278 },
279 tag: self.tag,
280 text: self.text,
281 listeners: self.listeners,
282 }
283 }
284}