1use crate::{node::VisitableNode, prelude::*};
2
3#[derive(Debug)]
10pub enum Event {
11 Enter,
12 Exit,
13}
14
15pub trait Visitor {
20 fn visit<V: VisitableNode + ?Sized>(&mut self, _: &V, _: Event) {}
22
23 fn push(&mut self, _: &str) {}
25 fn pop(&mut self) {}
26}
27
28#[derive(Debug, Default)]
33pub struct ValidateVisitor {
34 pub errors: ErrorTree,
35 pub path: Vec<String>,
36 pub node_count: usize,
37}
38
39impl ValidateVisitor {
40 #[must_use]
41 pub fn new() -> Self {
42 Self {
43 errors: ErrorTree::new(),
44 ..Default::default()
45 }
46 }
47
48 #[must_use]
49 pub const fn node_count(&self) -> usize {
50 self.node_count
51 }
52}
53
54impl ValidateVisitor {
55 fn current_route(&self) -> String {
56 self.path
57 .iter()
58 .filter(|s| !s.is_empty())
59 .cloned()
60 .collect::<Vec<_>>()
61 .join(".")
62 }
63}
64
65impl Visitor for ValidateVisitor {
66 fn visit<T: VisitableNode + ?Sized>(&mut self, node: &T, event: Event) {
67 match event {
68 Event::Enter => {
69 self.node_count += 1;
70
71 match node.validate() {
72 Ok(()) => {}
73 Err(errs) => {
74 if !errs.is_empty() {
75 let route = self.current_route();
76
77 if route.is_empty() {
78 self.errors.merge(errs);
80 } else {
81 self.errors.children.entry(route).or_default().merge(errs);
83 }
84 }
85 }
86 }
87 }
88 Event::Exit => {}
89 }
90 }
91
92 fn push(&mut self, s: &str) {
93 self.path.push(s.to_string());
94 }
95
96 fn pop(&mut self) {
97 self.path.pop();
98 }
99}