use super::*;
use std::collections::VecDeque;
impl Hatmel {
pub fn get(&self, handle: Handle) -> Option<&Content> {
self.nodes.get(handle).map(|n| &n.content)
}
pub fn children(&self, handle: Handle) -> impl DoubleEndedIterator<Item = Handle> + '_ {
self.children
.get(&handle)
.map(|v| &v[..])
.unwrap_or_default()
.iter()
.cloned()
}
pub fn parent(&self, handle: Handle) -> Option<Handle> {
self.parents.get(&handle).cloned()
}
pub fn ancestors(&self, adept: Handle) -> ParentIter {
ParentIter::new(self, adept)
}
pub fn get_element_name(&self, node: Handle) -> Option<(&str, &str)> {
self.nodes.get(node)?.content.element_name()
}
pub fn get_element_attribute(&self, node: Handle, name: &str, ns: &str) -> Option<&str> {
let attrs = self.nodes.get(node)?.content.attributes();
attrs
.rev()
.filter(|a| &a.name == name && namespace_equals_or_html(&a.namespace, ns))
.map(|a| a.value.as_ref())
.next()
}
pub fn siblings_after(&self, handle: Handle) -> impl DoubleEndedIterator<Item = Handle> + '_ {
self.parent(handle)
.and_then(|p| self.children.get(&p).map(|all| &all[..]))
.and_then(|all| {
all.iter()
.position(|c| c == &handle)
.map(|mypos| &all[mypos.saturating_add(1)..])
})
.unwrap_or_default()
.iter()
.cloned()
}
pub fn siblings_before(&self, handle: Handle) -> impl DoubleEndedIterator<Item = Handle> + '_ {
self.parent(handle)
.and_then(|p| self.children.get(&p).map(|all| &all[..]))
.and_then(|all| {
all.iter()
.position(|c| c == &handle)
.map(|mypos| &all[..mypos])
})
.unwrap_or_default()
.iter()
.cloned()
}
pub fn get_title(&self) -> StrTendril {
let title: Option<StrTendril> = (|| {
let html = self
.as_element(0, "html", "")
.or_else(|| self.children_as_elements(0, "html", "").into_iter().next())?;
let head = self
.children_as_elements(html, "head", "")
.into_iter()
.next()?;
let title = self
.children_as_elements(head, "title", "")
.into_iter()
.next()?;
Some(self.get_text(title))
})();
title.unwrap_or_default()
}
fn as_element(&self, node: Handle, local_name: &str, name_space: &str) -> Option<Handle> {
let (ln, ns) = self.get_element_name(node)?;
if local_name != ln {
return None;
}
if !namespace_equals_or_html(name_space, ns) {
return None;
}
Some(node)
}
fn children_as_elements<'a>(
&'a self,
node: Handle,
local_name: &'a str,
name_space: &'a str,
) -> impl IntoIterator<Item = Handle> + 'a {
self.children[&node]
.iter()
.filter_map(move |c| self.as_element(*c, local_name, name_space))
}
pub fn get_text(&self, node: Handle) -> StrTendril {
let mut s = StrTendril::new();
let mut nodes = VecDeque::from(vec![node]);
while let Some(node) = nodes.pop_front() {
match &self.nodes[node].content {
Content::Comment { .. }
| Content::ProcessingInstruction { .. }
| Content::DocType { .. }
| Content::Element(Element {
kind: ElementKind::Template,
..
}) => {}
Content::Element { .. } | Content::Document => {
nodes = self
.children(node)
.chain(nodes.into_iter())
.collect::<Vec<Handle>>()
.into()
}
Content::Text { text } => s.push_slice(text.as_str()),
}
}
s
}
}
#[derive(Debug)]
pub struct ParentIter<'a> {
adept: Option<Handle>,
doc: &'a Hatmel,
}
impl<'a> ParentIter<'a> {
fn new(doc: &'a Hatmel, adept: Handle) -> Self {
Self {
doc,
adept: Some(adept),
}
}
}
impl<'a> Iterator for ParentIter<'a> {
type Item = Handle;
fn next(&mut self) -> Option<Self::Item> {
if let Some(adept) = self.adept {
self.adept = self.doc.parent(adept);
}
self.adept
}
}
#[derive(Debug, Default, Clone)]
pub struct HandleIter<'a> {
curr: Arc<AtomicUsize>,
end: Handle,
phantom: PhantomData<Cow<'a, ()>>,
}
impl<'a> HandleIter<'a> {
pub(crate) fn new(range: std::ops::Range<usize>) -> Self {
Self {
curr: Arc::new(AtomicUsize::new(range.start)),
end: range.end,
phantom: PhantomData,
}
}
}
impl<'a> Iterator for HandleIter<'a> {
type Item = Handle;
fn next(&mut self) -> Option<Self::Item> {
if self.curr.load(std::sync::atomic::Ordering::SeqCst) >= self.end {
return None;
}
let next = self
.curr
.as_ref()
.fetch_add(1, std::sync::atomic::Ordering::SeqCst);
if next >= self.end {
return None;
}
Some(next)
}
}