eure_schema/validate/
context.rs1use std::cell::RefCell;
10
11use eure_document::document::EureDocument;
12use eure_document::identifier::Identifier;
13use eure_document::path::{ArrayIndexKind, EurePath, PathSegment};
14use eure_document::value::ObjectKey;
15
16use crate::{SchemaDocument, SchemaNodeContent, SchemaNodeId};
17
18use super::error::{ValidationError, ValidationWarning};
19
20#[derive(Debug, Clone, Default)]
26pub struct ValidationOutput {
27 pub is_valid: bool,
29 pub is_complete: bool,
31 pub errors: Vec<ValidationError>,
33 pub warnings: Vec<ValidationWarning>,
35}
36
37#[derive(Debug)]
45pub struct ValidationState {
46 pub path: EurePath,
48 pub has_holes: bool,
50 pub errors: Vec<ValidationError>,
52 pub warnings: Vec<ValidationWarning>,
54 pub(crate) variant_errors: Vec<(String, SchemaNodeId, Vec<ValidationError>)>,
57}
58
59impl Default for ValidationState {
60 fn default() -> Self {
61 Self {
62 path: EurePath::root(),
63 has_holes: false,
64 errors: Vec::new(),
65 warnings: Vec::new(),
66 variant_errors: Vec::new(),
67 }
68 }
69}
70
71impl ValidationState {
72 pub fn new() -> Self {
73 Self::default()
74 }
75
76 pub fn record_error(&mut self, error: ValidationError) {
78 self.errors.push(error);
79 }
80
81 pub fn record_warning(&mut self, warning: ValidationWarning) {
83 self.warnings.push(warning);
84 }
85
86 pub fn mark_has_holes(&mut self) {
88 self.has_holes = true;
89 }
90
91 pub fn has_errors(&self) -> bool {
93 !self.errors.is_empty()
94 }
95
96 pub fn error_count(&self) -> usize {
98 self.errors.len()
99 }
100
101 pub fn push_path_ident(&mut self, ident: Identifier) {
107 self.path.0.push(PathSegment::Ident(ident));
108 }
109
110 pub fn push_path_key(&mut self, key: ObjectKey) {
112 self.path.0.push(PathSegment::Value(key));
113 }
114
115 pub fn push_path_index(&mut self, index: usize) {
117 self.path
118 .0
119 .push(PathSegment::ArrayIndex(ArrayIndexKind::Specific(index)));
120 }
121
122 pub fn push_path_tuple_index(&mut self, index: u8) {
124 self.path.0.push(PathSegment::TupleIndex(index));
125 }
126
127 pub fn push_path_extension(&mut self, ident: Identifier) {
129 self.path.0.push(PathSegment::Extension(ident));
130 }
131
132 pub fn pop_path(&mut self) {
134 self.path.0.pop();
135 }
136
137 pub fn fork(&self) -> Self {
139 Self {
140 path: self.path.clone(),
141 has_holes: self.has_holes,
142 errors: Vec::new(),
143 warnings: Vec::new(),
144 variant_errors: Vec::new(), }
146 }
147
148 pub fn merge(&mut self, other: Self) {
150 self.has_holes |= other.has_holes;
151 self.errors.extend(other.errors);
152 self.warnings.extend(other.warnings);
153 }
154
155 pub fn finish(self) -> ValidationOutput {
157 ValidationOutput {
158 is_valid: self.errors.is_empty(),
159 is_complete: self.errors.is_empty() && !self.has_holes,
160 errors: self.errors,
161 warnings: self.warnings,
162 }
163 }
164
165 pub fn record_variant_errors(
171 &mut self,
172 variant_name: String,
173 schema_id: SchemaNodeId,
174 errors: Vec<ValidationError>,
175 ) {
176 self.variant_errors.push((variant_name, schema_id, errors));
177 }
178
179 pub fn take_variant_errors(&mut self) -> Vec<(String, SchemaNodeId, Vec<ValidationError>)> {
181 std::mem::take(&mut self.variant_errors)
182 }
183
184 pub fn clear_variant_errors(&mut self) {
186 self.variant_errors.clear();
187 }
188}
189
190pub struct ValidationContext<'a> {
199 pub schema: &'a SchemaDocument,
201 pub document: &'a EureDocument,
203 pub state: RefCell<ValidationState>,
205}
206
207impl<'a> ValidationContext<'a> {
208 pub fn new(document: &'a EureDocument, schema: &'a SchemaDocument) -> Self {
210 Self {
211 schema,
212 document,
213 state: RefCell::new(ValidationState::new()),
214 }
215 }
216
217 pub fn with_state(
219 document: &'a EureDocument,
220 schema: &'a SchemaDocument,
221 state: ValidationState,
222 ) -> Self {
223 Self {
224 schema,
225 document,
226 state: RefCell::new(state),
227 }
228 }
229
230 pub fn record_error(&self, error: ValidationError) {
232 self.state.borrow_mut().record_error(error);
233 }
234
235 pub fn record_warning(&self, warning: ValidationWarning) {
237 self.state.borrow_mut().record_warning(warning);
238 }
239
240 pub fn mark_has_holes(&self) {
242 self.state.borrow_mut().mark_has_holes();
243 }
244
245 pub fn has_errors(&self) -> bool {
247 self.state.borrow().has_errors()
248 }
249
250 pub fn error_count(&self) -> usize {
252 self.state.borrow().error_count()
253 }
254
255 pub fn path(&self) -> EurePath {
257 self.state.borrow().path.clone()
258 }
259
260 pub fn push_path_ident(&self, ident: Identifier) {
262 self.state.borrow_mut().push_path_ident(ident);
263 }
264
265 pub fn push_path_key(&self, key: ObjectKey) {
267 self.state.borrow_mut().push_path_key(key);
268 }
269
270 pub fn push_path_index(&self, index: usize) {
272 self.state.borrow_mut().push_path_index(index);
273 }
274
275 pub fn push_path_tuple_index(&self, index: u8) {
277 self.state.borrow_mut().push_path_tuple_index(index);
278 }
279
280 pub fn push_path_extension(&self, ident: Identifier) {
282 self.state.borrow_mut().push_path_extension(ident);
283 }
284
285 pub fn pop_path(&self) {
287 self.state.borrow_mut().pop_path();
288 }
289
290 pub fn fork_state(&self) -> ValidationState {
292 self.state.borrow().fork()
293 }
294
295 pub fn merge_state(&self, other: ValidationState) {
297 self.state.borrow_mut().merge(other);
298 }
299
300 pub fn resolve_schema_content(&self, schema_id: SchemaNodeId) -> &SchemaNodeContent {
302 let mut current_id = schema_id;
303 for _ in 0..100 {
305 let content = &self.schema.node(current_id).content;
306 match content {
307 SchemaNodeContent::Reference(type_ref) => {
308 if type_ref.namespace.is_some() {
309 return content; }
311 if let Some(&resolved_id) = self.schema.types.get(&type_ref.name) {
312 current_id = resolved_id;
313 } else {
314 return content; }
316 }
317 _ => return content,
318 }
319 }
320 &self.schema.node(current_id).content
321 }
322
323 pub fn parse_context(
325 &self,
326 node_id: eure_document::document::NodeId,
327 ) -> eure_document::parse::ParseContext<'a> {
328 eure_document::parse::ParseContext::new(self.document, node_id)
329 }
330
331 pub fn record_variant_errors(
337 &self,
338 variant_name: String,
339 schema_id: SchemaNodeId,
340 errors: Vec<ValidationError>,
341 ) {
342 self.state
343 .borrow_mut()
344 .record_variant_errors(variant_name, schema_id, errors);
345 }
346
347 pub fn take_variant_errors(&self) -> Vec<(String, SchemaNodeId, Vec<ValidationError>)> {
349 self.state.borrow_mut().take_variant_errors()
350 }
351
352 pub fn clear_variant_errors(&self) {
354 self.state.borrow_mut().clear_variant_errors();
355 }
356
357 pub fn finish(self) -> ValidationOutput {
359 self.state.into_inner().finish()
360 }
361}