jsona_schema_validator/
validates.rs

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            // dot before local part is not valid
870            return false;
871        }
872        // This loop exits early if it finds `@`.
873        // Therefore, match arms examine only the local part
874        for (a, b) in value.chars().zip(value.chars().skip(1)) {
875            match (a, b) {
876                // two subsequent dots inside local part are not valid
877                // dot after local part is not valid
878                ('.', '.') | ('.', '@') => return false,
879                // The domain part is not validated for simplicity
880                (_, '@') => 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    // Based on implementation proposed by Sven Marnach:
938    // https://stackoverflow.com/questions/60882381/what-is-the-fastest-correct-way-to-detect-that-there-are-no-duplicates-in-a-json
939    #[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), // chosen randomly
948                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                        // We have no way of building a new hasher of type `H`, so we
968                        // hardcode using the default hasher of a hash map.
969                        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    // Empirically calculated threshold after which the validator resorts to hashing.
981    // Calculated for an array of mixed types, large homogenous arrays of primitive values might be
982    // processed faster with different thresholds, but this one gives a good baseline for the common
983    // case.
984    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            // Empty arrays and one-element arrays always contain unique elements
991            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            // If the array size is small enough we can compare all elements pairwise, which will
998            // be faster than calculating hashes for each element, even if the algorithm is O(N^2)
999            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
1054// ECMA 262 has differences
1055fn convert_regex(pattern: &str) -> Result<fancy_regex::Regex, fancy_regex::Error> {
1056    // replace control chars
1057    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    // To convert character group we need to iterate over chars and in case of `\` take a look
1061    // at the next char to detect whether this group should be converted
1062    while let Some(current) = chars.next() {
1063        if current == '\\' {
1064            // Possible character group
1065            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                        // Nothing interesting, push as is
1079                        out.push(current);
1080                        out.push(next)
1081                    }
1082                }
1083            } else {
1084                // End of the string, push the last char.
1085                // Note that it is an incomplete escape sequence and will lead to an error on
1086                // the next step
1087                out.push(current);
1088            }
1089        } else {
1090            // Regular character
1091            out.push(current);
1092        }
1093    }
1094    fancy_regex::Regex::new(&out)
1095}
1096
1097fn replace_control_group(captures: &regex::Captures) -> String {
1098    // There will be no overflow, because the minimum value is 65 (char 'A')
1099    ((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}