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 self.path
67 .iter()
68 .filter(|s| !s.is_empty())
69 .cloned()
70 .collect::<Vec<_>>()
71 .join(".")
72 }
73}
74
75impl Visitor for ValidateVisitor {
76 fn visit<T: VisitableNode + ?Sized>(&mut self, node: &T, event: Event) {
77 match event {
78 Event::Enter => {
79 self.node_count += 1;
80
81 match node.validate() {
82 Ok(()) => {}
83 Err(errs) => {
84 if !errs.is_empty() {
85 let route = self.current_route();
86
87 if route.is_empty() {
88 self.errors.merge(errs);
90 } else {
91 self.errors.merge_for(route, errs);
93 }
94 }
95 }
96 }
97 }
98 Event::Exit => {}
99 }
100 }
101
102 fn push(&mut self, s: &str) {
103 self.path.push(s.to_string());
104 }
105
106 fn pop(&mut self) {
107 self.path.pop();
108 }
109}