Skip to main content

tl/queryselector/
iterable.rs

1use crate::{HTMLTag, InnerNodeHandle, Node, NodeHandle, Parser, VDom};
2
3mod private {
4    pub trait Sealed {}
5}
6
7/// Trait for types that a query selector can iterate over
8pub trait QueryIterable<
9    'a,
10    const MAX_NODES: usize = 0,
11    const MAX_STACK: usize = 0,
12    const MAX_ROOTS: usize = 0,
13    const MAX_IDS: usize = 0,
14    const MAX_CLASSES: usize = 0,
15    const MAX_SELECTOR_NODES: usize = 0,
16>: private::Sealed
17{
18    /// Gets a node at a specific index
19    fn get<'b>(
20        &'b self,
21        parser: &'b Parser<
22            'a,
23            MAX_NODES,
24            MAX_STACK,
25            MAX_ROOTS,
26            MAX_IDS,
27            MAX_CLASSES,
28            MAX_SELECTOR_NODES,
29        >,
30        index: usize,
31    ) -> Option<(&'b Node<'a>, NodeHandle)>;
32    /// Gets or computes the length (number of nodes)
33    fn len(
34        &self,
35        parser: &Parser<
36            'a,
37            MAX_NODES,
38            MAX_STACK,
39            MAX_ROOTS,
40            MAX_IDS,
41            MAX_CLASSES,
42            MAX_SELECTOR_NODES,
43        >,
44    ) -> usize;
45    /// Gets the starting index
46    fn start(&self) -> Option<InnerNodeHandle>;
47}
48
49impl<
50    'a,
51    const MAX_NODES: usize,
52    const MAX_STACK: usize,
53    const MAX_ROOTS: usize,
54    const MAX_IDS: usize,
55    const MAX_CLASSES: usize,
56    const MAX_SELECTOR_NODES: usize,
57> private::Sealed
58    for VDom<'a, MAX_NODES, MAX_STACK, MAX_ROOTS, MAX_IDS, MAX_CLASSES, MAX_SELECTOR_NODES>
59{
60}
61impl<
62    'a,
63    const MAX_NODES: usize,
64    const MAX_STACK: usize,
65    const MAX_ROOTS: usize,
66    const MAX_IDS: usize,
67    const MAX_CLASSES: usize,
68    const MAX_SELECTOR_NODES: usize,
69> QueryIterable<'a, MAX_NODES, MAX_STACK, MAX_ROOTS, MAX_IDS, MAX_CLASSES, MAX_SELECTOR_NODES>
70    for VDom<'a, MAX_NODES, MAX_STACK, MAX_ROOTS, MAX_IDS, MAX_CLASSES, MAX_SELECTOR_NODES>
71{
72    #[inline]
73    fn get<'b>(
74        &'b self,
75        parser: &'b Parser<
76            'a,
77            MAX_NODES,
78            MAX_STACK,
79            MAX_ROOTS,
80            MAX_IDS,
81            MAX_CLASSES,
82            MAX_SELECTOR_NODES,
83        >,
84        index: usize,
85    ) -> Option<(&'b Node<'a>, NodeHandle)> {
86        // In a VDom, the index is equal to the node's id
87        // and as such, we can recreate a `NodeHandle` from that ID
88        parser
89            .tags
90            .as_slice()
91            .get(index)
92            .map(|node| (node, NodeHandle::new(index as u32)))
93    }
94
95    #[inline]
96    fn len(
97        &self,
98        _parser: &Parser<
99            'a,
100            MAX_NODES,
101            MAX_STACK,
102            MAX_ROOTS,
103            MAX_IDS,
104            MAX_CLASSES,
105            MAX_SELECTOR_NODES,
106        >,
107    ) -> usize {
108        self.parser().tags.len()
109    }
110
111    #[inline]
112    fn start(&self) -> Option<InnerNodeHandle> {
113        // The starting ID is always 0 in a VDom
114        Some(0)
115    }
116}
117
118impl<'a> private::Sealed for HTMLTag<'a> {}
119impl<
120    'a,
121    const MAX_NODES: usize,
122    const MAX_STACK: usize,
123    const MAX_ROOTS: usize,
124    const MAX_IDS: usize,
125    const MAX_CLASSES: usize,
126    const MAX_SELECTOR_NODES: usize,
127> QueryIterable<'a, MAX_NODES, MAX_STACK, MAX_ROOTS, MAX_IDS, MAX_CLASSES, MAX_SELECTOR_NODES>
128    for HTMLTag<'a>
129{
130    #[inline]
131    fn get<'b>(
132        &'b self,
133        parser: &'b Parser<
134            'a,
135            MAX_NODES,
136            MAX_STACK,
137            MAX_ROOTS,
138            MAX_IDS,
139            MAX_CLASSES,
140            MAX_SELECTOR_NODES,
141        >,
142        index: usize,
143    ) -> Option<(&'b Node<'a>, NodeHandle)> {
144        // Add `index` to the starting ID to get the ID of the node we need
145        let index = self.children().start().map(|h| h as usize + index)?;
146        let handle = NodeHandle::new(index as u32);
147        let node = parser.tags.get(index)?;
148        Some((node, handle))
149    }
150
151    #[inline]
152    fn len(
153        &self,
154        parser: &Parser<
155            'a,
156            MAX_NODES,
157            MAX_STACK,
158            MAX_ROOTS,
159            MAX_IDS,
160            MAX_CLASSES,
161            MAX_SELECTOR_NODES,
162        >,
163    ) -> usize {
164        if let Some((start, end)) = self.children().boundaries(parser) {
165            ((end - start) + 1) as usize
166        } else {
167            0
168        }
169    }
170
171    #[inline]
172    fn start(&self) -> Option<InnerNodeHandle> {
173        self.children().start()
174    }
175}