use alloc::string::String;
use alloc::vec::Vec;
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct NodeId(pub(crate) usize);
impl NodeId {
#[must_use]
pub const fn index(self) -> usize {
self.0
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct ExpandedName {
pub namespace: Option<String>,
pub local: String,
}
impl ExpandedName {
#[must_use]
pub fn local(local: impl Into<String>) -> Self {
Self {
namespace: None,
local: local.into(),
}
}
#[must_use]
pub fn qualified(
namespace: impl Into<String>,
local: impl Into<String>,
) -> Self {
Self {
namespace: Some(namespace.into()),
local: local.into(),
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Attribute {
pub name: ExpandedName,
pub value: String,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum NodeKind {
Root,
Element {
name: ExpandedName,
attributes: Vec<NodeId>,
},
Attr(Attribute),
Text(String),
Comment(String),
ProcessingInstruction {
target: String,
data: String,
},
}
#[derive(Debug, Clone)]
pub(crate) struct Node {
pub(crate) kind: NodeKind,
pub(crate) parent: Option<NodeId>,
pub(crate) children: Vec<NodeId>,
}
#[derive(Debug, Clone)]
pub struct Document {
pub(crate) nodes: Vec<Node>,
}
impl Document {
pub(crate) fn new() -> Self {
Self {
nodes: alloc::vec![Node {
kind: NodeKind::Root,
parent: None,
children: Vec::new(),
}],
}
}
#[must_use]
pub const fn root(&self) -> NodeId {
NodeId(0)
}
pub(crate) fn push(&mut self, kind: NodeKind, parent: NodeId) -> NodeId {
let id = NodeId(self.nodes.len());
self.nodes.push(Node {
kind,
parent: Some(parent),
children: Vec::new(),
});
self.nodes[parent.0].children.push(id);
id
}
pub(crate) fn push_detached(
&mut self,
kind: NodeKind,
parent: NodeId,
) -> NodeId {
let id = NodeId(self.nodes.len());
self.nodes.push(Node {
kind,
parent: Some(parent),
children: Vec::new(),
});
id
}
#[must_use]
pub fn kind(&self, id: NodeId) -> Option<&NodeKind> {
self.nodes.get(id.0).map(|n| &n.kind)
}
pub(crate) fn kind_mut(&mut self, id: NodeId) -> Option<&mut NodeKind> {
self.nodes.get_mut(id.0).map(|n| &mut n.kind)
}
#[must_use]
pub fn parent(&self, id: NodeId) -> Option<NodeId> {
self.nodes.get(id.0).and_then(|n| n.parent)
}
#[must_use]
pub fn children(&self, id: NodeId) -> &[NodeId] {
self.nodes.get(id.0).map_or(&[], |n| n.children.as_slice())
}
#[must_use]
pub fn root_element(&self) -> Option<NodeId> {
self.children(self.root())
.iter()
.copied()
.find(|id| self.is_element(*id))
}
#[must_use]
pub fn is_element(&self, id: NodeId) -> bool {
matches!(self.kind(id), Some(NodeKind::Element { .. }))
}
#[must_use]
pub fn element_name(&self, id: NodeId) -> Option<&ExpandedName> {
match self.kind(id) {
Some(NodeKind::Element { name, .. }) => Some(name),
_ => None,
}
}
#[must_use]
pub fn attribute_nodes(&self, id: NodeId) -> &[NodeId] {
match self.kind(id) {
Some(NodeKind::Element { attributes, .. }) => attributes,
_ => &[],
}
}
#[must_use]
pub fn attributes(&self, id: NodeId) -> Vec<&Attribute> {
self.attribute_nodes(id)
.iter()
.filter_map(|a| match self.kind(*a) {
Some(NodeKind::Attr(at)) => Some(at),
_ => None,
})
.collect()
}
#[must_use]
pub fn attribute(&self, id: NodeId, local: &str) -> Option<&str> {
self.attributes(id)
.into_iter()
.find(|a| a.name.local == local)
.map(|a| a.value.as_str())
}
#[must_use]
pub fn text(&self, id: NodeId) -> String {
let mut out = String::new();
self.collect_text(id, &mut out);
out
}
fn collect_text(&self, id: NodeId, out: &mut String) {
match self.kind(id) {
Some(NodeKind::Attr(a)) => out.push_str(&a.value),
Some(NodeKind::Text(t)) => out.push_str(t),
Some(NodeKind::Root | NodeKind::Element { .. }) => {
for child in self.children(id) {
self.collect_text(*child, out);
}
}
_ => {}
}
}
pub fn descendants(&self) -> impl Iterator<Item = NodeId> + '_ {
(0..self.nodes.len()).map(NodeId)
}
#[must_use]
pub fn len(&self) -> usize {
self.nodes.len()
}
#[must_use]
pub fn is_empty(&self) -> bool {
self.nodes.len() <= 1
}
}