use crate::arena::NodeId;
use crate::document::Document;
use crate::iter::{Attributes, ChildElements, Children, Descendants, Siblings};
use crate::node::NodeKind;
#[derive(Debug, Clone, Copy)]
pub struct NodeRef<'a> {
doc: &'a Document,
id: NodeId,
}
impl<'a> NodeRef<'a> {
pub(crate) fn new(doc: &'a Document, id: NodeId) -> Self {
Self { doc, id }
}
pub fn id(&self) -> NodeId {
self.id
}
pub fn document(&self) -> &'a Document {
self.doc
}
pub fn kind(&self) -> &'a NodeKind {
&self
.doc
.arena
.get(self.id)
.expect("NodeRef holds invalid id")
.kind
}
pub fn parent(&self) -> Option<NodeRef<'a>> {
self.doc
.parent(self.id)
.map(|pid| NodeRef::new(self.doc, pid))
}
pub fn children(&self) -> Children<'a> {
Children::new(self.doc, self.id)
}
pub fn siblings(&self) -> Siblings<'a> {
Siblings::new(self.doc, self.id)
}
pub fn descendants(&self) -> Descendants<'a> {
Descendants::new(self.doc, self.id)
}
pub fn value(&self) -> &'a str {
let Some(data) = self.doc.arena.get(self.id) else {
return "";
};
match &data.kind {
NodeKind::Document => "",
NodeKind::Element(el) | NodeKind::Declaration(el) => &el.name,
NodeKind::Text(txt) => &txt.content,
NodeKind::Comment(s) | NodeKind::Unknown(s) => s,
}
}
pub fn line(&self) -> u32 {
self.doc.line_num(self.id).unwrap_or(0)
}
pub fn as_element(&self) -> Option<ElementRef<'a>> {
let data = self.doc.arena.get(self.id)?;
match &data.kind {
NodeKind::Element(_) => Some(ElementRef::new(self.doc, self.id)),
_ => None,
}
}
}
impl PartialEq for NodeRef<'_> {
fn eq(&self, other: &Self) -> bool {
std::ptr::eq(self.doc, other.doc) && self.id == other.id
}
}
impl Eq for NodeRef<'_> {}
#[derive(Debug, Clone, Copy)]
pub struct ElementRef<'a> {
doc: &'a Document,
id: NodeId,
}
impl<'a> ElementRef<'a> {
pub(crate) fn new(doc: &'a Document, id: NodeId) -> Self {
Self { doc, id }
}
pub fn id(&self) -> NodeId {
self.id
}
pub fn document(&self) -> &'a Document {
self.doc
}
pub fn as_node(&self) -> NodeRef<'a> {
NodeRef::new(self.doc, self.id)
}
pub fn name(&self) -> &'a str {
let data = self
.doc
.arena
.get(self.id)
.expect("ElementRef holds invalid id");
match &data.kind {
NodeKind::Element(el) => &el.name,
_ => panic!("ElementRef references a non-Element node"),
}
}
pub fn attribute(&self, name: &str) -> Option<&'a str> {
self.doc.attribute(self.id, name)
}
pub fn attributes(&self) -> Attributes<'a> {
let Some(data) = self.doc.arena.get(self.id) else {
return Attributes::empty();
};
match &data.kind {
NodeKind::Element(el) => Attributes::new(&el.attributes),
_ => Attributes::empty(),
}
}
pub fn children(&self) -> Children<'a> {
Children::new(self.doc, self.id)
}
pub fn child_elements(&self) -> ChildElements<'a> {
ChildElements::new(self.doc, self.id, None)
}
pub fn child_elements_by_name(&self, name: &str) -> ChildElements<'a> {
ChildElements::new(self.doc, self.id, Some(name))
}
pub fn text(&self) -> Option<&'a str> {
self.doc.get_text(self.id)
}
pub fn int_attribute(&self, name: &str, default: i32) -> i32 {
self.doc.int_attribute(self.id, name, default)
}
pub fn bool_attribute(&self, name: &str, default: bool) -> bool {
self.doc.bool_attribute(self.id, name, default)
}
pub fn double_attribute(&self, name: &str, default: f64) -> f64 {
self.doc.double_attribute(self.id, name, default)
}
}
impl PartialEq for ElementRef<'_> {
fn eq(&self, other: &Self) -> bool {
std::ptr::eq(self.doc, other.doc) && self.id == other.id
}
}
impl Eq for ElementRef<'_> {}