use super::{
document::Document,
element::Element,
node::{Node, NodeData, NodeId},
selectors::{ParseError, Selectors},
Specificity,
};
use std::iter::{Enumerate, Skip};
#[inline]
pub(crate) fn select<'a, 'b>(
document: &'a Document,
selectors: &'b str,
) -> Result<Select<'a>, ParseError<'b>> {
Selectors::compile(selectors).map(|selectors| Select {
elements: Elements {
document,
iter: document.nodes.iter().enumerate().skip(2),
},
selectors,
})
}
struct Elements<'a> {
document: &'a Document,
iter: Skip<Enumerate<std::slice::Iter<'a, Node>>>,
}
impl<'a> Iterator for Elements<'a> {
type Item = Element<'a>;
fn next(&mut self) -> Option<Self::Item> {
loop {
if let Some((id, node)) = self.iter.next() {
if let NodeData::Element { element, .. } = &node.data {
return Some(Element::new(self.document, NodeId::new(id), element));
}
} else {
return None;
}
}
}
}
pub(crate) struct Select<'a> {
elements: Elements<'a>,
selectors: Selectors,
}
impl<'a> Select<'a> {
#[inline]
pub(crate) fn specificity(&self) -> Specificity {
Specificity::new(self.selectors.0[0].specificity())
}
}
impl<'a> Iterator for Select<'a> {
type Item = Element<'a>;
#[inline]
fn next(&mut self) -> Option<Element<'a>> {
for element in self.elements.by_ref() {
for selector in self.selectors.iter() {
if element.matches(selector) {
return Some(element);
}
}
}
None
}
}