icydb_core/visitor/
mod.rs

1pub mod sanitize;
2pub mod validate;
3
4pub use sanitize::*;
5pub use validate::*;
6
7use crate::{ThisError, traits::Visitable, visitor::SanitizeVisitor};
8
9///
10/// VisitorError
11///
12
13#[derive(Debug, ThisError)]
14pub enum VisitorError {
15    #[error(transparent)]
16    ValidateError(#[from] validate::ValidateError),
17}
18
19///
20/// MAIN FUNCTIONS
21///
22
23// sanitize
24pub fn sanitize(node: &mut dyn Visitable) {
25    let mut visitor = SanitizeVisitor::new();
26    perform_visit_mut(&mut visitor, node, PathSegment::Empty);
27}
28
29///
30/// Event
31///
32
33#[derive(Clone, Copy, Debug)]
34pub enum Event {
35    Enter,
36    Exit,
37}
38
39///
40/// PathSegment
41///
42
43#[derive(Debug)]
44pub enum PathSegment {
45    Empty,
46    Field(&'static str),
47    Index(usize),
48}
49
50impl From<&'static str> for PathSegment {
51    fn from(s: &'static str) -> Self {
52        Self::Field(s)
53    }
54}
55
56impl From<usize> for PathSegment {
57    fn from(i: usize) -> Self {
58        Self::Index(i)
59    }
60}
61
62impl From<Option<&'static str>> for PathSegment {
63    fn from(opt: Option<&'static str>) -> Self {
64        match opt {
65            Some(s) if !s.is_empty() => Self::Field(s),
66            _ => Self::Empty,
67        }
68    }
69}
70
71///
72/// Visitor
73/// plus helper functions that allow navigation of the tree in an object-safe way
74///
75
76pub trait Visitor {
77    // nodes
78    fn visit(&mut self, node: &dyn Visitable, event: Event);
79
80    // path
81    fn push(&mut self, _: PathSegment) {}
82    fn pop(&mut self) {}
83}
84
85// perform_visit
86#[inline]
87pub fn perform_visit<S: Into<PathSegment>>(
88    visitor: &mut dyn Visitor,
89    node: &dyn Visitable,
90    seg: S,
91) {
92    let seg = seg.into();
93    let should_push = !matches!(seg, PathSegment::Empty);
94    if should_push {
95        visitor.push(seg);
96    }
97    visitor.visit(node, Event::Enter);
98    node.drive(visitor);
99    visitor.visit(node, Event::Exit);
100    if should_push {
101        visitor.pop();
102    }
103}
104
105#[inline]
106pub fn perform_visit_mut<S: Into<PathSegment>>(
107    visitor: &mut dyn VisitorMut,
108    node: &mut dyn Visitable,
109    seg: S,
110) {
111    let seg = seg.into();
112    let should_push = !matches!(seg, PathSegment::Empty);
113    if should_push {
114        visitor.push(seg);
115    }
116    visitor.visit(node, Event::Enter);
117    node.drive_mut(visitor);
118    visitor.visit(node, Event::Exit);
119    if should_push {
120        visitor.pop();
121    }
122}
123
124///
125/// VisitorMut
126/// (adapted for mutable sanitization)
127///
128
129pub trait VisitorMut {
130    fn visit(&mut self, node: &mut dyn Visitable, event: Event);
131
132    fn push(&mut self, _: PathSegment) {}
133    fn pop(&mut self) {}
134}