1use std::cell::RefCell;
10
11use eure_document::document::EureDocument;
12use eure_document::identifier::Identifier;
13use eure_document::parse::UnionTagMode;
14use eure_document::path::{EurePath, PathSegment};
15use eure_document::value::ObjectKey;
16
17use crate::{SchemaDocument, SchemaNodeContent, SchemaNodeId};
18
19use super::error::{ValidationError, ValidationWarning};
20
21#[derive(Debug, Clone, Default)]
27pub struct ValidationOutput {
28 pub is_valid: bool,
30 pub is_complete: bool,
32 pub errors: Vec<ValidationError>,
34 pub warnings: Vec<ValidationWarning>,
36}
37
38#[derive(Debug)]
46pub struct ValidationState {
47 pub path: EurePath,
49 pub has_holes: bool,
51 pub errors: Vec<ValidationError>,
53 pub warnings: Vec<ValidationWarning>,
55 pub(crate) variant_errors: Vec<(String, Vec<ValidationError>)>,
58}
59
60impl Default for ValidationState {
61 fn default() -> Self {
62 Self {
63 path: EurePath::root(),
64 has_holes: false,
65 errors: Vec::new(),
66 warnings: Vec::new(),
67 variant_errors: Vec::new(),
68 }
69 }
70}
71
72impl ValidationState {
73 pub fn new() -> Self {
74 Self::default()
75 }
76
77 pub fn record_error(&mut self, error: ValidationError) {
79 self.errors.push(error);
80 }
81
82 pub fn record_warning(&mut self, warning: ValidationWarning) {
84 self.warnings.push(warning);
85 }
86
87 pub fn mark_has_holes(&mut self) {
89 self.has_holes = true;
90 }
91
92 pub fn has_errors(&self) -> bool {
94 !self.errors.is_empty()
95 }
96
97 pub fn error_count(&self) -> usize {
99 self.errors.len()
100 }
101
102 pub fn push_path_ident(&mut self, ident: Identifier) {
108 self.path.0.push(PathSegment::Ident(ident));
109 }
110
111 pub fn push_path_key(&mut self, key: ObjectKey) {
113 self.path.0.push(PathSegment::Value(key));
114 }
115
116 pub fn push_path_index(&mut self, index: usize) {
118 self.path.0.push(PathSegment::ArrayIndex(Some(index)));
119 }
120
121 pub fn push_path_tuple_index(&mut self, index: u8) {
123 self.path.0.push(PathSegment::TupleIndex(index));
124 }
125
126 pub fn push_path_extension(&mut self, ident: Identifier) {
128 self.path.0.push(PathSegment::Extension(ident));
129 }
130
131 pub fn pop_path(&mut self) {
133 self.path.0.pop();
134 }
135
136 pub fn fork(&self) -> Self {
138 Self {
139 path: self.path.clone(),
140 has_holes: self.has_holes,
141 errors: Vec::new(),
142 warnings: Vec::new(),
143 variant_errors: Vec::new(), }
145 }
146
147 pub fn merge(&mut self, other: Self) {
149 self.has_holes |= other.has_holes;
150 self.errors.extend(other.errors);
151 self.warnings.extend(other.warnings);
152 }
153
154 pub fn finish(self) -> ValidationOutput {
156 ValidationOutput {
157 is_valid: self.errors.is_empty(),
158 is_complete: self.errors.is_empty() && !self.has_holes,
159 errors: self.errors,
160 warnings: self.warnings,
161 }
162 }
163
164 pub fn record_variant_errors(&mut self, variant_name: String, errors: Vec<ValidationError>) {
170 self.variant_errors.push((variant_name, errors));
171 }
172
173 pub fn take_variant_errors(&mut self) -> Vec<(String, Vec<ValidationError>)> {
175 std::mem::take(&mut self.variant_errors)
176 }
177
178 pub fn clear_variant_errors(&mut self) {
180 self.variant_errors.clear();
181 }
182}
183
184pub struct ValidationContext<'a> {
193 pub schema: &'a SchemaDocument,
195 pub document: &'a EureDocument,
197 pub state: RefCell<ValidationState>,
199 pub union_tag_mode: UnionTagMode,
201}
202
203impl<'a> ValidationContext<'a> {
204 pub fn new(document: &'a EureDocument, schema: &'a SchemaDocument) -> Self {
206 Self::with_mode(document, schema, UnionTagMode::default())
207 }
208
209 pub fn with_mode(
211 document: &'a EureDocument,
212 schema: &'a SchemaDocument,
213 union_tag_mode: UnionTagMode,
214 ) -> Self {
215 Self {
216 schema,
217 document,
218 state: RefCell::new(ValidationState::new()),
219 union_tag_mode,
220 }
221 }
222
223 pub fn with_state(
225 document: &'a EureDocument,
226 schema: &'a SchemaDocument,
227 state: ValidationState,
228 ) -> Self {
229 Self::with_state_and_mode(document, schema, state, UnionTagMode::default())
230 }
231
232 pub fn with_state_and_mode(
234 document: &'a EureDocument,
235 schema: &'a SchemaDocument,
236 state: ValidationState,
237 union_tag_mode: UnionTagMode,
238 ) -> Self {
239 Self {
240 schema,
241 document,
242 state: RefCell::new(state),
243 union_tag_mode,
244 }
245 }
246
247 pub fn record_error(&self, error: ValidationError) {
249 self.state.borrow_mut().record_error(error);
250 }
251
252 pub fn record_warning(&self, warning: ValidationWarning) {
254 self.state.borrow_mut().record_warning(warning);
255 }
256
257 pub fn mark_has_holes(&self) {
259 self.state.borrow_mut().mark_has_holes();
260 }
261
262 pub fn has_errors(&self) -> bool {
264 self.state.borrow().has_errors()
265 }
266
267 pub fn error_count(&self) -> usize {
269 self.state.borrow().error_count()
270 }
271
272 pub fn path(&self) -> EurePath {
274 self.state.borrow().path.clone()
275 }
276
277 pub fn push_path_ident(&self, ident: Identifier) {
279 self.state.borrow_mut().push_path_ident(ident);
280 }
281
282 pub fn push_path_key(&self, key: ObjectKey) {
284 self.state.borrow_mut().push_path_key(key);
285 }
286
287 pub fn push_path_index(&self, index: usize) {
289 self.state.borrow_mut().push_path_index(index);
290 }
291
292 pub fn push_path_tuple_index(&self, index: u8) {
294 self.state.borrow_mut().push_path_tuple_index(index);
295 }
296
297 pub fn push_path_extension(&self, ident: Identifier) {
299 self.state.borrow_mut().push_path_extension(ident);
300 }
301
302 pub fn pop_path(&self) {
304 self.state.borrow_mut().pop_path();
305 }
306
307 pub fn fork_state(&self) -> ValidationState {
309 self.state.borrow().fork()
310 }
311
312 pub fn merge_state(&self, other: ValidationState) {
314 self.state.borrow_mut().merge(other);
315 }
316
317 pub fn resolve_schema_content(&self, schema_id: SchemaNodeId) -> &SchemaNodeContent {
319 let mut current_id = schema_id;
320 for _ in 0..100 {
322 let content = &self.schema.node(current_id).content;
323 match content {
324 SchemaNodeContent::Reference(type_ref) => {
325 if type_ref.namespace.is_some() {
326 return content; }
328 if let Some(&resolved_id) = self.schema.types.get(&type_ref.name) {
329 current_id = resolved_id;
330 } else {
331 return content; }
333 }
334 _ => return content,
335 }
336 }
337 &self.schema.node(current_id).content
338 }
339
340 pub fn parse_context(
342 &self,
343 node_id: eure_document::document::NodeId,
344 ) -> eure_document::parse::ParseContext<'a> {
345 eure_document::parse::ParseContext::with_union_tag_mode(
346 self.document,
347 node_id,
348 self.union_tag_mode,
349 )
350 }
351
352 pub fn record_variant_errors(&self, variant_name: String, errors: Vec<ValidationError>) {
358 self.state
359 .borrow_mut()
360 .record_variant_errors(variant_name, errors);
361 }
362
363 pub fn take_variant_errors(&self) -> Vec<(String, Vec<ValidationError>)> {
365 self.state.borrow_mut().take_variant_errors()
366 }
367
368 pub fn clear_variant_errors(&self) {
370 self.state.borrow_mut().clear_variant_errors();
371 }
372
373 pub fn finish(self) -> ValidationOutput {
375 self.state.into_inner().finish()
376 }
377}