icydb_core/traits/
visitor.rs

1use crate::visitor::{
2    PathSegment, VisitorContext, VisitorCore, VisitorMutCore, perform_visit, perform_visit_mut,
3};
4
5//
6// ============================================================================
7// Visitable
8// ============================================================================
9//
10
11/// A node that participates in visitor-based traversal.
12///
13/// Invariants:
14/// - Traversal is owned by the visitor, not by sanitize/validate hooks.
15/// - `drive` / `drive_mut` describe *structure only*.
16/// - No validation or sanitization logic lives here.
17pub trait Visitable: Sanitize + Validate {
18    fn drive(&self, _: &mut dyn VisitorCore) {}
19    fn drive_mut(&mut self, _: &mut dyn VisitorMutCore) {}
20}
21
22//
23// -------------------- Container forwarding --------------------
24//
25
26impl<T: Visitable> Visitable for Option<T> {
27    fn drive(&self, visitor: &mut dyn VisitorCore) {
28        if let Some(value) = self.as_ref() {
29            perform_visit(visitor, value, PathSegment::Empty);
30        }
31    }
32
33    fn drive_mut(&mut self, visitor: &mut dyn VisitorMutCore) {
34        if let Some(value) = self.as_mut() {
35            perform_visit_mut(visitor, value, PathSegment::Empty);
36        }
37    }
38}
39
40impl<T: Visitable> Visitable for Vec<T> {
41    fn drive(&self, visitor: &mut dyn VisitorCore) {
42        for (i, value) in self.iter().enumerate() {
43            perform_visit(visitor, value, i);
44        }
45    }
46
47    fn drive_mut(&mut self, visitor: &mut dyn VisitorMutCore) {
48        for (i, value) in self.iter_mut().enumerate() {
49            perform_visit_mut(visitor, value, i);
50        }
51    }
52}
53
54impl<T: Visitable + ?Sized> Visitable for Box<T> {
55    fn drive(&self, visitor: &mut dyn VisitorCore) {
56        (**self).drive(visitor);
57    }
58
59    fn drive_mut(&mut self, visitor: &mut dyn VisitorMutCore) {
60        (**self).drive_mut(visitor);
61    }
62}
63
64// Primitive leaf nodes: no structure
65impl_primitive!(Visitable);
66
67//
68// ============================================================================
69// Sanitize
70// ============================================================================
71//
72
73/// Marker trait: a type supports sanitization.
74pub trait Sanitize: SanitizeAuto + SanitizeCustom {}
75
76impl<T> Sanitize for T where T: SanitizeAuto + SanitizeCustom {}
77
78//
79// -------------------- SanitizeAuto --------------------
80//
81
82/// Schema-defined sanitization for this node only.
83///
84/// Rules:
85/// - May mutate only `self`
86/// - Must NOT recurse
87/// - Must NOT fail-fast
88/// - Must report issues via `VisitorContext`
89pub trait SanitizeAuto {
90    fn sanitize_self(&mut self, _ctx: &mut dyn VisitorContext) {}
91}
92
93impl<T: SanitizeAuto> SanitizeAuto for Option<T> {
94    fn sanitize_self(&mut self, ctx: &mut dyn VisitorContext) {
95        if let Some(v) = self.as_mut() {
96            v.sanitize_self(ctx);
97        }
98    }
99}
100
101impl<T: SanitizeAuto> SanitizeAuto for Vec<T> {
102    fn sanitize_self(&mut self, ctx: &mut dyn VisitorContext) {
103        for v in self.iter_mut() {
104            v.sanitize_self(ctx);
105        }
106    }
107}
108
109impl<T: SanitizeAuto + ?Sized> SanitizeAuto for Box<T> {
110    fn sanitize_self(&mut self, ctx: &mut dyn VisitorContext) {
111        (**self).sanitize_self(ctx);
112    }
113}
114
115impl_primitive!(SanitizeAuto);
116
117//
118// -------------------- SanitizeCustom --------------------
119//
120
121/// User-defined sanitization hooks.
122///
123/// Same rules as `SanitizeAuto`.
124pub trait SanitizeCustom {
125    fn sanitize_custom(&mut self, _ctx: &mut dyn VisitorContext) {}
126}
127
128impl<T: SanitizeCustom> SanitizeCustom for Option<T> {
129    fn sanitize_custom(&mut self, ctx: &mut dyn VisitorContext) {
130        if let Some(v) = self.as_mut() {
131            v.sanitize_custom(ctx);
132        }
133    }
134}
135
136impl<T: SanitizeCustom> SanitizeCustom for Vec<T> {
137    fn sanitize_custom(&mut self, ctx: &mut dyn VisitorContext) {
138        for v in self.iter_mut() {
139            v.sanitize_custom(ctx);
140        }
141    }
142}
143
144impl<T: SanitizeCustom + ?Sized> SanitizeCustom for Box<T> {
145    fn sanitize_custom(&mut self, ctx: &mut dyn VisitorContext) {
146        (**self).sanitize_custom(ctx);
147    }
148}
149
150impl_primitive!(SanitizeCustom);
151
152//
153// ============================================================================
154// Validate
155// ============================================================================
156//
157
158/// Marker trait: a type supports validation.
159pub trait Validate: ValidateAuto + ValidateCustom {}
160
161impl<T> Validate for T where T: ValidateAuto + ValidateCustom {}
162
163//
164// -------------------- ValidateAuto --------------------
165//
166
167/// Schema-defined validation for this node only.
168///
169/// Rules:
170/// - Must NOT recurse
171/// - Must NOT aggregate
172/// - Must NOT return errors
173/// - Must report issues via `VisitorContext`
174pub trait ValidateAuto {
175    fn validate_self(&self, _ctx: &mut dyn VisitorContext) {}
176}
177
178impl<T: ValidateAuto> ValidateAuto for Option<T> {
179    fn validate_self(&self, ctx: &mut dyn VisitorContext) {
180        if let Some(v) = self.as_ref() {
181            v.validate_self(ctx);
182        }
183    }
184}
185
186impl<T: ValidateAuto> ValidateAuto for Vec<T> {
187    fn validate_self(&self, ctx: &mut dyn VisitorContext) {
188        for v in self {
189            v.validate_self(ctx);
190        }
191    }
192}
193
194impl<T: ValidateAuto + ?Sized> ValidateAuto for Box<T> {
195    fn validate_self(&self, ctx: &mut dyn VisitorContext) {
196        (**self).validate_self(ctx);
197    }
198}
199
200impl_primitive!(ValidateAuto);
201
202//
203// -------------------- ValidateCustom --------------------
204//
205
206/// User-defined validation hooks.
207///
208/// Same rules as `ValidateAuto`.
209pub trait ValidateCustom {
210    fn validate_custom(&self, _ctx: &mut dyn VisitorContext) {}
211}
212
213impl<T: ValidateCustom> ValidateCustom for Option<T> {
214    fn validate_custom(&self, ctx: &mut dyn VisitorContext) {
215        if let Some(v) = self.as_ref() {
216            v.validate_custom(ctx);
217        }
218    }
219}
220
221impl<T: ValidateCustom> ValidateCustom for Vec<T> {
222    fn validate_custom(&self, ctx: &mut dyn VisitorContext) {
223        for v in self {
224            v.validate_custom(ctx);
225        }
226    }
227}
228
229impl<T: ValidateCustom + ?Sized> ValidateCustom for Box<T> {
230    fn validate_custom(&self, ctx: &mut dyn VisitorContext) {
231        (**self).validate_custom(ctx);
232    }
233}
234
235impl_primitive!(ValidateCustom);