1use super::utils::TryValue;
16use super::SchemaError::{self, UnexpectedValue};
17use super::{subschema::Subschema, ValidationError};
18use regex::Regex;
19use serde_json::{json, Number, Value};
20use std::{cmp::Ordering, collections::HashSet};
21
22#[derive(Debug, PartialEq)]
25pub enum InstanceType {
26 Null,
28 Boolean,
30 Object,
32 Array,
34 Number,
36 Integer,
38 String,
40}
41
42impl<'a> TryFrom<&'a str> for InstanceType {
43 type Error = SchemaError<'a>;
44
45 fn try_from(s: &'a str) -> Result<Self, Self::Error> {
46 match s {
47 "null" => Ok(InstanceType::Null),
48 "boolean" => Ok(InstanceType::Boolean),
49 "object" => Ok(InstanceType::Object),
50 "array" => Ok(InstanceType::Array),
51 "number" => Ok(InstanceType::Number),
52 "integer" => Ok(InstanceType::Integer),
53 "string" => Ok(InstanceType::String),
54 _ => Err(SchemaError::UnkownInstanceType(s)),
55 }
56 }
57}
58impl<'a> TryFrom<&'a String> for InstanceType {
59 type Error = SchemaError<'a>;
60
61 fn try_from(s: &'a String) -> Result<Self, Self::Error> {
62 Self::try_from(s as &str)
63 }
64}
65
66impl PartialEq<Value> for InstanceType {
67 fn eq(&self, other: &Value) -> bool {
68 match self {
69 InstanceType::Null => other.is_null(),
70 InstanceType::Boolean => other.is_boolean(),
71 InstanceType::Object => other.is_object(),
72 InstanceType::Array => other.is_array(),
73 InstanceType::Number => other.is_number(),
74 InstanceType::Integer => {
75 other.as_number().map_or(false, |n| n.as_f64().map_or(true, |n| n.fract() == 0.0))
76 }
77 InstanceType::String => other.is_string(),
78 }
79 }
80}
81
82#[derive(Debug)]
84pub enum SchemaAssertion<'a> {
85 Type(Vec<InstanceType>),
88 Enum(&'a Vec<Value>),
91 Const(&'a Value),
93 Pattern(Regex),
95 Minimum(&'a Number),
98 ExclusiveMinimum(&'a Number),
100 Maximum(&'a Number),
103 ExclusiveMaximum(&'a Number),
105 MaxItems(&'a Number),
108 MinItems(&'a Number),
111 UniqueItems(bool),
114 Required(HashSet<&'a str>),
117 }
129
130impl<'a> SchemaAssertion<'a> {
131 pub fn try_new_type(value: &Value) -> Result<Self, SchemaError> {
134 Ok(SchemaAssertion::Type(match value {
135 Value::String(str) => vec![str.try_into()?],
136 Value::Array(arr) => {
137 arr.iter().map(|s| s.try_str()?.try_into()).collect::<Result<Vec<_>, _>>()?
138 }
139 _ => return Err(UnexpectedValue { expected: "string or array", value }),
140 }))
141 }
142
143 pub fn try_new_enum(v: &'a Value) -> Result<Self, SchemaError<'a>> {
146 let arr = v.try_array()?;
147 if arr.len() > 0 {
148 Ok(SchemaAssertion::Enum(arr))
149 } else {
150 Err(SchemaError::UnexpectedValue { expected: "non-empty array", value: v })
151 }
152 }
153
154 pub fn new_const(v: &'a Value) -> Self {
156 SchemaAssertion::Const(v)
157 }
158
159 pub fn try_new_pattern(v: &'a Value) -> Result<Self, SchemaError<'a>> {
162 Ok(SchemaAssertion::Pattern(Regex::new(v.try_str()?).map_err(SchemaError::RegexError)?))
163 }
164
165 pub fn try_new_min(v: &'a Value) -> Result<Self, SchemaError<'a>> {
168 Ok(SchemaAssertion::Minimum(v.try_number()?))
169 }
170
171 pub fn try_new_xmin(v: &'a Value) -> Result<Self, SchemaError<'a>> {
174 Ok(SchemaAssertion::ExclusiveMinimum(v.try_number()?))
175 }
176
177 pub fn try_new_max(v: &'a Value) -> Result<Self, SchemaError<'a>> {
180 Ok(SchemaAssertion::Maximum(v.try_number()?))
181 }
182
183 pub fn try_new_xmax(v: &'a Value) -> Result<Self, SchemaError<'a>> {
186 Ok(SchemaAssertion::ExclusiveMaximum(v.try_number()?))
187 }
188
189 pub fn try_new_min_items(v: &'a Value) -> Result<Self, SchemaError<'a>> {
192 Ok(SchemaAssertion::MinItems(v.try_number()?))
193 }
194
195 pub fn try_new_max_items(v: &'a Value) -> Result<Self, SchemaError<'a>> {
198 Ok(SchemaAssertion::MaxItems(v.try_number()?))
199 }
200
201 pub fn try_new_unique_items(v: &'a Value) -> Result<Self, SchemaError<'a>> {
204 Ok(SchemaAssertion::UniqueItems(v.try_bool()?))
205 }
206
207 pub fn try_new_required(v: &'a Value) -> Result<Self, SchemaError<'a>> {
210 Ok(SchemaAssertion::Required(
211 v.try_array()?.iter().map(|v| v.try_str()).collect::<Result<HashSet<_>, _>>()?,
212 ))
213 }
214
215 pub fn validate<'i>(
216 &self,
217 instance: &'i Value,
218 subschema: &'a Subschema<'a>,
219 ) -> Result<(), ValidationError<'i, 'a>> {
220 if match self {
221 SchemaAssertion::Type(vec) => vec.iter().any(|t| t == instance),
222 SchemaAssertion::Enum(vec) => vec.contains(instance),
223 SchemaAssertion::Const(value) => *value == instance,
224 SchemaAssertion::Pattern(re) => instance.as_str().map_or(true, |s| re.is_match(s)),
225 SchemaAssertion::Minimum(limit) => {
226 instance.as_number().map_or(true, |n| compare(n, limit).is_ge())
227 }
228 SchemaAssertion::ExclusiveMinimum(limit) => {
229 instance.as_number().map_or(true, |n| compare(n, limit).is_gt())
230 }
231 SchemaAssertion::Maximum(limit) => {
232 instance.as_number().map_or(true, |n| compare(n, limit).is_le())
233 }
234 SchemaAssertion::ExclusiveMaximum(limit) => {
235 instance.as_number().map_or(true, |n| compare(n, limit).is_lt())
236 }
237 SchemaAssertion::MaxItems(limit) => {
238 instance.as_array().map_or(true, |a| compare(&Number::from(a.len()), limit).is_le())
239 }
240 SchemaAssertion::MinItems(limit) => {
241 instance.as_array().map_or(true, |a| compare(&Number::from(a.len()), limit).is_ge())
242 }
243 SchemaAssertion::UniqueItems(unique) => {
244 let mut seen = HashSet::new();
245 instance.as_array().map_or(true, |a| !unique || a.iter().all(|v| seen.insert(v)))
246 }
247 SchemaAssertion::Required(req) => {
248 instance.as_object().map_or(true, |o| req.iter().all(|p| o.contains_key(*p)))
249 }
250 } {
251 Ok(())
252 } else {
253 Err(ValidationError { instance, subschema })
254 }
255 }
256}
257
258fn compare(left: &Number, right: &Number) -> Ordering {
259 left.as_f64().unwrap().partial_cmp(&right.as_f64().unwrap()).unwrap()
261}
262
263#[cfg(test)]
264mod test {
265 use super::*;
266 use Subschema::Bool;
267
268 #[test]
269 fn test_instance_type_parse() {
270 assert_eq!(InstanceType::try_from("null").unwrap(), InstanceType::Null);
271 assert_eq!(InstanceType::try_from("boolean").unwrap(), InstanceType::Boolean);
272 assert_eq!(InstanceType::try_from("object").unwrap(), InstanceType::Object);
273 assert_eq!(InstanceType::try_from("array").unwrap(), InstanceType::Array);
274 assert_eq!(InstanceType::try_from("number").unwrap(), InstanceType::Number);
275 assert_eq!(InstanceType::try_from("integer").unwrap(), InstanceType::Integer);
276 assert_eq!(InstanceType::try_from("string").unwrap(), InstanceType::String);
277 assert!(InstanceType::try_from("somethingElse").is_err());
278 }
279
280 #[test]
281 fn test_instance_type_value_partial_equality() {
282 assert_eq!(InstanceType::Null, json!(null));
283 assert_eq!(InstanceType::Boolean, json!(true));
284 assert_eq!(InstanceType::Object, json!({"key":42}));
285 assert_eq!(InstanceType::Array, json!([42]));
286 assert_eq!(InstanceType::Number, json!(42));
287 assert_eq!(InstanceType::Number, json!(42.42));
288 assert_eq!(InstanceType::Integer, json!(42));
289 assert_ne!(InstanceType::Integer, json!(42.42));
290 assert_eq!(InstanceType::String, json!("str"));
291 }
292
293 #[test]
294 fn test_new_type() {
295 assert!(matches!(
296 SchemaAssertion::try_new_type(&json!("integer")),
297 Ok(SchemaAssertion::Type(v)) if v == &[InstanceType::Integer]
298 ));
299 assert!(matches!(SchemaAssertion::try_new_type(&json!(42)), Err(_)));
300 assert!(matches!(
301 SchemaAssertion::try_new_type(&json!(["integer", "string"])),
302 Ok(SchemaAssertion::Type(v)) if v == &[InstanceType::Integer, InstanceType::String]
303 ));
304 assert!(matches!(SchemaAssertion::try_new_type(&json!([[], "string"])), Err(_)));
305 }
306
307 #[test]
308 fn test_new_enum() {
309 assert!(matches!(
310 SchemaAssertion::try_new_enum(&json!([1, 2.1, true, "3", [], null, {"foo": 42}])),
311 Ok(SchemaAssertion::Enum(v)) if v == &[json!(1), json!(2.1), json!(true),json!("3"), json!([]), json!(null), json!({"foo":42}),]
312 ));
313
314 assert!(matches!(SchemaAssertion::try_new_enum(&json!(42)), Err(_)));
315 assert!(matches!(SchemaAssertion::try_new_enum(&json!([])), Err(_)));
316 }
317
318 #[test]
319 fn test_new_const() {
320 let value = &json!({"foo": 42, "bar": [null, 2]});
321 assert!(
322 matches!(&SchemaAssertion::new_const(value), SchemaAssertion::Const(&ref v) if v == value)
323 );
324 }
325
326 #[test]
327 fn test_new_pattern() {
328 let re = Regex::new("(foo|bar|baz)").unwrap();
329 assert!(matches!(
330 &SchemaAssertion::try_new_pattern(&json!(re.as_str())),
331 Ok(SchemaAssertion::Pattern(r)) if r.as_str() == re.as_str()));
332
333 assert!(matches!(SchemaAssertion::try_new_pattern(&json!("(foo|bar")), Err(_)));
334 assert!(matches!(SchemaAssertion::try_new_pattern(&json!([re.as_str()])), Err(_)));
335 }
336
337 #[test]
338 fn test_new_min() {
339 let num = &Number::from_f64(42.1).unwrap();
340
341 assert!(matches!(
342 &SchemaAssertion::try_new_min(&json!(num)),
343 Ok(SchemaAssertion::Minimum(&ref n)) if n == num));
344
345 assert!(matches!(SchemaAssertion::try_new_min(&json!("foo")), Err(_)));
346 }
347
348 #[test]
349 fn test_new_xmin() {
350 let num = &Number::from_f64(42.1).unwrap();
351
352 assert!(matches!(
353 &SchemaAssertion::try_new_xmin(&json!(num)),
354 Ok(SchemaAssertion::ExclusiveMinimum(&ref n)) if n == num
355 ));
356
357 assert!(matches!(SchemaAssertion::try_new_xmin(&json!("foo")), Err(_)));
358 }
359
360 #[test]
361 fn test_new_max() {
362 let num = &Number::from_f64(42.1).unwrap();
363
364 assert!(matches!(
365 &SchemaAssertion::try_new_max(&json!(num)),
366 Ok(SchemaAssertion::Maximum(&ref n)) if n == num
367 ));
368
369 assert!(matches!(SchemaAssertion::try_new_max(&json!("foo")), Err(_)));
370 }
371
372 #[test]
373 fn test_new_xmax() {
374 let num = &Number::from_f64(42.1).unwrap();
375
376 assert!(matches!(
377 &SchemaAssertion::try_new_xmax(&json!(num)),
378 Ok(SchemaAssertion::ExclusiveMaximum(&ref n)) if n == num
379 ));
380
381 assert!(matches!(SchemaAssertion::try_new_xmax(&json!("foo")), Err(_)));
382 }
383
384 #[test]
385 fn test_new_min_items() {
386 let num = &Number::from_f64(42.1).unwrap();
387
388 assert!(matches!(
389 &SchemaAssertion::try_new_min_items(&json!(num)),
390 Ok(SchemaAssertion::MinItems(&ref n)) if n == num
391 ));
392
393 assert!(matches!(SchemaAssertion::try_new_min_items(&json!("foo")), Err(_)));
394 }
395
396 #[test]
397 fn test_new_max_items() {
398 let num = &Number::from_f64(42.1).unwrap();
399
400 assert!(matches!(
401 &SchemaAssertion::try_new_max_items(&json!(num)),
402 Ok(SchemaAssertion::MaxItems(&ref n)) if n == num
403 ));
404
405 assert!(matches!(SchemaAssertion::try_new_max_items(&json!("foo")), Err(_)));
406 }
407
408 #[test]
409 fn test_new_unique_items() {
410 assert!(matches!(
411 &SchemaAssertion::try_new_unique_items(&json!(true)),
412 Ok(SchemaAssertion::UniqueItems(true))
413 ));
414
415 assert!(matches!(SchemaAssertion::try_new_unique_items(&json!("foo")), Err(_)));
416 }
417
418 #[test]
419 fn test_new_required() {
420 assert!(matches!(
421 SchemaAssertion::try_new_required(&json!(["foo", "bar"])),
422 Ok(SchemaAssertion::Required(v)) if v == HashSet::from(["foo", "bar"])
423 ));
424
425 assert!(matches!(SchemaAssertion::try_new_required(&json!(42)), Err(_)));
426 assert!(matches!(SchemaAssertion::try_new_required(&json!(["foo", 42])), Err(_)));
427 }
428
429 #[test]
434 fn test_validate_type() {
435 assert!(SchemaAssertion::Type(vec![InstanceType::String])
436 .validate(&json!("42"), &Bool(true))
437 .is_ok());
438 assert!(SchemaAssertion::Type(vec![InstanceType::String, InstanceType::Number])
439 .validate(&json!(42), &Bool(true))
440 .is_ok());
441 assert!(SchemaAssertion::Type(vec![InstanceType::Integer])
442 .validate(&json!(42.0), &Bool(true))
443 .is_ok());
444
445 assert!(SchemaAssertion::Type(vec![InstanceType::String, InstanceType::Null])
446 .validate(&json!(42), &Bool(true))
447 .is_err());
448 }
449
450 #[test]
451 fn test_validate_enum() {
452 let e = vec![json!(42), json!(null), json!("foo")];
453 assert!(SchemaAssertion::Enum(&e).validate(&json!(42), &Bool(true)).is_ok());
454 assert!(SchemaAssertion::Enum(&e).validate(&json!(null), &Bool(true)).is_ok());
455 assert!(SchemaAssertion::Enum(&e).validate(&json!("foo"), &Bool(true)).is_ok());
456
457 assert!(SchemaAssertion::Enum(&e)
458 .validate(&json!([42, null, "foo"]), &Bool(true))
459 .is_err());
460 }
461
462 #[test]
463 fn test_validate_const() {
464 assert!(SchemaAssertion::Const(&json!(42.123))
465 .validate(&json!(42.123), &Bool(true))
466 .is_ok());
467 assert!(SchemaAssertion::Const(&json!({"foo": 42}))
468 .validate(&json!({"foo":42}), &Bool(true))
469 .is_ok());
470 assert!(SchemaAssertion::Const(&json!(null)).validate(&json!(null), &Bool(true)).is_ok());
471
472 assert!(SchemaAssertion::Const(&json!(42)).validate(&json!("42"), &Bool(true)).is_err());
473 assert!(SchemaAssertion::Const(&json!(null)).validate(&json!([]), &Bool(true)).is_err());
474 }
475
476 #[test]
477 fn test_validate_pattern() {
478 assert!(SchemaAssertion::Pattern(Regex::new("(foo|bar)").unwrap())
479 .validate(&json!("foo"), &Bool(true))
480 .is_ok());
481 assert!(SchemaAssertion::Pattern(Regex::new("(foo|bar)").unwrap())
482 .validate(&json!(42), &Bool(true))
483 .is_ok());
484 assert!(SchemaAssertion::Pattern(Regex::new("^(foo|bar)$").unwrap())
485 .validate(&json!(["foot"]), &Bool(true))
486 .is_ok());
487
488 assert!(SchemaAssertion::Pattern(Regex::new("^(foo|bar)$").unwrap())
489 .validate(&json!("foot"), &Bool(true))
490 .is_err());
491 }
492
493 #[test]
494 fn test_validate_min() {
495 assert!(SchemaAssertion::Minimum(&Number::from_i128(10).unwrap())
496 .validate(&json!(10), &Bool(true))
497 .is_ok());
498 assert!(SchemaAssertion::Minimum(&Number::from_i128(10).unwrap())
499 .validate(&json!(11), &Bool(true))
500 .is_ok());
501 assert!(SchemaAssertion::Minimum(&Number::from_i128(10).unwrap())
502 .validate(&json!("0"), &Bool(true))
503 .is_ok());
504 assert!(SchemaAssertion::Minimum(&Number::from_i128(10).unwrap())
505 .validate(&json!(null), &Bool(true))
506 .is_ok());
507 assert!(SchemaAssertion::Minimum(&Number::from_f64(3.14).unwrap())
508 .validate(&json!(3.14), &Bool(true))
509 .is_ok());
510
511 assert!(SchemaAssertion::Minimum(&Number::from_i128(10).unwrap())
512 .validate(&json!(9), &Bool(true))
513 .is_err());
514 }
515
516 #[test]
517 fn test_validate_xmin() {
518 assert!(SchemaAssertion::ExclusiveMinimum(&Number::from_i128(10).unwrap())
519 .validate(&json!(11), &Bool(true))
520 .is_ok());
521 assert!(SchemaAssertion::ExclusiveMinimum(&Number::from_i128(10).unwrap())
522 .validate(&json!("0"), &Bool(true))
523 .is_ok());
524 assert!(SchemaAssertion::ExclusiveMinimum(&Number::from_i128(10).unwrap())
525 .validate(&json!(null), &Bool(true))
526 .is_ok());
527
528 assert!(SchemaAssertion::ExclusiveMinimum(&Number::from_i128(10).unwrap())
529 .validate(&json!(10), &Bool(true))
530 .is_err());
531 assert!(SchemaAssertion::ExclusiveMinimum(&Number::from_f64(3.14).unwrap())
532 .validate(&json!(3.14), &Bool(true))
533 .is_err());
534 assert!(SchemaAssertion::ExclusiveMinimum(&Number::from_i128(10).unwrap())
535 .validate(&json!(9), &Bool(true))
536 .is_err());
537 }
538
539 #[test]
540 fn test_validate_max() {
541 assert!(SchemaAssertion::Maximum(&Number::from_i128(10).unwrap())
542 .validate(&json!(10), &Bool(true))
543 .is_ok());
544 assert!(SchemaAssertion::Maximum(&Number::from_i128(10).unwrap())
545 .validate(&json!(9), &Bool(true))
546 .is_ok());
547 assert!(SchemaAssertion::Maximum(&Number::from_i128(10).unwrap())
548 .validate(&json!(-11), &Bool(true))
549 .is_ok());
550 assert!(SchemaAssertion::Maximum(&Number::from_i128(10).unwrap())
551 .validate(&json!("0"), &Bool(true))
552 .is_ok());
553 assert!(SchemaAssertion::Maximum(&Number::from_i128(10).unwrap())
554 .validate(&json!(null), &Bool(true))
555 .is_ok());
556 assert!(SchemaAssertion::Maximum(&Number::from_f64(3.14).unwrap())
557 .validate(&json!(3.14), &Bool(true))
558 .is_ok());
559
560 assert!(SchemaAssertion::Maximum(&Number::from_i128(10).unwrap())
561 .validate(&json!(11), &Bool(true))
562 .is_err());
563 }
564
565 #[test]
566 fn test_validate_xmax() {
567 assert!(SchemaAssertion::ExclusiveMaximum(&Number::from_i128(10).unwrap())
568 .validate(&json!(9), &Bool(true))
569 .is_ok());
570 assert!(SchemaAssertion::ExclusiveMaximum(&Number::from_i128(10).unwrap())
571 .validate(&json!("0"), &Bool(true))
572 .is_ok());
573 assert!(SchemaAssertion::ExclusiveMaximum(&Number::from_i128(10).unwrap())
574 .validate(&json!(null), &Bool(true))
575 .is_ok());
576
577 assert!(SchemaAssertion::ExclusiveMaximum(&Number::from_i128(10).unwrap())
578 .validate(&json!(10), &Bool(true))
579 .is_err());
580 assert!(SchemaAssertion::ExclusiveMaximum(&Number::from_f64(3.14).unwrap())
581 .validate(&json!(3.14), &Bool(true))
582 .is_err());
583 assert!(SchemaAssertion::ExclusiveMaximum(&Number::from_i128(10).unwrap())
584 .validate(&json!(11), &Bool(true))
585 .is_err());
586 }
587
588 #[test]
589 fn test_validate_min_items() {
590 let arr = &json!([1, 2, "3", null, []]);
591 assert!(SchemaAssertion::MinItems(&Number::from_i128(4).unwrap())
592 .validate(arr, &Bool(true))
593 .is_ok());
594 assert!(SchemaAssertion::MinItems(&Number::from_i128(5).unwrap())
595 .validate(arr, &Bool(true))
596 .is_ok());
597 assert!(SchemaAssertion::MinItems(&Number::from_i128(5).unwrap())
598 .validate(&json!(42), &Bool(true))
599 .is_ok());
600
601 assert!(SchemaAssertion::MinItems(&Number::from_i128(6).unwrap())
602 .validate(arr, &Bool(true))
603 .is_err());
604 }
605
606 #[test]
607 fn test_validate_max_items() {
608 let arr = &json!([1, 2, "3", null, []]);
609 assert!(SchemaAssertion::MaxItems(&Number::from_i128(6).unwrap())
610 .validate(arr, &Bool(true))
611 .is_ok());
612 assert!(SchemaAssertion::MaxItems(&Number::from_i128(5).unwrap())
613 .validate(arr, &Bool(true))
614 .is_ok());
615 assert!(SchemaAssertion::MaxItems(&Number::from_i128(5).unwrap())
616 .validate(&json!(42), &Bool(true))
617 .is_ok());
618
619 assert!(SchemaAssertion::MaxItems(&Number::from_i128(4).unwrap())
620 .validate(arr, &Bool(true))
621 .is_err());
622 }
623
624 #[test]
625 fn test_validate_unique_items() {
626 assert!(SchemaAssertion::UniqueItems(true)
627 .validate(&json!([1, 2, null, false]), &Bool(true))
628 .is_ok());
629 assert!(SchemaAssertion::UniqueItems(true).validate(&json!([]), &Bool(true)).is_ok());
630 assert!(SchemaAssertion::UniqueItems(true).validate(&json!(42), &Bool(true)).is_ok());
631 assert!(SchemaAssertion::UniqueItems(false)
632 .validate(&json!([1, 2, null, false]), &Bool(true))
633 .is_ok());
634 assert!(SchemaAssertion::UniqueItems(false).validate(&json!([2, 2]), &Bool(true)).is_ok());
635
636 assert!(SchemaAssertion::UniqueItems(true).validate(&json!([2, 2]), &Bool(true)).is_err());
637 }
638
639 #[test]
640 fn test_validate_required() {
641 let a = SchemaAssertion::Required(HashSet::from(["foo", "bar"]));
642 assert!(a.validate(&json!({"foo": 42, "bar": null}), &Bool(true)).is_ok());
643 assert!(a.validate(&json!({"foo": 42, "bar": null, "baz": false}), &Bool(true)).is_ok());
644 assert!(a.validate(&json!(42), &Bool(true)).is_ok());
645
646 assert!(a.validate(&json!({"foo": 42}), &Bool(true)).is_err());
647 }
648}