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 errors: ErrorTree,
35 path: Vec<String>,
36 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 #[must_use]
54 pub const fn errors(&self) -> &ErrorTree {
55 &self.errors
56 }
57
58 #[must_use]
59 pub fn into_errors(self) -> ErrorTree {
60 self.errors
61 }
62}
63
64impl ValidateVisitor {
65 fn current_route(&self) -> String {
66 let mut route = String::new();
67
68 for segment in self.path.iter().filter(|segment| !segment.is_empty()) {
69 if !route.is_empty() {
70 route.push('.');
71 }
72 route.push_str(segment);
73 }
74
75 route
76 }
77}
78
79impl Visitor for ValidateVisitor {
80 fn visit<T: VisitableNode + ?Sized>(&mut self, node: &T, event: Event) {
81 match event {
82 Event::Enter => {
83 self.node_count += 1;
84
85 match node.validate() {
86 Ok(()) => {}
87 Err(errs) => {
88 if !errs.is_empty() {
89 let route = self.current_route();
90
91 if route.is_empty() {
92 self.errors.merge(errs);
94 } else {
95 self.errors.merge_for(route, errs);
97 }
98 }
99 }
100 }
101 }
102 Event::Exit => {}
103 }
104 }
105
106 fn push(&mut self, s: &str) {
107 self.path.push(s.to_string());
108 }
109
110 fn pop(&mut self) {
111 self.path.pop();
112 }
113}