use crate::tree::{Document, Node, NodeId, NodeKind};
#[derive(Debug)]
struct Entry {
kind: NodeKind,
name: String,
text: String,
parent: Option<u32>,
children: Vec<u32>,
attrs: Vec<(String, String)>,
}
#[derive(Debug, Default)]
pub struct Arena {
nodes: Vec<Entry>,
}
impl Arena {
pub fn builder() -> ArenaBuilder {
ArenaBuilder {
arena: Arena::default(),
open: Vec::new(),
}
}
pub fn len(&self) -> usize {
self.nodes.len()
}
pub fn is_empty(&self) -> bool {
self.nodes.is_empty()
}
pub fn get(&self, id: NodeId) -> Option<ArenaNode<'_>> {
((id.0 as usize) < self.nodes.len()).then_some(ArenaNode {
arena: self,
idx: id.0,
})
}
}
#[derive(Debug, Clone, Copy)]
pub struct ArenaNode<'a> {
arena: &'a Arena,
idx: u32,
}
impl PartialEq for ArenaNode<'_> {
fn eq(&self, other: &Self) -> bool {
std::ptr::eq(self.arena, other.arena) && self.idx == other.idx
}
}
impl Eq for ArenaNode<'_> {}
impl<'a> ArenaNode<'a> {
fn entry(&self) -> &'a Entry {
&self.arena.nodes[self.idx as usize]
}
}
impl<'a> Node<'a> for ArenaNode<'a> {
fn id(self) -> NodeId {
NodeId(self.idx)
}
fn kind(self) -> NodeKind {
self.entry().kind
}
fn parent(self) -> Option<Self> {
self.entry().parent.map(|p| ArenaNode {
arena: self.arena,
idx: p,
})
}
fn children(self) -> impl Iterator<Item = Self> + 'a {
let arena = self.arena;
self.entry()
.children
.iter()
.map(move |&idx| ArenaNode { arena, idx })
}
fn local_name(self) -> &'a str {
&self.entry().name
}
fn attributes(self) -> impl Iterator<Item = (&'a str, &'a str)> + 'a {
self.entry()
.attrs
.iter()
.map(|(k, v)| (k.as_str(), v.as_str()))
}
fn text(self) -> &'a str {
&self.entry().text
}
}
impl Document for Arena {
type N<'a>
= ArenaNode<'a>
where
Self: 'a;
fn root(&self) -> Self::N<'_> {
ArenaNode {
arena: self,
idx: 0,
}
}
fn node_count(&self) -> Option<usize> {
Some(self.nodes.len())
}
}
pub struct ArenaBuilder {
arena: Arena,
open: Vec<u32>,
}
impl ArenaBuilder {
fn push(&mut self, kind: NodeKind, name: &str, text: &str) -> u32 {
let idx = self.arena.nodes.len() as u32;
let parent = self.open.last().copied();
self.arena.nodes.push(Entry {
kind,
name: name.to_string(),
text: text.to_string(),
parent,
children: Vec::new(),
attrs: Vec::new(),
});
if let Some(p) = parent {
self.arena.nodes[p as usize].children.push(idx);
}
idx
}
pub fn open(mut self, local_name: &str) -> Self {
let idx = self.push(NodeKind::Element, local_name, "");
self.open.push(idx);
self
}
pub fn attr(mut self, name: &str, value: &str) -> Self {
if let Some(&idx) = self.open.last() {
self.arena.nodes[idx as usize]
.attrs
.push((name.to_string(), value.to_string()));
}
self
}
pub fn text(mut self, text: &str) -> Self {
self.push(NodeKind::Text, "#text", text);
self
}
pub fn close(mut self) -> Self {
self.open.pop();
self
}
pub fn leaf(self, local_name: &str) -> Self {
self.open(local_name).close()
}
pub fn build(self) -> Arena {
self.arena
}
}