1use crate::{node::VisitableNode, prelude::*};
2
3#[derive(Debug)]
10pub enum Event {
11 Enter,
12 Exit,
13}
14
15pub trait Visitor {
24 fn visit<V: VisitableNode + ?Sized>(&mut self, _: &V, _: Event) {}
26
27 fn push(&mut self, _: &str) {}
29 fn pop(&mut self) {}
30}
31
32#[derive(Debug, Default)]
40pub struct ValidateVisitor {
41 errors: ErrorTree,
42 path: Vec<String>,
43 node_count: usize,
44}
45
46impl ValidateVisitor {
47 #[must_use]
49 pub fn new() -> Self {
50 Self {
51 errors: ErrorTree::new(),
52 ..Default::default()
53 }
54 }
55
56 #[must_use]
57 pub const fn node_count(&self) -> usize {
58 self.node_count
59 }
60
61 #[must_use]
62 pub const fn errors(&self) -> &ErrorTree {
63 &self.errors
64 }
65
66 #[must_use]
67 pub fn into_errors(self) -> ErrorTree {
68 self.errors
69 }
70}
71
72impl ValidateVisitor {
73 fn current_route(&self) -> String {
75 let mut route = String::new();
76
77 for segment in self.path.iter().filter(|segment| !segment.is_empty()) {
78 if !route.is_empty() {
79 route.push('.');
80 }
81 route.push_str(segment);
82 }
83
84 route
85 }
86}
87
88impl Visitor for ValidateVisitor {
89 fn visit<T: VisitableNode + ?Sized>(&mut self, node: &T, event: Event) {
90 match event {
91 Event::Enter => {
92 self.node_count += 1;
93
94 match node.validate() {
95 Ok(()) => {}
96 Err(errs) => {
97 if !errs.is_empty() {
98 let route = self.current_route();
99
100 if route.is_empty() {
101 self.errors.merge(errs);
103 } else {
104 self.errors.merge_for(route, errs);
106 }
107 }
108 }
109 }
110 }
111 Event::Exit => {}
112 }
113 }
114
115 fn push(&mut self, s: &str) {
116 self.path.push(s.to_string());
117 }
118
119 fn pop(&mut self) {
120 self.path.pop();
121 }
122}