//! Node iterators use std::borrow::Borrow; use std::cell::RefCell; use std::iter::Rev; use crate::node_data_ref::NodeDataRef; use crate::select::Selectors; use crate::tree::{ElementData, NodeRef}; impl NodeRef { /// Return an iterator of references to this node and its ancestors. #[inline] pub fn inclusive_ancestors(&self) -> Ancestors { Ancestors(Some(self.clone())) } /// Return an iterator of references to this node’s ancestors. #[inline] pub fn ancestors(&self) -> Ancestors { Ancestors(self.parent()) } /// Return an iterator of references to this node and the siblings before it. #[inline] pub fn inclusive_preceding_siblings(&self) -> Rev { match self.parent() { Some(parent) => { let first_sibling = parent.first_child().unwrap(); debug_assert!(self.previous_sibling().is_some() || *self == first_sibling); Siblings(Some(State { next: first_sibling, next_back: self.clone(), })) } None => { debug_assert!(self.previous_sibling().is_none()); Siblings(Some(State { next: self.clone(), next_back: self.clone(), })) } } .rev() } /// Return an iterator of references to this node’s siblings before it. #[inline] pub fn preceding_siblings(&self) -> Rev { match (self.parent(), self.previous_sibling()) { (Some(parent), Some(previous_sibling)) => { let first_sibling = parent.first_child().unwrap(); Siblings(Some(State { next: first_sibling, next_back: previous_sibling, })) } _ => Siblings(None), } .rev() } /// Return an iterator of references to this node and the siblings after it. #[inline] pub fn inclusive_following_siblings(&self) -> Siblings { match self.parent() { Some(parent) => { let last_sibling = parent.last_child().unwrap(); debug_assert!(self.next_sibling().is_some() || *self == last_sibling); Siblings(Some(State { next: self.clone(), next_back: last_sibling, })) } None => { debug_assert!(self.next_sibling().is_none()); Siblings(Some(State { next: self.clone(), next_back: self.clone(), })) } } } /// Return an iterator of references to this node’s siblings after it. #[inline] pub fn following_siblings(&self) -> Siblings { match (self.parent(), self.next_sibling()) { (Some(parent), Some(next_sibling)) => { let last_sibling = parent.last_child().unwrap(); Siblings(Some(State { next: next_sibling, next_back: last_sibling, })) } _ => Siblings(None), } } /// Return an iterator of references to this node’s children. #[inline] pub fn children(&self) -> Siblings { match (self.first_child(), self.last_child()) { (Some(first_child), Some(last_child)) => Siblings(Some(State { next: first_child, next_back: last_child, })), (None, None) => Siblings(None), _ => unreachable!(), } } /// Return an iterator of references to this node and its descendants, in tree order. /// /// Parent nodes appear before the descendants. /// /// Note: this is the `NodeEdge::Start` items from `traverse()`. #[inline] pub fn inclusive_descendants(&self) -> Descendants { Descendants(self.traverse_inclusive()) } /// Return an iterator of references to this node’s descendants, in tree order. /// /// Parent nodes appear before the descendants. /// /// Note: this is the `NodeEdge::Start` items from `traverse()`. #[inline] pub fn descendants(&self) -> Descendants { Descendants(self.traverse()) } /// Return an iterator of the start and end edges of this node and its descendants, /// in tree order. #[inline] pub fn traverse_inclusive(&self) -> Traverse { Traverse(Some(State { next: NodeEdge::Start(self.clone()), next_back: NodeEdge::End(self.clone()), })) } /// Return an iterator of the start and end edges of this node’s descendants, /// in tree order. #[inline] pub fn traverse(&self) -> Traverse { match (self.first_child(), self.last_child()) { (Some(first_child), Some(last_child)) => Traverse(Some(State { next: NodeEdge::Start(first_child), next_back: NodeEdge::End(last_child), })), (None, None) => Traverse(None), _ => unreachable!(), } } /// Return an iterator of the inclusive descendants element that match the given selector list. #[inline] pub fn select(&self, selectors: &str) -> Result>, ()> { self.inclusive_descendants().select(selectors) } /// Return the first inclusive descendants element that match the given selector list. #[inline] pub fn select_first(&self, selectors: &str) -> Result, ()> { let mut elements = self.select(selectors)?; elements.next().ok_or(()) } } #[derive(Debug, Clone)] struct State { next: T, next_back: T, } /// A double-ended iterator of sibling nodes. #[derive(Debug, Clone)] pub struct Siblings(Option>); macro_rules! siblings_next { ($next: ident, $next_back: ident, $next_sibling: ident) => { fn $next(&mut self) -> Option { #![allow(non_shorthand_field_patterns)] self.0.take().map(|State { $next: next, $next_back: next_back }| { if let Some(sibling) = next.$next_sibling() { if next != next_back { self.0 = Some(State { $next: sibling, $next_back: next_back }) } } next }) } } } impl Iterator for Siblings { type Item = NodeRef; siblings_next!(next, next_back, next_sibling); } impl DoubleEndedIterator for Siblings { siblings_next!(next_back, next, previous_sibling); } /// An iterator on ancestor nodes. #[derive(Debug, Clone)] pub struct Ancestors(Option); impl Iterator for Ancestors { type Item = NodeRef; #[inline] fn next(&mut self) -> Option { self.0.take().map(|node| { self.0 = node.parent(); node }) } } /// An iterator of references to a given node and its descendants, in tree order. #[derive(Debug, Clone)] pub struct Descendants(Traverse); macro_rules! descendants_next { ($next: ident) => { #[inline] fn $next(&mut self) -> Option { loop { match (self.0).$next() { Some(NodeEdge::Start(node)) => return Some(node), Some(NodeEdge::End(_)) => {} None => return None } } } } } impl Iterator for Descendants { type Item = NodeRef; descendants_next!(next); } impl DoubleEndedIterator for Descendants { descendants_next!(next_back); } /// Marks either the start or the end of a node. #[derive(Debug, Copy, Clone, PartialEq, Eq)] pub enum NodeEdge { /// Indicates that start of a node that has children. /// Yielded by `Traverse::next` before the node’s descendants. /// In HTML or XML, this corresponds to an opening tag like `
` Start(T), /// Indicates that end of a node that has children. /// Yielded by `Traverse::next` after the node’s descendants. /// In HTML or XML, this corresponds to a closing tag like `
` End(T), } /// An iterator of the start and end edges of the nodes in a given subtree. #[derive(Debug, Clone)] pub struct Traverse(Option>>); macro_rules! traverse_next { ($next: ident, $next_back: ident, $first_child: ident, $next_sibling: ident, $Start: ident, $End: ident) => { fn $next(&mut self) -> Option> { #![allow(non_shorthand_field_patterns)] self.0.take().map(|State { $next: next, $next_back: next_back }| { if next != next_back { self.0 = match next { NodeEdge::$Start(ref node) => { match node.$first_child() { Some(child) => { Some(State { $next: NodeEdge::$Start(child), $next_back: next_back }) } None => Some(State { $next: NodeEdge::$End(node.clone()), $next_back: next_back }) } } NodeEdge::$End(ref node) => { match node.$next_sibling() { Some(sibling) => { Some(State { $next: NodeEdge::$Start(sibling), $next_back: next_back }) } None => node.parent().map(|parent| { State { $next: NodeEdge::$End(parent), $next_back: next_back } }) } } }; } next }) } } } impl Iterator for Traverse { type Item = NodeEdge; traverse_next!(next, next_back, first_child, next_sibling, Start, End); } impl DoubleEndedIterator for Traverse { traverse_next!(next_back, next, last_child, previous_sibling, End, Start); } macro_rules! filter_map_like_iterator { (#[$doc: meta] $name: ident: $f: expr, $from: ty => $to: ty) => { #[$doc] #[derive(Debug, Clone)] pub struct $name(pub I); impl Iterator for $name where I: Iterator, { type Item = $to; #[inline] fn next(&mut self) -> Option<$to> { for x in self.0.by_ref() { if let Some(y) = ($f)(x) { return Some(y); } } None } } impl DoubleEndedIterator for $name where I: DoubleEndedIterator, { #[inline] fn next_back(&mut self) -> Option<$to> { for x in self.0.by_ref().rev() { if let Some(y) = ($f)(x) { return Some(y); } } None } } }; } filter_map_like_iterator! { /// A node iterator adaptor that yields element nodes. Elements: NodeRef::into_element_ref, NodeRef => NodeDataRef } filter_map_like_iterator! { /// A node iterator adaptor that yields comment nodes. Comments: NodeRef::into_comment_ref, NodeRef => NodeDataRef> } filter_map_like_iterator! { /// A node iterator adaptor that yields text nodes. TextNodes: NodeRef::into_text_ref, NodeRef => NodeDataRef> } /// An element iterator adaptor that yields elements maching given selectors. pub struct Select where I: Iterator>, S: Borrow, { /// The underlying iterator. pub iter: I, /// The selectors to be matched. pub selectors: S, } impl Iterator for Select where I: Iterator>, S: Borrow, { type Item = NodeDataRef; #[inline] fn next(&mut self) -> Option> { for element in self.iter.by_ref() { if self.selectors.borrow().matches(&element) { return Some(element); } } None } } impl DoubleEndedIterator for Select where I: DoubleEndedIterator>, S: Borrow, { #[inline] fn next_back(&mut self) -> Option> { for element in self.iter.by_ref().rev() { if self.selectors.borrow().matches(&element) { return Some(element); } } None } } /// Convenience methods for node iterators. pub trait NodeIterator: Sized + Iterator { /// Filter this element iterator to elements. #[inline] fn elements(self) -> Elements { Elements(self) } /// Filter this node iterator to text nodes. #[inline] fn text_nodes(self) -> TextNodes { TextNodes(self) } /// Filter this node iterator to comment nodes. #[inline] fn comments(self) -> Comments { Comments(self) } /// Filter this node iterator to elements maching the given selectors. #[inline] fn select(self, selectors: &str) -> Result>, ()> { self.elements().select(selectors) } } /// Convenience methods for element iterators. pub trait ElementIterator: Sized + Iterator> { /// Filter this element iterator to elements maching the given selectors. #[inline] fn select(self, selectors: &str) -> Result, ()> { Selectors::compile(selectors).map(|s| Select { iter: self, selectors: s, }) } } impl NodeIterator for I where I: Iterator {} impl ElementIterator for I where I: Iterator> {}