use super::{
document::Document,
element::Element,
node::{NodeData, NodeId},
selectors::{ParseError, Selectors},
Specificity,
};
use selectors::NthIndexCache;
use std::iter::Zip;
#[inline]
pub(crate) fn select<'a, 'b, 'c>(
document: &'a Document,
selectors: &'b str,
caches: &'c mut [NthIndexCache],
) -> Result<Select<'a, 'c>, ParseError<'b>> {
Selectors::compile(selectors).map(|selectors| Select {
document,
iter: document.elements.iter().zip(caches.iter_mut()),
selectors,
})
}
pub(crate) struct Select<'a, 'c> {
document: &'a Document,
iter: Zip<std::slice::Iter<'a, NodeId>, std::slice::IterMut<'c, NthIndexCache>>,
selectors: Selectors,
}
impl<'a, 'c> Select<'a, 'c> {
#[inline]
pub(crate) fn specificity(&self) -> Specificity {
Specificity::new(self.selectors.0[0].specificity())
}
}
impl<'a, 'c> Iterator for Select<'a, 'c> {
type Item = Element<'a>;
#[inline]
fn next(&mut self) -> Option<Element<'a>> {
for (element_id, cache) in self.iter.by_ref() {
let NodeData::Element { element, .. } = &self.document[*element_id].data else {
unreachable!("Element ids always point to element nodes")
};
let element = Element::new(self.document, *element_id, element);
for selector in self.selectors.iter() {
if element.matches(selector, cache) {
return Some(element);
}
}
}
None
}
}