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<'a>: private::Sealed {
9    /// Gets a node at a specific index
10    fn get<'b>(
11        &'b self,
12        parser: &'b Parser<'a>,
13        index: usize,
14    ) -> Option<(&'b Node<'a>, NodeHandle)>;
15    /// Gets or computes the length (number of nodes)
16    fn len(&self, parser: &Parser) -> usize;
17    /// Gets the starting index
18    fn start(&self) -> Option<InnerNodeHandle>;
19}
20
21impl<'a> private::Sealed for VDom<'a> {}
22impl<'a> QueryIterable<'a> for VDom<'a> {
23    #[inline]
24    fn get<'b>(
25        &'b self,
26        parser: &'b Parser<'a>,
27        index: usize,
28    ) -> Option<(&'b Node<'a>, NodeHandle)> {
29        // In a VDom, the index is equal to the node's id
30        // and as such, we can recreate a `NodeHandle` from that ID
31        parser
32            .tags
33            .get(index)
34            .map(|node| (node, NodeHandle::new(index as u32)))
35    }
36
37    #[inline]
38    fn len(&self, _parser: &Parser) -> usize {
39        self.parser().tags.len()
40    }
41
42    #[inline]
43    fn start(&self) -> Option<InnerNodeHandle> {
44        // The starting ID is always 0 in a VDom
45        Some(0)
46    }
47}
48
49impl<'a> private::Sealed for HTMLTag<'a> {}
50impl<'a> QueryIterable<'a> for HTMLTag<'a> {
51    #[inline]
52    fn get<'b>(
53        &'b self,
54        parser: &'b Parser<'a>,
55        index: usize,
56    ) -> Option<(&'b Node<'a>, NodeHandle)> {
57        // Add `index` to the starting ID to get the ID of the node we need
58        let index = self.start().map(|h| h as usize + index)?;
59        let handle = NodeHandle::new(index as u32);
60        let node = parser.tags.get(index)?;
61        Some((node, handle))
62    }
63
64    #[inline]
65    fn len(&self, parser: &Parser) -> usize {
66        if let Some((start, end)) = self.children().boundaries(parser) {
67            ((end - start) + 1) as usize
68        } else {
69            0
70        }
71    }
72
73    #[inline]
74    fn start(&self) -> Option<InnerNodeHandle> {
75        self.children().start()
76    }
77}