use crate::binxml::value_variant::BinXmlValue;
use crate::model::ir::{Element, ElementId, IrTree, Name, Node, Placeholder, Text};
pub trait IrVisitor {
type Error;
fn start_element(&mut self, element: &Element<'_>) -> Result<(), Self::Error>;
fn end_element(&mut self, element: &Element<'_>) -> Result<(), Self::Error>;
fn visit_text(&mut self, text: &Text<'_>) -> Result<(), Self::Error>;
fn visit_value(&mut self, value: &BinXmlValue<'_>) -> Result<(), Self::Error>;
fn visit_entity_ref(&mut self, name: &Name<'_>) -> Result<(), Self::Error>;
fn visit_char_ref(&mut self, value: u16) -> Result<(), Self::Error>;
fn visit_cdata(&mut self, text: &Text<'_>) -> Result<(), Self::Error>;
fn visit_pi_target(&mut self, name: &Name<'_>) -> Result<(), Self::Error>;
fn visit_pi_data(&mut self, text: &Text<'_>) -> Result<(), Self::Error>;
fn visit_placeholder(&mut self, placeholder: &Placeholder) -> Result<(), Self::Error>;
}
pub fn walk_ir<V: IrVisitor>(tree: &IrTree<'_>, visitor: &mut V) -> Result<(), V::Error> {
walk_ir_node(tree, tree.root(), visitor)
}
fn walk_ir_node<V: IrVisitor>(
tree: &IrTree<'_>,
element_id: ElementId,
visitor: &mut V,
) -> Result<(), V::Error> {
let element = tree.element(element_id);
visitor.start_element(element)?;
for node in &element.children {
match node {
Node::Element(child_id) => walk_ir_node(tree, *child_id, visitor)?,
Node::Text(text) => visitor.visit_text(text)?,
Node::Value(value) => visitor.visit_value(value)?,
Node::EntityRef(name) => visitor.visit_entity_ref(name)?,
Node::CharRef(value) => visitor.visit_char_ref(*value)?,
Node::CData(text) => visitor.visit_cdata(text)?,
Node::PITarget(name) => visitor.visit_pi_target(name)?,
Node::PIData(text) => visitor.visit_pi_data(text)?,
Node::Placeholder(ph) => visitor.visit_placeholder(ph)?,
}
}
visitor.end_element(element)?;
Ok(())
}