1use std::{
2 cmp::Ordering,
3 collections::HashSet,
4 fmt::{Display, Formatter},
5};
6
7use either::Either;
8use fancy_regex::Regex;
9use indexmap::IndexMap;
10use jsona::{
11 dom::{KeyOrIndex, Keys, Node},
12 error::ErrorObject,
13 util::mapper::Mapper,
14};
15use jsona_schema::{Schema, SchemaType, REF_REGEX};
16use once_cell::sync::Lazy;
17use std::ops::Index;
18
19const ERROR_SOURCE: &str = "validator";
20
21static TIME_RE: Lazy<Regex> = Lazy::new(|| {
22 Regex::new(r"^([01][0-9]|2[0-3]):([0-5][0-9]):([0-5][0-9])(\.[0-9]{6})?(([Zz])|([+|\-]([01][0-9]|2[0-3]):[0-5][0-9]))\z").unwrap()
23});
24static CONTROL_GROUPS_RE: Lazy<regex::Regex> =
25 Lazy::new(|| regex::Regex::new(r"\\c[A-Za-z]").unwrap());
26static UUID_RE: Lazy<Regex> = Lazy::new(|| {
27 Regex::new(
28 r"^[0-9a-fA-F]{8}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{12}$",
29 )
30 .unwrap()
31});
32
33pub fn validate(
34 defs: &IndexMap<String, Schema>,
35 schema: &Schema,
36 keys: &Keys,
37 node: &Node,
38) -> Vec<Error> {
39 let mut errors = vec![];
40 if let Some(schema) = resolve(defs, schema) {
41 validate_impl(&mut errors, defs, schema, keys, node);
42 }
43 errors
44}
45
46fn validate_impl(
47 errors: &mut Vec<Error>,
48 defs: &IndexMap<String, Schema>,
49 local_schema: &Schema,
50 keys: &Keys,
51 node: &Node,
52) {
53 let local_schema = match resolve(defs, local_schema) {
54 Some(v) => v,
55 None => return,
56 };
57 validate_type(errors, defs, local_schema, keys, node);
58 validate_enum(errors, defs, local_schema, keys, node);
59 validate_const(errors, defs, local_schema, keys, node);
60
61 if node.is_object() {
62 validate_properties(errors, defs, local_schema, keys, node);
63 validate_required(errors, defs, local_schema, keys, node);
64 validate_maxmin_properties(errors, defs, local_schema, keys, node);
65 }
66
67 if node.is_array() {
68 validate_items(errors, defs, local_schema, keys, node);
69 validate_contains(errors, defs, local_schema, keys, node);
70 validate_maxmin_items(errors, defs, local_schema, keys, node);
71 validate_unique_items(errors, defs, local_schema, keys, node);
72 }
73
74 if node.is_string() {
75 validate_pattern(errors, defs, local_schema, keys, node);
76 validate_maxmin_length(errors, defs, local_schema, keys, node);
77 validate_format(errors, defs, local_schema, keys, node);
78 }
79
80 if node.is_number() {
81 validate_maxmin(errors, defs, local_schema, keys, node);
82 validate_multiple_of(errors, defs, local_schema, keys, node);
83 }
84
85 validate_allof(errors, defs, local_schema, keys, node);
86 validate_anyof(errors, defs, local_schema, keys, node);
87 validate_oneof(errors, defs, local_schema, keys, node);
88 validate_not(errors, defs, local_schema, keys, node);
89 validate_condiational(errors, defs, local_schema, keys, node);
90}
91
92fn validate_type(
93 errors: &mut Vec<Error>,
94 _defs: &IndexMap<String, Schema>,
95 local_schema: &Schema,
96 keys: &Keys,
97 node: &Node,
98) {
99 let types = local_schema.types();
100 if types.is_empty() {
101 return;
102 }
103 let mut is_type_match = false;
104 for schema_type in types.iter() {
105 if schema_type.match_node(node) {
106 is_type_match = true;
107 break;
108 }
109 }
110 if !is_type_match {
111 errors.push(Error::new(
112 keys,
113 ErrorKind::Type {
114 types: types.into_iter().collect(),
115 },
116 ));
117 }
118}
119
120fn validate_enum(
121 errors: &mut Vec<Error>,
122 _defs: &IndexMap<String, Schema>,
123 local_schema: &Schema,
124 keys: &Keys,
125 node: &Node,
126) {
127 if let Some(enum_items) = local_schema.enum_value.as_ref() {
128 let value = node.to_plain_json();
129 let mut contains = false;
130 for enum_value in enum_items.iter() {
131 if is_matching(&value, enum_value) {
132 contains = true;
133 break;
134 }
135 }
136 if !contains {
137 errors.push(Error::new(keys, ErrorKind::Enum));
138 }
139 }
140}
141
142fn validate_const(
143 errors: &mut Vec<Error>,
144 _defs: &IndexMap<String, Schema>,
145 local_schema: &Schema,
146 keys: &Keys,
147 node: &Node,
148) {
149 if let Some(const_value) = local_schema.const_value.as_ref() {
150 let value = node.to_plain_json();
151 if !is_matching(&value, const_value) {
152 errors.push(Error::new(keys, ErrorKind::Const));
153 }
154 }
155}
156
157fn validate_properties(
158 errors: &mut Vec<Error>,
159 defs: &IndexMap<String, Schema>,
160 local_schema: &Schema,
161 keys: &Keys,
162 node: &Node,
163) {
164 let object = match node.as_object() {
165 Some(v) => v,
166 None => return,
167 };
168 for (key, value) in object.value().read().iter() {
169 let new_keys = keys.join(KeyOrIndex::property(key.value()));
170 let is_property_passed = if let Some(schema) = local_schema
171 .properties
172 .as_ref()
173 .and_then(|v| v.get(key.value()))
174 {
175 validate_impl(errors, defs, schema, &new_keys, value);
176 true
177 } else {
178 false
179 };
180 let mut is_pattern_passed = false;
181 if let Some(patterns) = local_schema.pattern_properties.as_ref() {
182 for (pat, schema) in patterns.iter() {
183 if let Ok(re) = Regex::new(pat) {
184 if let Ok(true) = re.is_match(key.value()) {
185 validate_impl(errors, defs, schema, &new_keys, value);
186 is_pattern_passed = true;
187 }
188 }
189 }
190 }
191 if is_property_passed || is_pattern_passed {
192 continue;
193 }
194
195 if let Some(additional_properties) = local_schema.additional_properties.as_ref() {
196 match additional_properties.value.as_ref() {
197 Either::Left(allowed) => {
198 if !allowed {
199 errors.push(Error::new(
200 keys,
201 ErrorKind::AdditionalProperties {
202 key: key.value().to_string(),
203 },
204 ));
205 }
206 }
207 Either::Right(schema) => validate_impl(errors, defs, schema, &new_keys, value),
208 }
209 }
210 }
211}
212
213fn validate_required(
214 errors: &mut Vec<Error>,
215 _defs: &IndexMap<String, Schema>,
216 local_schema: &Schema,
217 keys: &Keys,
218 node: &Node,
219) {
220 if let Some(required) = local_schema.required.as_ref() {
221 let object = match node.as_object() {
222 Some(v) => v,
223 None => return,
224 };
225 let mut miss: Vec<String> = vec![];
226 let map = object.value().read();
227 let object_keys: HashSet<&str> = map.iter().map(|(k, _)| k.value()).collect();
228 for key in required.iter() {
229 if object_keys.contains(key.as_str()) {
230 continue;
231 }
232 miss.push(key.to_string());
233 }
234 if !miss.is_empty() {
235 errors.push(Error::new(keys, ErrorKind::Required { keys: miss }));
236 }
237 }
238}
239
240fn validate_maxmin_properties(
241 errors: &mut Vec<Error>,
242 _defs: &IndexMap<String, Schema>,
243 local_schema: &Schema,
244 keys: &Keys,
245 node: &Node,
246) {
247 let object = match node.as_object() {
248 Some(v) => v,
249 None => return,
250 };
251 let len = object.value().read().len();
252 if let Some(max_properties) = local_schema.max_properties.as_ref() {
253 if len > *max_properties as usize {
254 errors.push(Error::new(keys, ErrorKind::MaxProperties));
255 }
256 }
257 if let Some(min_properties) = local_schema.min_properties.as_ref() {
258 if len < *min_properties as usize {
259 errors.push(Error::new(keys, ErrorKind::MinProperties));
260 }
261 }
262}
263
264fn validate_items(
265 errors: &mut Vec<Error>,
266 defs: &IndexMap<String, Schema>,
267 local_schema: &Schema,
268 keys: &Keys,
269 node: &Node,
270) {
271 if let Some(items) = local_schema.items.as_ref() {
272 let array = match node.as_array() {
273 Some(v) => v,
274 None => return,
275 };
276 match items.value.as_ref() {
277 Either::Left(schema) => {
278 for (idx, value) in array.value().read().iter().enumerate() {
279 let new_keys = keys.join(KeyOrIndex::Index(idx));
280 validate_impl(errors, defs, schema, &new_keys, value);
281 }
282 }
283 Either::Right(schemas) => {
284 let items = array.value().read();
285 for (idx, (value, schema)) in items.iter().zip(schemas.iter()).enumerate() {
286 let new_keys = keys.join(KeyOrIndex::Index(idx));
287 validate_impl(errors, defs, schema, &new_keys, value);
288 }
289 let schemas_len = schemas.len();
290 if items.len() > schemas_len {
291 if let Some(additional_items) = local_schema.additional_items.as_ref() {
292 match additional_items.value.as_ref() {
293 Either::Left(allowed) => {
294 if !allowed {
295 errors.push(Error::new(keys, ErrorKind::AdditionalItems));
296 }
297 }
298 Either::Right(schema) => {
299 for (idx, value) in items.iter().skip(schemas_len).enumerate() {
300 let new_keys = keys.join(KeyOrIndex::Index(idx + schemas_len));
301 validate_impl(errors, defs, schema, &new_keys, value);
302 }
303 }
304 }
305 }
306 }
307 }
308 }
309 }
310}
311
312fn validate_contains(
313 errors: &mut Vec<Error>,
314 defs: &IndexMap<String, Schema>,
315 local_schema: &Schema,
316 keys: &Keys,
317 node: &Node,
318) {
319 if let Some(schema) = local_schema.contains.as_ref() {
320 let array = match node.as_array() {
321 Some(v) => v,
322 None => return,
323 };
324 let mut any_matched = false;
325 for (idx, value) in array.value().read().iter().enumerate() {
326 let mut local_errors = vec![];
327 let new_keys = keys.join(KeyOrIndex::Index(idx));
328 validate_impl(&mut local_errors, defs, schema, &new_keys, value);
329 if local_errors.is_empty() {
330 any_matched = true;
331 break;
332 }
333 }
334 if !any_matched {
335 errors.push(Error::new(keys, ErrorKind::Contains))
336 }
337 }
338}
339
340fn validate_maxmin_items(
341 errors: &mut Vec<Error>,
342 _defs: &IndexMap<String, Schema>,
343 local_schema: &Schema,
344 keys: &Keys,
345 node: &Node,
346) {
347 let array = match node.as_array() {
348 Some(v) => v,
349 None => return,
350 };
351 if let Some(max_items) = local_schema.max_items {
352 if array.value().read().len() > max_items as usize {
353 errors.push(Error::new(keys, ErrorKind::MaxItems))
354 }
355 }
356 if let Some(min_items) = local_schema.min_items {
357 if array.value().read().len() < min_items as usize {
358 errors.push(Error::new(keys, ErrorKind::MinItems))
359 }
360 }
361}
362
363fn validate_unique_items(
364 errors: &mut Vec<Error>,
365 _defs: &IndexMap<String, Schema>,
366 local_schema: &Schema,
367 keys: &Keys,
368 node: &Node,
369) {
370 if let Some(unique_items) = local_schema.unique_items {
371 if !unique_items {
372 return;
373 }
374 let array = match node.as_array() {
375 Some(v) => v,
376 None => return,
377 };
378 let items: Vec<serde_json::Value> = array
379 .value()
380 .read()
381 .iter()
382 .map(|v| v.to_plain_json())
383 .collect();
384 if !equal::is_unique(&items) {
385 errors.push(Error::new(keys, ErrorKind::UniqueItems))
386 }
387 }
388}
389
390fn validate_pattern(
391 errors: &mut Vec<Error>,
392 _defs: &IndexMap<String, Schema>,
393 local_schema: &Schema,
394 keys: &Keys,
395 node: &Node,
396) {
397 if let Some(pattern) = local_schema.pattern.as_ref() {
398 let value = match node.as_string() {
399 Some(v) => v.value(),
400 None => return,
401 };
402 if let Ok(re) = convert_regex(pattern) {
403 if !matches!(re.is_match(value), Ok(true)) {
404 errors.push(Error::new(keys, ErrorKind::Pattern))
405 }
406 }
407 }
408}
409
410fn validate_maxmin_length(
411 errors: &mut Vec<Error>,
412 _defs: &IndexMap<String, Schema>,
413 local_schema: &Schema,
414 keys: &Keys,
415 node: &Node,
416) {
417 let value = match node.as_string() {
418 Some(v) => v.value(),
419 None => return,
420 };
421 if let Some(max_length) = local_schema.max_length.as_ref() {
422 if value.len() > *max_length as usize {
423 errors.push(Error::new(keys, ErrorKind::MaxLength))
424 }
425 }
426 if let Some(min_length) = local_schema.min_length.as_ref() {
427 if value.len() < *min_length as usize {
428 errors.push(Error::new(keys, ErrorKind::MinLength))
429 }
430 }
431}
432
433fn validate_format(
434 errors: &mut Vec<Error>,
435 _defs: &IndexMap<String, Schema>,
436 local_schema: &Schema,
437 keys: &Keys,
438 node: &Node,
439) {
440 if let Some(format) = local_schema.format.as_ref() {
441 let value = match node.as_string() {
442 Some(v) => v.value(),
443 None => return,
444 };
445 let valid = match format.as_str() {
446 "date" => formats::date(value),
447 "date-time" => formats::date_time(value),
448 "email" => formats::email(value),
449 "hostname" => formats::hostname(value),
450 "ipv4" => formats::ipv4(value),
451 "ipv6" => formats::ipv6(value),
452 "uri" => formats::uri(value),
453 "regex" => formats::regex(value),
454 "time" => formats::time(value),
455 "uuid" => formats::uuid(value),
456 _ => true,
457 };
458 if !valid {
459 errors.push(Error::new(keys, ErrorKind::Format))
460 }
461 }
462}
463
464fn validate_maxmin(
465 errors: &mut Vec<Error>,
466 _defs: &IndexMap<String, Schema>,
467 local_schema: &Schema,
468 keys: &Keys,
469 node: &Node,
470) {
471 let value = match node.as_number() {
472 Some(v) => v.value(),
473 None => return,
474 };
475 if let Some(maximum) = local_schema.maximum.as_ref() {
476 let mut valid = true;
477 if local_schema
478 .exclusive_maximum
479 .as_ref()
480 .copied()
481 .unwrap_or_default()
482 {
483 if value.as_f64() >= maximum.as_f64() {
484 valid = false;
485 }
486 } else if value.as_f64() > maximum.as_f64() {
487 valid = false;
488 }
489 if !valid {
490 errors.push(Error::new(keys, ErrorKind::Maximum))
491 }
492 }
493 if let Some(minimum) = local_schema.minimum.as_ref() {
494 let mut valid = true;
495 if local_schema
496 .exclusive_minimum
497 .as_ref()
498 .copied()
499 .unwrap_or_default()
500 {
501 if value.as_f64() <= minimum.as_f64() {
502 valid = false;
503 }
504 } else if value.as_f64() < minimum.as_f64() {
505 valid = false;
506 }
507 if !valid {
508 errors.push(Error::new(keys, ErrorKind::Minimum))
509 }
510 }
511}
512
513fn validate_multiple_of(
514 errors: &mut Vec<Error>,
515 _defs: &IndexMap<String, Schema>,
516 local_schema: &Schema,
517 keys: &Keys,
518 node: &Node,
519) {
520 if let Some(multiple_of) = local_schema.multiple_of.as_ref() {
521 let value = match node.as_number().and_then(|v| v.value().as_f64()) {
522 Some(v) => v,
523 None => return,
524 };
525 let valid = if (value.fract() == 0f64) && (multiple_of.fract() == 0f64) {
526 (value % multiple_of) == 0f64
527 } else {
528 let remainder: f64 = (value / multiple_of) % 1f64;
529 let remainder_less_than_epsilon = matches!(
530 remainder.partial_cmp(&f64::EPSILON),
531 None | Some(Ordering::Less)
532 );
533 let remainder_less_than_one = remainder < (1f64 - f64::EPSILON);
534 remainder_less_than_epsilon && remainder_less_than_one
535 };
536 if !valid {
537 errors.push(Error::new(keys, ErrorKind::MultipleOf))
538 }
539 }
540}
541
542fn validate_allof(
543 errors: &mut Vec<Error>,
544 defs: &IndexMap<String, Schema>,
545 local_schema: &Schema,
546 keys: &Keys,
547 node: &Node,
548) {
549 if let Some(all_off) = local_schema.all_of.as_ref() {
550 for schema in all_off.iter() {
551 validate_impl(errors, defs, schema, keys, node)
552 }
553 }
554}
555
556fn validate_anyof(
557 errors: &mut Vec<Error>,
558 defs: &IndexMap<String, Schema>,
559 local_schema: &Schema,
560 keys: &Keys,
561 node: &Node,
562) {
563 if let Some(any_of) = local_schema.any_of.as_ref() {
564 let mut collect_errors = vec![];
565 let mut valid = false;
566 for schema in any_of.iter() {
567 let mut local_errors = vec![];
568 validate_impl(&mut local_errors, defs, schema, keys, node);
569 if local_errors.is_empty() {
570 valid = true;
571 } else {
572 collect_errors.extend(local_errors);
573 }
574 }
575 if !valid {
576 errors.push(Error::new(
577 keys,
578 ErrorKind::AnyOf {
579 errors: collect_errors,
580 },
581 ));
582 }
583 }
584}
585
586fn validate_oneof(
587 errors: &mut Vec<Error>,
588 defs: &IndexMap<String, Schema>,
589 local_schema: &Schema,
590 keys: &Keys,
591 node: &Node,
592) {
593 if let Some(one_of) = local_schema.one_of.as_ref() {
594 let mut collect_errors = vec![];
595 let mut valid = 0;
596 let mut indexes = vec![];
597 for (index, schema) in one_of.iter().enumerate() {
598 let mut local_errors = vec![];
599 validate_impl(&mut local_errors, defs, schema, keys, node);
600 if local_errors.is_empty() {
601 valid += 1;
602 }
603 if local_errors
604 .iter()
605 .filter(|v| {
606 v.keys.len() > keys.len()
607 || !matches!(
608 v.kind,
609 ErrorKind::AdditionalProperties { .. } | ErrorKind::Type { .. }
610 )
611 })
612 .count()
613 > 0
614 {
615 indexes.push(index);
616 }
617 collect_errors.push(local_errors);
618 }
619 if valid == 1 {
620 return;
621 }
622 if valid == 0 && indexes.len() == 1 {
623 errors.extend(collect_errors.remove(indexes[0]))
624 } else {
625 errors.push(Error::new(
626 keys,
627 ErrorKind::OneOf {
628 errors: collect_errors.into_iter().flatten().collect(),
629 },
630 ));
631 }
632 }
633}
634
635fn validate_not(
636 errors: &mut Vec<Error>,
637 defs: &IndexMap<String, Schema>,
638 local_schema: &Schema,
639 keys: &Keys,
640 node: &Node,
641) {
642 if let Some(schema) = local_schema.not.as_ref() {
643 let mut local_errors = vec![];
644 validate_impl(&mut local_errors, defs, schema, keys, node);
645 if local_errors.is_empty() {
646 errors.push(Error::new(keys, ErrorKind::Not));
647 }
648 }
649}
650
651fn validate_condiational(
652 errors: &mut Vec<Error>,
653 defs: &IndexMap<String, Schema>,
654 local_schema: &Schema,
655 keys: &Keys,
656 node: &Node,
657) {
658 if let Some(if_schema) = local_schema.if_value.as_ref() {
659 let mut local_errors = vec![];
660 validate_impl(&mut local_errors, defs, if_schema, keys, node);
661 if local_errors.is_empty() {
662 if let Some(then_schema) = local_schema.then_value.as_ref() {
663 validate_impl(errors, defs, then_schema, keys, node);
664 }
665 } else if let Some(else_schema) = local_schema.else_value.as_ref() {
666 validate_impl(errors, defs, else_schema, keys, node);
667 }
668 }
669}
670
671#[derive(Debug)]
672pub struct Error {
673 pub keys: Keys,
674 pub kind: ErrorKind,
675}
676
677impl Error {
678 pub fn new(keys: &Keys, kind: ErrorKind) -> Self {
679 Self {
680 keys: keys.clone(),
681 kind,
682 }
683 }
684 pub fn to_error_object(&self, node: &Node, mapper: &Mapper) -> ErrorObject {
685 let message = self.to_string();
686 ErrorObject::new(
687 ERROR_SOURCE,
688 self.kind.name(),
689 message,
690 self.keys.mapper_range(node, mapper),
691 )
692 }
693}
694
695impl Display for Error {
696 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
697 write!(f, "{}: {}", self.keys, self.kind)
698 }
699}
700
701#[derive(Debug)]
702pub enum ErrorKind {
703 Type { types: Vec<SchemaType> },
704 Enum,
705 Const,
706 AdditionalProperties { key: String },
707 Required { keys: Vec<String> },
708 MaxProperties,
709 MinProperties,
710 AdditionalItems,
711 Contains,
712 MaxItems,
713 MinItems,
714 UniqueItems,
715 Pattern,
716 MaxLength,
717 MinLength,
718 Format,
719 Maximum,
720 Minimum,
721 MultipleOf,
722 AnyOf { errors: Vec<Error> },
723 OneOf { errors: Vec<Error> },
724 Not,
725}
726
727impl ErrorKind {
728 pub fn name(&self) -> &'static str {
729 match self {
730 ErrorKind::Type { .. } => "Type",
731 ErrorKind::Enum => "Enum",
732 ErrorKind::Const => "Const",
733 ErrorKind::AdditionalProperties { .. } => "AdditionalProperties",
734 ErrorKind::Required { .. } => "Required",
735 ErrorKind::MaxProperties => "MaxProperties",
736 ErrorKind::MinProperties => "MinProperties",
737 ErrorKind::AdditionalItems => "AdditionalItems",
738 ErrorKind::Contains => "Contains",
739 ErrorKind::MaxItems => "MaxItems",
740 ErrorKind::MinItems => "MinItems",
741 ErrorKind::UniqueItems => "UniqueItems",
742 ErrorKind::Pattern => "Pattern",
743 ErrorKind::MaxLength => "MaxLength",
744 ErrorKind::MinLength => "MinLength",
745 ErrorKind::Format => "Format",
746 ErrorKind::Maximum => "Maximum",
747 ErrorKind::Minimum => "Minimum",
748 ErrorKind::MultipleOf => "MultipleOf",
749 ErrorKind::AnyOf { .. } => "AnyOf",
750 ErrorKind::OneOf { .. } => "OneOf",
751 ErrorKind::Not => "Not",
752 }
753 }
754}
755
756impl Display for ErrorKind {
757 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
758 match self {
759 ErrorKind::Type { types } => write!(
760 f,
761 "The value must be any of: {}",
762 types
763 .iter()
764 .map(|v| v.to_string())
765 .collect::<Vec<String>>()
766 .join(",")
767 ),
768 ErrorKind::Enum => write!(f, "Enum conditions are not met"),
769 ErrorKind::Const => write!(f, "Const condition is not met"),
770 ErrorKind::AdditionalProperties { key } => {
771 write!(f, "Additional property '{}' is not allowed", key)
772 }
773 ErrorKind::Required { keys } => {
774 write!(f, "This properties {} is required", keys.join(","))
775 }
776 ErrorKind::MaxProperties => write!(f, "MaxProperties condition is not met"),
777 ErrorKind::MinProperties => write!(f, "MinProperties condition is not met"),
778 ErrorKind::AdditionalItems => write!(f, "Additional items are not allowed"),
779 ErrorKind::Contains => write!(f, "Contains condition is not met"),
780 ErrorKind::MaxItems => write!(f, "MaxItems condition is not met"),
781 ErrorKind::MinItems => write!(f, "MinItems condition is not met"),
782 ErrorKind::UniqueItems => write!(f, "UniqueItems condition is not met"),
783 ErrorKind::Pattern => write!(f, "Pattern condition is not met"),
784 ErrorKind::MinLength => write!(f, "MinLength condition is not met"),
785 ErrorKind::MaxLength => write!(f, "MaxLength condition is not met"),
786 ErrorKind::Format => write!(f, "Format condition is not met"),
787 ErrorKind::Maximum => write!(f, "Maximum condition is not met"),
788 ErrorKind::Minimum => write!(f, "Minimum condition is not met"),
789 ErrorKind::MultipleOf => write!(f, "MultipleOf condition is not met"),
790 ErrorKind::AnyOf { errors } => {
791 let mut extra = "".into();
792 if !errors.is_empty() {
793 extra = format!(
794 "; {}",
795 errors
796 .iter()
797 .map(|v| v.to_string())
798 .collect::<Vec<String>>()
799 .join("; ")
800 );
801 }
802 write!(f, "AnyOf conditions are not met{}", extra)
803 }
804 ErrorKind::OneOf { errors } => {
805 let mut extra = ", more than one valid".into();
806 if !errors.is_empty() {
807 extra = format!(
808 "; {}",
809 errors
810 .iter()
811 .map(|v| v.to_string())
812 .collect::<Vec<String>>()
813 .join("; ")
814 );
815 }
816 write!(f, "OneOf conditions are not met{}", extra)
817 }
818 ErrorKind::Not => write!(f, "Not condition is not met"),
819 }
820 }
821}
822
823fn resolve<'a>(defs: &'a IndexMap<String, Schema>, local_schema: &'a Schema) -> Option<&'a Schema> {
824 let schema = match local_schema.ref_value.as_ref() {
825 Some(ref_value) => {
826 match REF_REGEX
827 .captures(ref_value)
828 .ok()
829 .flatten()
830 .and_then(|v| v.get(1))
831 .and_then(|v| defs.get(v.as_str()))
832 {
833 Some(v) => v,
834 None => return None,
835 }
836 }
837 None => local_schema,
838 };
839 Some(schema)
840}
841
842fn is_matching(va: &serde_json::Value, vb: &serde_json::Value) -> bool {
843 match va {
844 serde_json::Value::Number(a) => match vb {
845 serde_json::Value::Number(b) => a.as_f64().unwrap() == b.as_f64().unwrap(),
846 _ => false,
847 },
848 _ => *va == *vb,
849 }
850}
851
852mod formats {
853 use super::*;
854 use std::net::IpAddr;
855 use std::str::FromStr;
856
857 pub(crate) fn date(value: &str) -> bool {
858 time::Date::parse(
859 value,
860 &time::macros::format_description!("[year]-[month]-[day]"),
861 )
862 .is_ok()
863 }
864 pub(crate) fn date_time(value: &str) -> bool {
865 time::OffsetDateTime::parse(value, &time::format_description::well_known::Rfc3339).is_ok()
866 }
867 pub(crate) fn email(value: &str) -> bool {
868 if let Some('.') = value.chars().next() {
869 return false;
871 }
872 for (a, b) in value.chars().zip(value.chars().skip(1)) {
875 match (a, b) {
876 ('.', '.') | ('.', '@') => return false,
879 (_, '@') => return true,
881 (_, _) => continue,
882 }
883 }
884 false
885 }
886 pub(crate) fn hostname(value: &str) -> bool {
887 !(value.ends_with('-')
888 || value.starts_with('-')
889 || value.is_empty()
890 || bytecount::num_chars(value.as_bytes()) > 255
891 || value
892 .chars()
893 .any(|c| !(c.is_alphanumeric() || c == '-' || c == '.'))
894 || value
895 .split('.')
896 .any(|part| bytecount::num_chars(part.as_bytes()) > 63))
897 }
898
899 pub(crate) fn ipv4(value: &str) -> bool {
900 if value.starts_with('0') {
901 return false;
902 }
903 match IpAddr::from_str(value) {
904 Ok(i) => i.is_ipv4(),
905 Err(_) => false,
906 }
907 }
908
909 pub(crate) fn ipv6(value: &str) -> bool {
910 match IpAddr::from_str(value) {
911 Ok(i) => i.is_ipv6(),
912 Err(_) => false,
913 }
914 }
915
916 pub(crate) fn uri(value: &str) -> bool {
917 url::Url::from_str(value).is_ok()
918 }
919
920 pub(crate) fn regex(value: &str) -> bool {
921 convert_regex(value).is_ok()
922 }
923
924 pub(crate) fn time(value: &str) -> bool {
925 matches!(TIME_RE.is_match(value), Ok(true))
926 }
927
928 pub(crate) fn uuid(value: &str) -> bool {
929 matches!(UUID_RE.is_match(value), Ok(true))
930 }
931}
932
933mod equal {
934 use ahash::{AHashSet, AHasher};
935 use serde_json::{Map, Value};
936 use std::hash::{Hash, Hasher};
937 #[derive(PartialEq)]
940 pub(crate) struct HashedValue<'a>(&'a Value);
941
942 impl Eq for HashedValue<'_> {}
943
944 impl Hash for HashedValue<'_> {
945 fn hash<H: Hasher>(&self, state: &mut H) {
946 match self.0 {
947 Value::Null => state.write_u32(3_221_225_473), Value::Bool(ref item) => item.hash(state),
949 Value::Number(ref item) => {
950 if let Some(number) = item.as_u64() {
951 number.hash(state);
952 } else if let Some(number) = item.as_i64() {
953 number.hash(state);
954 } else if let Some(number) = item.as_f64() {
955 number.to_bits().hash(state)
956 }
957 }
958 Value::String(ref item) => item.hash(state),
959 Value::Array(ref items) => {
960 for item in items {
961 HashedValue(item).hash(state);
962 }
963 }
964 Value::Object(ref items) => {
965 let mut hash = 0;
966 for (key, value) in items {
967 let mut item_hasher = AHasher::default();
970 key.hash(&mut item_hasher);
971 HashedValue(value).hash(&mut item_hasher);
972 hash ^= item_hasher.finish();
973 }
974 state.write_u64(hash);
975 }
976 }
977 }
978 }
979
980 const ITEMS_SIZE_THRESHOLD: usize = 15;
985
986 #[inline]
987 pub(crate) fn is_unique(items: &[Value]) -> bool {
988 let size = items.len();
989 if size <= 1 {
990 true
992 } else if let [first, second] = items {
993 !equal(first, second)
994 } else if let [first, second, third] = items {
995 !equal(first, second) && !equal(first, third) && !equal(second, third)
996 } else if size <= ITEMS_SIZE_THRESHOLD {
997 let mut idx = 0_usize;
1000 while idx < items.len() {
1001 let mut inner_idx = idx + 1;
1002 while inner_idx < items.len() {
1003 if equal(&items[idx], &items[inner_idx]) {
1004 return false;
1005 }
1006 inner_idx += 1;
1007 }
1008 idx += 1;
1009 }
1010 true
1011 } else {
1012 let mut seen = AHashSet::with_capacity(size);
1013 items.iter().map(HashedValue).all(move |x| seen.insert(x))
1014 }
1015 }
1016
1017 #[inline]
1018 pub(crate) fn equal(left: &Value, right: &Value) -> bool {
1019 match (left, right) {
1020 (Value::String(left), Value::String(right)) => left == right,
1021 (Value::Bool(left), Value::Bool(right)) => left == right,
1022 (Value::Null, Value::Null) => true,
1023 (Value::Number(left), Value::Number(right)) => left.as_f64() == right.as_f64(),
1024 (Value::Array(left), Value::Array(right)) => equal_arrays(left, right),
1025 (Value::Object(left), Value::Object(right)) => equal_objects(left, right),
1026 (_, _) => false,
1027 }
1028 }
1029
1030 #[inline]
1031 pub(crate) fn equal_arrays(left: &[Value], right: &[Value]) -> bool {
1032 left.len() == right.len() && {
1033 let mut idx = 0_usize;
1034 while idx < left.len() {
1035 if !equal(&left[idx], &right[idx]) {
1036 return false;
1037 }
1038 idx += 1;
1039 }
1040 true
1041 }
1042 }
1043
1044 #[inline]
1045 pub(crate) fn equal_objects(left: &Map<String, Value>, right: &Map<String, Value>) -> bool {
1046 left.len() == right.len()
1047 && left
1048 .iter()
1049 .zip(right)
1050 .all(|((ka, va), (kb, vb))| ka == kb && equal(va, vb))
1051 }
1052}
1053
1054fn convert_regex(pattern: &str) -> Result<fancy_regex::Regex, fancy_regex::Error> {
1056 let new_pattern = CONTROL_GROUPS_RE.replace_all(pattern, replace_control_group);
1058 let mut out = String::with_capacity(new_pattern.len());
1059 let mut chars = new_pattern.chars().peekable();
1060 while let Some(current) = chars.next() {
1063 if current == '\\' {
1064 if let Some(next) = chars.next() {
1066 match next {
1067 'd' => out.push_str("[0-9]"),
1068 'D' => out.push_str("[^0-9]"),
1069 'w' => out.push_str("[A-Za-z0-9_]"),
1070 'W' => out.push_str("[^A-Za-z0-9_]"),
1071 's' => {
1072 out.push_str("[ \t\n\r\u{000b}\u{000c}\u{2003}\u{feff}\u{2029}\u{00a0}]")
1073 }
1074 'S' => {
1075 out.push_str("[^ \t\n\r\u{000b}\u{000c}\u{2003}\u{feff}\u{2029}\u{00a0}]")
1076 }
1077 _ => {
1078 out.push(current);
1080 out.push(next)
1081 }
1082 }
1083 } else {
1084 out.push(current);
1088 }
1089 } else {
1090 out.push(current);
1092 }
1093 }
1094 fancy_regex::Regex::new(&out)
1095}
1096
1097fn replace_control_group(captures: ®ex::Captures) -> String {
1098 ((captures
1100 .index(0)
1101 .trim_start_matches(r"\c")
1102 .chars()
1103 .next()
1104 .expect("This is always present because of the regex rule. It has [A-Za-z] next")
1105 .to_ascii_uppercase() as u8
1106 - 64) as char)
1107 .to_string()
1108}