eure_schema/validate/
context.rs1use std::cell::RefCell;
10
11use eure_document::document::EureDocument;
12use eure_document::identifier::Identifier;
13use eure_document::path::{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.0.push(PathSegment::ArrayIndex(Some(index)));
118 }
119
120 pub fn push_path_tuple_index(&mut self, index: u8) {
122 self.path.0.push(PathSegment::TupleIndex(index));
123 }
124
125 pub fn push_path_extension(&mut self, ident: Identifier) {
127 self.path.0.push(PathSegment::Extension(ident));
128 }
129
130 pub fn pop_path(&mut self) {
132 self.path.0.pop();
133 }
134
135 pub fn fork(&self) -> Self {
137 Self {
138 path: self.path.clone(),
139 has_holes: self.has_holes,
140 errors: Vec::new(),
141 warnings: Vec::new(),
142 variant_errors: Vec::new(), }
144 }
145
146 pub fn merge(&mut self, other: Self) {
148 self.has_holes |= other.has_holes;
149 self.errors.extend(other.errors);
150 self.warnings.extend(other.warnings);
151 }
152
153 pub fn finish(self) -> ValidationOutput {
155 ValidationOutput {
156 is_valid: self.errors.is_empty(),
157 is_complete: self.errors.is_empty() && !self.has_holes,
158 errors: self.errors,
159 warnings: self.warnings,
160 }
161 }
162
163 pub fn record_variant_errors(
169 &mut self,
170 variant_name: String,
171 schema_id: SchemaNodeId,
172 errors: Vec<ValidationError>,
173 ) {
174 self.variant_errors.push((variant_name, schema_id, errors));
175 }
176
177 pub fn take_variant_errors(&mut self) -> Vec<(String, SchemaNodeId, Vec<ValidationError>)> {
179 std::mem::take(&mut self.variant_errors)
180 }
181
182 pub fn clear_variant_errors(&mut self) {
184 self.variant_errors.clear();
185 }
186}
187
188pub struct ValidationContext<'a> {
197 pub schema: &'a SchemaDocument,
199 pub document: &'a EureDocument,
201 pub state: RefCell<ValidationState>,
203}
204
205impl<'a> ValidationContext<'a> {
206 pub fn new(document: &'a EureDocument, schema: &'a SchemaDocument) -> Self {
208 Self {
209 schema,
210 document,
211 state: RefCell::new(ValidationState::new()),
212 }
213 }
214
215 pub fn with_state(
217 document: &'a EureDocument,
218 schema: &'a SchemaDocument,
219 state: ValidationState,
220 ) -> Self {
221 Self {
222 schema,
223 document,
224 state: RefCell::new(state),
225 }
226 }
227
228 pub fn record_error(&self, error: ValidationError) {
230 self.state.borrow_mut().record_error(error);
231 }
232
233 pub fn record_warning(&self, warning: ValidationWarning) {
235 self.state.borrow_mut().record_warning(warning);
236 }
237
238 pub fn mark_has_holes(&self) {
240 self.state.borrow_mut().mark_has_holes();
241 }
242
243 pub fn has_errors(&self) -> bool {
245 self.state.borrow().has_errors()
246 }
247
248 pub fn error_count(&self) -> usize {
250 self.state.borrow().error_count()
251 }
252
253 pub fn path(&self) -> EurePath {
255 self.state.borrow().path.clone()
256 }
257
258 pub fn push_path_ident(&self, ident: Identifier) {
260 self.state.borrow_mut().push_path_ident(ident);
261 }
262
263 pub fn push_path_key(&self, key: ObjectKey) {
265 self.state.borrow_mut().push_path_key(key);
266 }
267
268 pub fn push_path_index(&self, index: usize) {
270 self.state.borrow_mut().push_path_index(index);
271 }
272
273 pub fn push_path_tuple_index(&self, index: u8) {
275 self.state.borrow_mut().push_path_tuple_index(index);
276 }
277
278 pub fn push_path_extension(&self, ident: Identifier) {
280 self.state.borrow_mut().push_path_extension(ident);
281 }
282
283 pub fn pop_path(&self) {
285 self.state.borrow_mut().pop_path();
286 }
287
288 pub fn fork_state(&self) -> ValidationState {
290 self.state.borrow().fork()
291 }
292
293 pub fn merge_state(&self, other: ValidationState) {
295 self.state.borrow_mut().merge(other);
296 }
297
298 pub fn resolve_schema_content(&self, schema_id: SchemaNodeId) -> &SchemaNodeContent {
300 let mut current_id = schema_id;
301 for _ in 0..100 {
303 let content = &self.schema.node(current_id).content;
304 match content {
305 SchemaNodeContent::Reference(type_ref) => {
306 if type_ref.namespace.is_some() {
307 return content; }
309 if let Some(&resolved_id) = self.schema.types.get(&type_ref.name) {
310 current_id = resolved_id;
311 } else {
312 return content; }
314 }
315 _ => return content,
316 }
317 }
318 &self.schema.node(current_id).content
319 }
320
321 pub fn parse_context(
323 &self,
324 node_id: eure_document::document::NodeId,
325 ) -> eure_document::parse::ParseContext<'a> {
326 eure_document::parse::ParseContext::new(self.document, node_id)
327 }
328
329 pub fn record_variant_errors(
335 &self,
336 variant_name: String,
337 schema_id: SchemaNodeId,
338 errors: Vec<ValidationError>,
339 ) {
340 self.state
341 .borrow_mut()
342 .record_variant_errors(variant_name, schema_id, errors);
343 }
344
345 pub fn take_variant_errors(&self) -> Vec<(String, SchemaNodeId, Vec<ValidationError>)> {
347 self.state.borrow_mut().take_variant_errors()
348 }
349
350 pub fn clear_variant_errors(&self) {
352 self.state.borrow_mut().clear_variant_errors();
353 }
354
355 pub fn finish(self) -> ValidationOutput {
357 self.state.into_inner().finish()
358 }
359}