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
24/// Run the sanitizer visitor over a mutable visitable tree.
25pub fn sanitize(node: &mut dyn Visitable) {
26    let mut visitor = SanitizeVisitor::new();
27    perform_visit_mut(&mut visitor, node, PathSegment::Empty);
28}
29
30///
31/// Event
32///
33
34#[derive(Clone, Copy, Debug)]
35pub enum Event {
36    Enter,
37    Exit,
38}
39
40///
41/// PathSegment
42///
43
44#[derive(Debug)]
45pub enum PathSegment {
46    Empty,
47    Field(&'static str),
48    Index(usize),
49}
50
51impl From<&'static str> for PathSegment {
52    fn from(s: &'static str) -> Self {
53        Self::Field(s)
54    }
55}
56
57impl From<usize> for PathSegment {
58    fn from(i: usize) -> Self {
59        Self::Index(i)
60    }
61}
62
63impl From<Option<&'static str>> for PathSegment {
64    fn from(opt: Option<&'static str>) -> Self {
65        match opt {
66            Some(s) if !s.is_empty() => Self::Field(s),
67            _ => Self::Empty,
68        }
69    }
70}
71
72///
73/// Visitor
74/// plus helper functions that allow navigation of the tree in an object-safe way
75///
76
77pub trait Visitor {
78    // nodes
79    fn visit(&mut self, node: &dyn Visitable, event: Event);
80
81    // path
82    fn push(&mut self, _: PathSegment) {}
83    fn pop(&mut self) {}
84}
85
86// perform_visit
87#[inline]
88/// Walk an immutable visitable node with a visitor, pushing the provided path segment.
89pub fn perform_visit<S: Into<PathSegment>>(
90    visitor: &mut dyn Visitor,
91    node: &dyn Visitable,
92    seg: S,
93) {
94    let seg = seg.into();
95    let should_push = !matches!(seg, PathSegment::Empty);
96    if should_push {
97        visitor.push(seg);
98    }
99    visitor.visit(node, Event::Enter);
100    node.drive(visitor);
101    visitor.visit(node, Event::Exit);
102    if should_push {
103        visitor.pop();
104    }
105}
106
107#[inline]
108/// Walk a mutable visitable node with a visitor, pushing the provided path segment.
109pub fn perform_visit_mut<S: Into<PathSegment>>(
110    visitor: &mut dyn VisitorMut,
111    node: &mut dyn Visitable,
112    seg: S,
113) {
114    let seg = seg.into();
115    let should_push = !matches!(seg, PathSegment::Empty);
116    if should_push {
117        visitor.push(seg);
118    }
119    visitor.visit(node, Event::Enter);
120    node.drive_mut(visitor);
121    visitor.visit(node, Event::Exit);
122    if should_push {
123        visitor.pop();
124    }
125}
126
127///
128/// VisitorMut
129/// (adapted for mutable sanitization)
130///
131
132pub trait VisitorMut {
133    fn visit(&mut self, node: &mut dyn Visitable, event: Event);
134
135    fn push(&mut self, _: PathSegment) {}
136    fn pop(&mut self) {}
137}