use std::borrow::Cow;
use std::cmp::Ordering;
use std::fmt;
use std::hash::{Hash, Hasher};
use std::iter::{Enumerate, from_fn};
use std::num::NonZeroU32;
use std::slice::Iter;
use crate::{
Document, Name, NameData,
error::{ErrorKind, Result},
};
impl<'input> Document<'input> {
pub fn root<'doc>(&'doc self) -> Node<'doc, 'input> {
self.node(NodeId::ROOT).unwrap()
}
pub fn root_element<'doc>(&'doc self) -> Node<'doc, 'input> {
self.root().first_child_element().unwrap()
}
pub fn node<'doc>(&'doc self, id: NodeId) -> Option<Node<'doc, 'input>> {
self.nodes.get(id.get()).map(|data| Node {
id,
data,
doc: self,
})
}
}
#[derive(Clone, Copy)]
pub struct Node<'doc, 'input> {
pub(crate) id: NodeId,
pub(crate) data: &'doc NodeData,
pub(crate) doc: &'doc Document<'input>,
}
impl PartialEq for Node<'_, '_> {
fn eq(&self, other: &Self) -> bool {
let doc = self.doc as *const Document;
let other_doc = other.doc as *const Document;
(self.id, doc) == (other.id, other_doc)
}
}
impl Eq for Node<'_, '_> {}
impl PartialOrd for Node<'_, '_> {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl Ord for Node<'_, '_> {
fn cmp(&self, other: &Self) -> Ordering {
let doc = self.doc as *const Document;
let other_doc = other.doc as *const Document;
(self.id, doc).cmp(&(other.id, other_doc))
}
}
impl Hash for Node<'_, '_> {
fn hash<H>(&self, hasher: &mut H)
where
H: Hasher,
{
let doc = self.doc as *const Document;
(self.id, doc).hash(hasher);
}
}
impl<'doc, 'input> Node<'doc, 'input> {
pub fn document(self) -> &'doc Document<'input> {
self.doc
}
pub fn id(self) -> NodeId {
self.id
}
pub fn is_root(&self) -> bool {
self.id == NodeId::ROOT
}
pub fn is_element(&self) -> bool {
self.data.element.is_some()
}
pub(crate) fn element_data(self) -> Option<&'doc ElementData<'input>> {
self.data
.element
.map(|element| &self.doc.elements[element.get()])
}
pub fn is_text(&self) -> bool {
self.data.text.is_some()
}
fn other(self, id: NodeId) -> Self {
self.doc.node(id).unwrap()
}
fn iter<F>(self, f: F) -> impl Iterator<Item = Self> + Clone
where
F: Fn(Self) -> Option<Self> + Clone,
{
let mut next = Some(self);
from_fn(move || match next {
Some(next1) => {
next = f(next1);
Some(next1)
}
None => None,
})
}
pub fn parent(self) -> Option<Self> {
self.data.parent.map(|id| self.other(id))
}
pub fn ancestors(self) -> impl Iterator<Item = Self> + Clone {
self.iter(Self::parent)
}
pub fn prev_sibling(self) -> Option<Self> {
self.data.prev_sibling.map(|id| self.other(id))
}
pub fn prev_siblings(self) -> impl Iterator<Item = Self> + Clone {
self.iter(Self::prev_sibling)
}
pub fn prev_sibling_element(self) -> Option<Self> {
self.prev_siblings().find(Self::is_element)
}
pub fn next_sibling(self) -> Option<Self> {
self.data
.next_subtree
.filter(|id| self.doc.nodes[id.get()].prev_sibling == Some(self.id))
.map(|id| self.other(id))
}
pub fn next_siblings(self) -> impl Iterator<Item = Self> + Clone {
self.iter(Self::next_sibling)
}
pub fn next_sibling_element(self) -> Option<Self> {
self.next_siblings().find(Self::is_element)
}
pub fn has_children(self) -> bool {
self.data.last_child.is_some()
}
pub fn first_child(self) -> Option<Self> {
if self.has_children() {
Some(self.other(self.id.next()))
} else {
None
}
}
pub fn first_child_element(self) -> Option<Self> {
self.child_elements().next()
}
pub fn last_child(self) -> Option<Self> {
self.data.last_child.map(|id| self.other(id))
}
pub fn last_child_element(self) -> Option<Self> {
self.child_elements().next_back()
}
pub fn children(self) -> Children<'doc, 'input> {
Children {
front: self.first_child(),
back: self.last_child(),
}
}
pub fn child_elements(self) -> impl DoubleEndedIterator<Item = Self> + Clone {
self.children().filter(Self::is_element)
}
pub fn descendants(self) -> Descendants<'doc, 'input> {
let from = self.id.get();
let until = self
.data
.next_subtree
.map_or(self.doc.nodes.len(), |id| id.get());
let nodes = self.doc.nodes[from..until].iter().enumerate();
Descendants {
from,
nodes,
doc: self.doc,
}
}
pub fn name(self) -> Option<Name<'doc, 'input>> {
self.element_data()
.map(|element| element.name.get(self.doc))
}
pub fn has_name<N>(self, name: N) -> bool
where
Name<'doc, 'input>: PartialEq<N>,
{
self.name().is_some_and(|name1| name1 == name)
}
pub fn text(self) -> Option<&'doc str> {
self.data.text.map(|text| self.doc.strings.get(text))
}
pub fn child_texts(self) -> impl Iterator<Item = &'doc str> + Clone {
self.children().filter_map(Self::text)
}
pub fn child_text(self) -> Option<Cow<'doc, str>> {
collect_text(self.child_texts())
}
pub fn descedant_texts(self) -> impl Iterator<Item = &'doc str> + Clone {
self.descendants().filter_map(Self::text)
}
pub fn descedant_text(self) -> Option<Cow<'doc, str>> {
collect_text(self.descedant_texts())
}
}
fn collect_text<'doc>(mut iter: impl Iterator<Item = &'doc str> + Clone) -> Option<Cow<'doc, str>> {
let mut cnt = 0;
let mut len = 0;
for text in iter.clone() {
cnt += 1;
len += text.len();
}
if cnt == 0 {
return None;
} else if cnt == 1 {
let text = iter.next().unwrap();
return Some(Cow::Borrowed(text));
}
let mut buf = String::with_capacity(len);
for text in iter {
buf.push_str(text);
}
Some(Cow::Owned(buf))
}
pub(crate) struct NodeData {
pub(crate) element: Option<NodeId>,
pub(crate) text: Option<NodeId>,
pub(crate) parent: Option<NodeId>,
pub(crate) prev_sibling: Option<NodeId>,
pub(crate) next_subtree: Option<NodeId>,
pub(crate) last_child: Option<NodeId>,
}
const _SIZE_OF_NODE_DATA: () = assert!(size_of::<NodeData>() == 3 * size_of::<usize>());
#[repr(Rust, packed)]
pub(crate) struct ElementData<'input> {
pub(crate) name: NameData<'input>,
pub(crate) attributes_start: u32,
pub(crate) attributes_len: u16,
}
const _SIZE_OF_ELEMENT_DATA: () = assert!(
size_of::<ElementData<'static>>()
== size_of::<u16>() + 2 * size_of::<usize>() + size_of::<u32>() + size_of::<u16>()
);
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct NodeId(NonZeroU32);
impl NodeId {
pub(crate) const ROOT: Self = Self(NonZeroU32::new(1).unwrap());
pub(crate) fn new(id: usize) -> Result<Self> {
if id >= u32::MAX as usize {
return ErrorKind::TooManyNodes.into();
}
Ok(Self(NonZeroU32::new(id as u32 + 1).unwrap()))
}
pub(crate) fn get(self) -> usize {
self.0.get() as usize - 1
}
fn next(self) -> Self {
Self(self.0.checked_add(1).unwrap())
}
}
#[derive(Clone)]
pub struct Children<'doc, 'input> {
front: Option<Node<'doc, 'input>>,
back: Option<Node<'doc, 'input>>,
}
impl<'doc, 'input> Iterator for Children<'doc, 'input> {
type Item = Node<'doc, 'input>;
fn next(&mut self) -> Option<Self::Item> {
let is_last = self.front == self.back;
let node = self.front.take();
if is_last {
self.back = None;
} else {
self.front = node.and_then(Node::next_sibling);
}
node
}
}
impl DoubleEndedIterator for Children<'_, '_> {
fn next_back(&mut self) -> Option<Self::Item> {
let is_last = self.front == self.back;
let node = self.back.take();
if is_last {
self.front = None;
} else {
self.back = node.and_then(Node::prev_sibling);
}
node
}
}
#[derive(Clone)]
pub struct Descendants<'doc, 'input> {
from: usize,
nodes: Enumerate<Iter<'doc, NodeData>>,
doc: &'doc Document<'input>,
}
impl<'doc, 'input> Descendants<'doc, 'input> {
fn get(&self, (idx, data): (usize, &'doc NodeData)) -> Node<'doc, 'input> {
Node {
id: NodeId::new(self.from + idx).unwrap(),
data,
doc: self.doc,
}
}
}
impl<'doc, 'input> Iterator for Descendants<'doc, 'input> {
type Item = Node<'doc, 'input>;
fn next(&mut self) -> Option<Self::Item> {
self.nodes.next().map(|node| self.get(node))
}
fn nth(&mut self, n: usize) -> Option<Self::Item> {
self.nodes.nth(n).map(|node| self.get(node))
}
fn size_hint(&self) -> (usize, Option<usize>) {
self.nodes.size_hint()
}
}
impl ExactSizeIterator for Descendants<'_, '_> {}
impl DoubleEndedIterator for Descendants<'_, '_> {
fn next_back(&mut self) -> Option<Self::Item> {
self.nodes.next_back().map(|node| self.get(node))
}
}
impl fmt::Debug for Node<'_, '_> {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut fmt = fmt.debug_struct("Node");
if let Some(name) = self.name() {
fmt.field("name", &name);
}
if let Some(text) = self.text() {
fmt.field("text", &text);
}
if self.has_attributes() {
fmt.field("attributes", &self.attributes());
}
if self.has_children() {
fmt.field("children", &self.children());
}
fmt.finish()
}
}
impl fmt::Debug for Children<'_, '_> {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt.debug_list().entries(self.clone()).finish()
}
}
impl fmt::Debug for Descendants<'_, '_> {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt.debug_list().entries(self.clone()).finish()
}
}