Skip to main content

icydb_core/traits/
visitor.rs

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