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/// Walk an immutable visitable node with a visitor, pushing the provided path segment.
88pub fn perform_visit<S: Into<PathSegment>>(
89    visitor: &mut dyn Visitor,
90    node: &dyn Visitable,
91    seg: S,
92) {
93    let seg = seg.into();
94    let should_push = !matches!(seg, PathSegment::Empty);
95    if should_push {
96        visitor.push(seg);
97    }
98    visitor.visit(node, Event::Enter);
99    node.drive(visitor);
100    visitor.visit(node, Event::Exit);
101    if should_push {
102        visitor.pop();
103    }
104}
105
106/// Walk a mutable visitable node with a visitor, pushing the provided path segment.
107pub fn perform_visit_mut<S: Into<PathSegment>>(
108    visitor: &mut dyn VisitorMut,
109    node: &mut dyn Visitable,
110    seg: S,
111) {
112    let seg = seg.into();
113    let should_push = !matches!(seg, PathSegment::Empty);
114    if should_push {
115        visitor.push(seg);
116    }
117    visitor.visit(node, Event::Enter);
118    node.drive_mut(visitor);
119    visitor.visit(node, Event::Exit);
120    if should_push {
121        visitor.pop();
122    }
123}
124
125///
126/// VisitorMut
127/// (adapted for mutable sanitization)
128///
129
130pub trait VisitorMut {
131    fn visit(&mut self, node: &mut dyn Visitable, event: Event);
132
133    fn push(&mut self, _: PathSegment) {}
134    fn pop(&mut self) {}
135}