use crate::{node::VisitableNode, prelude::*};
#[derive(Debug)]
pub enum Event {
Enter,
Exit,
}
pub trait Visitor {
fn visit<V: VisitableNode + ?Sized>(&mut self, _: &V, _: Event) {}
fn push(&mut self, _: &str) {}
fn pop(&mut self) {}
}
#[derive(Debug, Default)]
pub struct ValidateVisitor {
errors: ErrorTree,
path: Vec<String>,
node_count: usize,
}
impl ValidateVisitor {
#[must_use]
pub fn new() -> Self {
Self {
errors: ErrorTree::new(),
..Default::default()
}
}
#[must_use]
pub const fn node_count(&self) -> usize {
self.node_count
}
#[must_use]
pub const fn errors(&self) -> &ErrorTree {
&self.errors
}
#[must_use]
pub fn into_errors(self) -> ErrorTree {
self.errors
}
}
impl ValidateVisitor {
fn current_route(&self) -> String {
self.path
.iter()
.filter(|s| !s.is_empty())
.cloned()
.collect::<Vec<_>>()
.join(".")
}
}
impl Visitor for ValidateVisitor {
fn visit<T: VisitableNode + ?Sized>(&mut self, node: &T, event: Event) {
match event {
Event::Enter => {
self.node_count += 1;
match node.validate() {
Ok(()) => {}
Err(errs) => {
if !errs.is_empty() {
let route = self.current_route();
if route.is_empty() {
self.errors.merge(errs);
} else {
self.errors.merge_for(route, errs);
}
}
}
}
}
Event::Exit => {}
}
}
fn push(&mut self, s: &str) {
self.path.push(s.to_string());
}
fn pop(&mut self) {
self.path.pop();
}
}