1use crate::context::{Context, PathPart, State, Update, UpdateErr};
4use crate::error::*;
5use crate::node::{Kind, ListMode, Node, Validator};
6use crate::stringify::stringify_node;
7use crate::value::{is_integer, Map, Value};
8use std::collections::HashMap;
9use std::sync::Arc;
10
11pub(crate) enum Cur<'a, T = Value> {
16 Mut(&'a mut T),
17 Ref(&'a T),
18}
19
20impl<'a, T> Cur<'a, T> {
21 fn get(&self) -> &T {
22 match self {
23 Cur::Mut(v) => v,
24 Cur::Ref(v) => v,
25 }
26 }
27
28 fn set(&mut self, nv: T) {
29 if let Cur::Mut(v) = self {
30 **v = nv;
31 }
32 }
33
34 fn reborrow(&mut self) -> Cur<'_, T> {
35 match self {
36 Cur::Mut(v) => Cur::Mut(v),
37 Cur::Ref(v) => Cur::Ref(v),
38 }
39 }
40}
41
42pub(crate) struct Walk<'c> {
44 pub ctx: &'c mut Context,
45 pub defs: &'c HashMap<String, Arc<Node>>,
47 pub is_match: bool,
48 pub path: Vec<PathPart>,
50 pub paths: bool,
53}
54
55impl<'c> Walk<'c> {
56 #[inline]
57 fn push(&mut self, part: PathPart) {
58 if self.paths {
59 self.path.push(part);
60 }
61 }
62
63 #[inline]
64 fn pop(&mut self) {
65 if self.paths {
66 self.path.pop();
67 }
68 }
69}
70
71fn index_key(i: usize, buf: &mut [u8; 20]) -> &str {
74 let mut n = i;
75 let mut pos = buf.len();
76 loop {
77 pos -= 1;
78 buf[pos] = b'0' + (n % 10) as u8;
79 n /= 10;
80 if n == 0 {
81 break;
82 }
83 }
84 unsafe { std::str::from_utf8_unchecked(&buf[pos..]) }
86}
87
88pub(crate) fn required_mark_for(k: Kind) -> i64 {
89 match k {
90 Kind::Object => MARK_OBJECT_REQUIRED,
91 Kind::Array => MARK_ARRAY_REQUIRED,
92 _ => MARK_SCALAR_REQUIRED,
93 }
94}
95
96pub(crate) fn type_mark_for(k: Kind) -> i64 {
97 match k {
98 Kind::Object => MARK_OBJECT_TYPE,
99 Kind::Array => MARK_ARRAY_TYPE,
100 Kind::Check => MARK_CHECK_TYPE,
101 _ => MARK_SCALAR_TYPE,
102 }
103}
104
105pub(crate) fn validate_node(
109 n: &Node,
110 cur: Cur<'_>,
111 key: &str,
112 parent_is_array: bool,
113 w: &mut Walk<'_>,
114 verr: &mut ValidationError,
115) -> bool {
116 validate_node_with(
117 n,
118 &n.befores,
119 &n.afters,
120 n.silent,
121 cur,
122 key,
123 parent_is_array,
124 w,
125 verr,
126 )
127}
128
129#[allow(clippy::too_many_arguments)]
133pub(crate) fn validate_node_with(
134 n: &Node,
135 befores: &[Validator],
136 afters: &[Validator],
137 silent: bool,
138 mut cur: Cur<'_>,
139 key: &str,
140 parent_is_array: bool,
141 w: &mut Walk<'_>,
142 verr: &mut ValidationError,
143) -> bool {
144 let absent = cur.get().is_undefined();
145 let mut over: Option<Value> = None;
148 let mut node_over: Option<Arc<Node>> = None;
149 let mut done = false;
150
151 for b in befores {
152 let cur_node: &Node = node_over.as_deref().unwrap_or(n);
153 let mut update = Update::default();
154 let ok = {
155 let value: &Value = over.as_ref().unwrap_or_else(|| cur.get());
156 let mut state = State {
157 path_arr: &w.path,
158 key,
159 value,
160 node: cur_node,
161 parent_is_array,
162 is_match: w.is_match,
163 ctx: w.ctx,
164 absent,
165 check_name: &b.name,
166 defs: w.defs,
167 };
168 (b.func)(&mut state, &mut update)
169 };
170 if let Some(v) = update.val.take() {
171 match &mut cur {
172 Cur::Mut(_) => cur.set(v),
173 Cur::Ref(_) => over = Some(v),
174 }
175 }
176 if let Some(nn) = update.node.take() {
177 node_over = Some(nn);
178 }
179 let cur_node: &Node = node_over.as_deref().unwrap_or(n);
180 let cur_silent = if node_over.is_some() {
181 cur_node.silent
182 } else {
183 silent
184 };
185 let value_now: &Value = over.as_ref().unwrap_or_else(|| cur.get());
186 if !ok && absent_skips(cur_node, value_now, absent, &update) {
187 continue;
188 }
189 if !ok {
190 let at = at_of(w, key, cur_node, value_now, parent_is_array, &b.name);
191 emit_update_errors(&at, cur_node, cur_silent, &update, verr);
192 }
193 if !ok || update.done {
194 done = true;
195 }
196 }
197
198 let n: &Node = node_over.as_deref().unwrap_or(n);
199 let silent = if node_over.is_some() {
200 n.silent
201 } else {
202 silent
203 };
204 let mut kept = true;
205 if !done {
206 let inner = match over.as_mut() {
207 Some(v) => Cur::Mut(v),
208 None => cur.reborrow(),
209 };
210 kept = validate_structure(n, silent, inner, key, parent_is_array, absent, w, verr);
211 }
212
213 for a in afters {
215 let mut update = Update::default();
216 let ok = {
217 let value: &Value = over.as_ref().unwrap_or_else(|| cur.get());
218 let mut state = State {
219 path_arr: &w.path,
220 key,
221 value,
222 node: n,
223 parent_is_array,
224 is_match: w.is_match,
225 ctx: w.ctx,
226 absent,
227 check_name: &a.name,
228 defs: w.defs,
229 };
230 (a.func)(&mut state, &mut update)
231 };
232 if let Some(v) = update.val.take() {
233 kept = true;
234 match &mut cur {
235 Cur::Mut(_) => cur.set(v),
236 Cur::Ref(_) => over = Some(v),
237 }
238 }
239 let value_now: &Value = over.as_ref().unwrap_or_else(|| cur.get());
240 if !ok && absent_skips(n, value_now, absent, &update) {
241 continue;
242 }
243 if !ok {
244 let at = at_of(w, key, n, value_now, parent_is_array, &a.name);
245 emit_update_errors(&at, n, silent, &update, verr);
246 }
247 }
248
249 kept
250}
251
252fn absent_skips(n: &Node, value: &Value, absent: bool, update: &Update) -> bool {
255 absent && value.is_undefined() && (n.skippable || !n.required) && !update.done
256}
257
258pub(crate) fn at_of<'a>(
262 w: &'a Walk<'_>,
263 key: &'a str,
264 n: &Node,
265 value: &'a Value,
266 parent_is_array: bool,
267 check: &'a str,
268) -> At<'a> {
269 At {
270 path: &w.path,
271 key,
272 kind: n.kind,
273 value,
274 parent_arr: parent_is_array,
275 absent: value.is_undefined(),
276 check,
277 regexp_src: if w.ctx.terse {
279 None
280 } else {
281 n.regexp.as_ref().map(|_| format!("/{}/", n.regexp_src))
282 },
283 terse: w.ctx.terse,
284 }
285}
286
287fn emit_update_errors(
288 at: &At<'_>,
289 n: &Node,
290 silent: bool,
291 update: &Update,
292 verr: &mut ValidationError,
293) {
294 if silent {
295 return;
296 }
297 let why = update.why.as_deref().unwrap_or("");
298 match &update.err {
299 None => {
300 let why = if why.is_empty() { WHY_CHECK } else { why };
301 let mark = if update.mark == 0 {
302 MARK_CUSTOM_CHECK_ERR
303 } else {
304 update.mark
305 };
306 let mut err = make_err(at, why, mark, "");
307 if let Some(f) = &n.fault_msg {
308 if !err.terse {
309 err.text = expand_err_text(f, &err.path, at.value, at.absent);
310 }
311 }
312 verr.add(err);
313 }
314 Some(UpdateErr::Text(t)) => {
315 let why = if why.is_empty() { WHY_CHECK } else { why };
316 let mark = if update.mark == 0 {
317 MARK_CUSTOM_CHECK_TEXT
318 } else {
319 update.mark
320 };
321 verr.add(make_err(at, why, mark, t));
322 }
323 Some(UpdateErr::Field(e)) => {
324 let mut e = (**e).clone();
325 fill_field(&mut e, at);
326 verr.add(e);
327 }
328 Some(UpdateErr::Fields(es)) => {
329 for e in es {
330 let mut e = e.clone();
331 fill_field(&mut e, at);
332 verr.add(e);
333 }
334 }
335 }
336}
337
338fn fill_field(e: &mut FieldError, at: &At<'_>) {
339 if e.path.is_empty() {
340 e.path = crate::context::join_path(at.path);
341 }
342 if e.mark == 0 {
343 e.mark = MARK_CUSTOM_CHECK_TEXT;
344 }
345}
346
347fn add_structural(
348 at: &At<'_>,
349 n: &Node,
350 silent: bool,
351 why: &str,
352 mark: i64,
353 verr: &mut ValidationError,
354) {
355 let mut err = make_err(at, why, mark, "");
356 if let Some(f) = &n.fault_msg {
357 if !err.terse {
358 err.text = expand_err_text(f, &err.path, at.value, at.absent);
359 }
360 }
361 if !silent {
362 verr.add(err);
363 }
364}
365
366pub(crate) fn emit_type_err(
367 w: &Walk<'_>,
368 key: &str,
369 n: &Node,
370 silent: bool,
371 value: &Value,
372 parent_is_array: bool,
373 verr: &mut ValidationError,
374) {
375 let at = at_of(w, key, n, value, parent_is_array, "");
376 add_structural(&at, n, silent, WHY_TYPE, type_mark_for(n.kind), verr);
377}
378
379#[allow(clippy::too_many_arguments)]
382fn validate_structure(
383 n: &Node,
384 silent: bool,
385 mut cur: Cur<'_>,
386 key: &str,
387 parent_is_array: bool,
388 absent: bool,
389 w: &mut Walk<'_>,
390 verr: &mut ValidationError,
391) -> bool {
392 if n.kind == Kind::List && n.list_mode != ListMode::None && (n.required || !absent) {
393 let before = verr.count();
394 let kept = evaluate_list(
395 n,
396 silent,
397 cur.reborrow(),
398 key,
399 parent_is_array,
400 absent,
401 w,
402 verr,
403 );
404 if absent && n.required && verr.count() == before && cur.get().is_undefined() {
408 let at = at_of(w, key, n, cur.get(), parent_is_array, "");
409 add_structural(
410 &at,
411 n,
412 silent,
413 WHY_REQUIRED,
414 required_mark_for(n.kind),
415 verr,
416 );
417 return false;
418 }
419 return kept;
420 }
421
422 if cur.get().is_null() && n.nullable {
424 return true;
425 }
426
427 if n.kind == Kind::Never {
429 let at = at_of(w, key, n, cur.get(), parent_is_array, "");
430 add_structural(&at, n, silent, WHY_NEVER, MARK_NEVER, verr);
431 return !absent;
432 }
433
434 if n.kind == Kind::Regexp && absent && !n.required {
436 return false;
437 }
438
439 if absent && n.kind != Kind::Regexp {
442 if n.required {
443 let at = at_of(w, key, n, cur.get(), parent_is_array, "");
444 add_structural(
445 &at,
446 n,
447 silent,
448 WHY_REQUIRED,
449 required_mark_for(n.kind),
450 verr,
451 );
452 return false;
453 }
454 if n.skippable {
455 return false;
456 }
457 if !n.has_default && (n.kind == Kind::Object || n.kind == Kind::Array) {
458 cur.set(if n.kind == Kind::Array {
459 Value::Arr(Vec::new())
460 } else {
461 Value::Obj(Default::default())
462 });
463 if matches!(cur, Cur::Ref(_)) {
464 let mut scratch = if n.kind == Kind::Array {
467 Value::Arr(Vec::new())
468 } else {
469 Value::Obj(Default::default())
470 };
471 return validate_structure(
472 n,
473 silent,
474 Cur::Mut(&mut scratch),
475 key,
476 parent_is_array,
477 false,
478 w,
479 verr,
480 );
481 }
482 } else {
483 if n.default.is_undefined() {
484 return false;
486 }
487 cur.set(n.default.clone());
488 return true;
489 }
490 }
491
492 let value = cur.get();
493 match n.kind {
494 Kind::Any | Kind::Check => {}
495 Kind::Regexp => {
496 let Some(s) = value.as_str() else {
497 let at = at_of(w, key, n, value, parent_is_array, "");
498 let mut err = make_err(&at, WHY_TYPE, MARK_SCALAR_TYPE, "");
499 err.kind = Kind::String;
500 if !err.terse {
501 err.text = default_err_text(&err);
502 if let Some(f) = &n.fault_msg {
503 err.text = expand_err_text(f, &err.path, value, absent);
504 }
505 }
506 if !silent {
507 verr.add(err);
508 }
509 return true;
510 };
511 let matched = n.regexp.as_ref().is_some_and(|re| re.is_match(s));
512 if !matched {
513 let at = at_of(w, key, n, value, parent_is_array, "");
514 add_structural(&at, n, silent, WHY_REGEXP, MARK_REGEXP, verr);
515 }
516 }
517 Kind::String => match value {
518 Value::Str(s) => {
519 if s.is_empty() && !n.empty {
520 let at = at_of(w, key, n, value, parent_is_array, "");
521 add_structural(&at, n, silent, WHY_REQUIRED, MARK_UNDEF_REQUIRED, verr);
522 }
523 }
524 _ => emit_type_err(w, key, n, silent, value, parent_is_array, verr),
525 },
526 Kind::Number => match value {
527 Value::Num(x) if !x.is_nan() => {}
528 _ => emit_type_err(w, key, n, silent, value, parent_is_array, verr),
529 },
530 Kind::Integer => match value {
531 Value::Num(x) if is_integer(*x) => {}
532 _ => emit_type_err(w, key, n, silent, value, parent_is_array, verr),
533 },
534 Kind::Boolean => {
535 if !matches!(value, Value::Bool(_)) {
536 emit_type_err(w, key, n, silent, value, parent_is_array, verr);
537 }
538 }
539 Kind::Date => {
540 if !matches!(value, Value::Date(_)) {
541 emit_type_err(w, key, n, silent, value, parent_is_array, verr);
542 }
543 }
544 Kind::BigInt => {
545 if !matches!(value, Value::BigInt(_)) {
546 emit_type_err(w, key, n, silent, value, parent_is_array, verr);
547 }
548 }
549 Kind::NaN => match value {
550 Value::Num(x) if x.is_nan() => {}
551 _ => emit_type_err(w, key, n, silent, value, parent_is_array, verr),
552 },
553 Kind::Null => {
554 if !value.is_null() {
555 emit_type_err(w, key, n, silent, value, parent_is_array, verr);
556 }
557 }
558 Kind::Function => {
559 if !matches!(value, Value::Func(_)) {
560 emit_type_err(w, key, n, silent, value, parent_is_array, verr);
561 }
562 }
563 Kind::Array => return validate_array(n, silent, cur, key, parent_is_array, w, verr),
564 Kind::Object => return validate_object(n, silent, cur, key, parent_is_array, w, verr),
565 Kind::Never | Kind::List => {}
566 }
567 true
568}
569
570#[inline]
574fn plain_scalar_passes(n: &Node, v: &Value) -> bool {
575 match (n.kind, v) {
576 (Kind::String, Value::Str(s)) => n.empty || !s.is_empty(),
577 (Kind::Number, Value::Num(x)) => !x.is_nan(),
578 (Kind::Integer, Value::Num(x)) => is_integer(*x),
579 (Kind::Boolean, Value::Bool(_)) => true,
580 _ => false,
581 }
582}
583
584fn child_key(n: &Node, idx: usize, k: &str) -> Arc<str> {
587 match n.obj_keys.get(idx) {
588 Some(key) => Arc::clone(key),
589 None => Arc::from(k),
590 }
591}
592
593fn aligned(n: &Node, map: &Map) -> bool {
598 map.len() <= n.obj_keys.len()
599 && map
600 .keys()
601 .zip(&n.obj_keys)
602 .all(|(k, dk)| k.as_str() == &**dk)
603}
604
605fn guess<'m>(map: &'m Map, idx: usize, k: &str) -> Option<&'m Value> {
609 match map.get_index(idx) {
610 Some((mk, v)) if mk == k => Some(v),
611 _ => map.get(k),
612 }
613}
614
615fn guess_index(map: &Map, idx: usize, k: &str) -> Option<usize> {
617 match map.get_index(idx) {
618 Some((mk, _)) if mk == k => Some(idx),
619 _ => map.get_index_of(k),
620 }
621}
622
623fn unknown_keys(n: &Node, map: &Map) -> Vec<String> {
625 map.iter()
626 .filter(|(k, v)| !v.is_undefined() && !n.consumed.contains(*k))
627 .map(|(k, _)| k.clone())
628 .collect()
629}
630
631fn validate_object(
632 n: &Node,
633 silent: bool,
634 cur: Cur<'_>,
635 key: &str,
636 parent_is_array: bool,
637 w: &mut Walk<'_>,
638 verr: &mut ValidationError,
639) -> bool {
640 let aligned = cur.get().as_obj().is_some_and(|map| aligned(n, map));
643 if let Some(map) = cur.get().as_obj() {
644 if !n.is_open() && !aligned {
645 let unknown = unknown_keys(n, map);
646 if !unknown.is_empty() {
647 let value = cur.get();
648 let joined = unknown.join(", ");
649 let at = at_of(w, &joined, n, value, parent_is_array, "");
650 let mut err = make_err(&at, WHY_CLOSED, MARK_OBJECT_CLOSED, "");
651 err.plural = unknown.len() > 1;
652 if !err.terse {
653 err.text = default_err_text(&err);
654 if let Some(f) = &n.fault_msg {
655 err.text = expand_err_text(f, &err.path, value, false);
656 }
657 }
658 if !silent {
659 verr.add(err);
660 }
661 }
662 }
663 }
664
665 let mut oc: Cur<'_, Map> = match cur {
668 Cur::Mut(Value::Obj(m)) => Cur::Mut(m),
669 Cur::Ref(Value::Obj(m)) => Cur::Ref(m),
670 other => {
671 emit_type_err(w, key, n, silent, other.get(), parent_is_array, verr);
672 return true;
673 }
674 };
675
676 for (idx, (k, cn)) in n.obj_children.iter().enumerate() {
677 if cn.plain {
681 let found = match &oc {
682 Cur::Ref(map) if aligned => map.get_index(idx).map(|(_, v)| v),
683 Cur::Ref(map) => guess(map, idx, k),
684 Cur::Mut(map) => guess(map, idx, k),
685 };
686 if let Some(v) = found {
687 if plain_scalar_passes(cn, v) {
688 continue;
689 }
690 if let Cur::Ref(_) = &oc {
691 let container = matches!(
692 (cn.kind, v),
693 (Kind::Object, Value::Obj(_)) | (Kind::Array, Value::Arr(_))
694 );
695 if container {
696 if w.paths {
697 w.push(PathPart::Key(child_key(n, idx, k)));
698 }
699 if cn.kind == Kind::Object {
700 validate_object(cn, cn.silent, Cur::Ref(v), k, false, w, verr);
701 } else {
702 validate_array(cn, cn.silent, Cur::Ref(v), k, false, w, verr);
703 }
704 w.pop();
705 continue;
706 }
707 }
708 }
709 }
710
711 let mut claimed: Option<&Value> = None;
714 if cn.rename_to.is_some() && !cn.rename_claim.is_empty() {
715 let present = oc.get().get(k).map(|v| !v.is_undefined()).unwrap_or(false);
716 if !present {
717 let src = cn
718 .rename_claim
719 .iter()
720 .find(|src| oc.get().contains_key(*src))
721 .cloned();
722 if let Some(src) = src {
723 match &mut oc {
724 Cur::Mut(map) => {
725 let v = if cn.rename_keep {
726 map.get(&src).cloned().unwrap()
727 } else {
728 map.shift_remove(&src).unwrap()
729 };
730 map.insert(k.clone(), v);
731 }
732 Cur::Ref(map) => claimed = map.get(&src),
733 }
734 }
735 }
736 }
737
738 if w.paths {
740 w.push(PathPart::Key(child_key(n, idx, k)));
741 }
742 let mut scratch: Value;
745 let (child, was_absent) = match &mut oc {
746 Cur::Mut(map) => match guess_index(map, idx, k) {
747 Some(pos) => (Cur::Mut(&mut map[pos]), false),
749 None => (
750 Cur::Mut(map.entry(k.clone()).or_insert(Value::Undefined)),
751 true,
752 ),
753 },
754 Cur::Ref(map) => {
755 let found = if aligned {
758 map.get_index(idx).map(|(_, v)| v)
759 } else {
760 claimed.or_else(|| guess(map, idx, k))
761 };
762 match found {
763 Some(child) if !child.is_undefined() => (Cur::Ref(child), false),
764 _ => {
765 scratch = Value::Undefined;
766 (Cur::Mut(&mut scratch), true)
767 }
768 }
769 }
770 };
771 let keep = if cn.is_ignore() {
772 validate_ignored(cn, child, k, false, w, verr)
773 } else {
774 validate_node(cn, child, k, false, w, verr)
775 };
776 w.pop();
777 if let Cur::Mut(m) = &mut oc {
778 if !keep {
779 let empty = m.get(k).map(|x| x.is_undefined()).unwrap_or(false);
780 if was_absent || empty || cn.is_ignore() {
781 m.shift_remove(k);
782 }
783 } else if let Some(to) = &cn.rename_to {
784 if to != k {
786 let v = if cn.rename_keep {
787 m.get(k).cloned()
788 } else {
789 m.shift_remove(k)
790 };
791 if let Some(v) = v {
792 m.insert(to.clone(), v);
793 }
794 }
795 }
796 }
797 }
798
799 let rest_keys = !(aligned && matches!(oc, Cur::Ref(_)));
801 if let Some(rest) = n.obj_rest.as_deref().filter(|_| rest_keys) {
802 let extra: Vec<String> = oc
803 .get()
804 .iter()
805 .filter(|(k, v)| !v.is_undefined() && !n.obj_children.contains_key(*k))
806 .map(|(k, _)| k.clone())
807 .collect();
808 for k in extra {
809 w.push(PathPart::Key(Arc::from(k.as_str())));
810 let child = match &mut oc {
811 Cur::Mut(map) => Cur::Mut(map.get_mut(&k).unwrap()),
812 Cur::Ref(map) => Cur::Ref(map.get(&k).unwrap()),
813 };
814 let keep = if rest.is_ignore() {
815 validate_ignored(rest, child, &k, false, w, verr)
816 } else {
817 validate_node(rest, child, &k, false, w, verr)
818 };
819 w.pop();
820 if !keep {
821 if let Cur::Mut(m) = &mut oc {
822 m.shift_remove(&k);
823 }
824 }
825 }
826 }
827 true
828}
829
830fn validate_array(
831 n: &Node,
832 silent: bool,
833 cur: Cur<'_>,
834 key: &str,
835 parent_is_array: bool,
836 w: &mut Walk<'_>,
837 verr: &mut ValidationError,
838) -> bool {
839 let fixed = n.arr_children.len();
840 let has_child = n.arr_child.is_some();
841
842 if let Some(arr) = cur.get().as_arr() {
845 if fixed > 0 && arr.len() > fixed && !has_child && n.arr_rest.is_none() {
846 let value = cur.get();
847 let k = fixed.to_string();
848 let at = at_of(w, &k, n, value, parent_is_array, "");
849 let mut err = make_err(&at, WHY_CLOSED, MARK_ARRAY_CLOSED, "");
850 if !err.terse {
851 if let Some(f) = &n.fault_msg {
852 err.text = expand_err_text(f, &err.path, value, false);
853 }
854 }
855 if !silent {
856 verr.add(err);
857 }
858 return true;
859 }
860 }
861
862 let mut ac: Cur<'_, Vec<Value>> = match cur {
863 Cur::Mut(Value::Arr(a)) => Cur::Mut(a),
864 Cur::Ref(Value::Arr(a)) => Cur::Ref(a),
865 other => {
866 emit_type_err(w, key, n, silent, other.get(), parent_is_array, verr);
867 return true;
868 }
869 };
870 let len = ac.get().len();
871
872 let mut buf = [0u8; 20];
873 let mut i = 0usize;
874 for cn in &n.arr_children {
875 let k = index_key(i, &mut buf);
876 w.push(PathPart::Index(i));
877 let mut scratch = Value::Undefined;
878 let (child, appended) = match &mut ac {
879 Cur::Mut(a) => {
880 let appended = i >= a.len();
881 if appended {
882 a.push(Value::Undefined);
883 }
884 (Cur::Mut(&mut a[i]), appended)
885 }
886 Cur::Ref(a) => match a.get(i) {
887 Some(e) if !e.is_undefined() => (Cur::Ref(e), false),
888 _ => (Cur::Mut(&mut scratch), true),
889 },
890 };
891 let keep = if cn.is_ignore() {
892 validate_ignored(cn, child, k, true, w, verr)
893 } else {
894 validate_node(cn, child, k, true, w, verr)
895 };
896 w.pop();
897 if !keep && !appended && cn.is_ignore() {
898 if let Cur::Mut(a) = &mut ac {
899 a[i] = Value::Undefined;
900 }
901 }
902 i += 1;
903 }
904 if let Cur::Mut(a) = &mut ac {
907 while a.len() > len && a.last().map(|x| x.is_undefined()).unwrap_or(false) {
908 a.pop();
909 }
910 }
911
912 if let Some(child_shape) = n.arr_child.as_deref().or(n.arr_rest.as_deref()) {
913 let mut drop_at: Vec<usize> = Vec::new();
914 while i < len {
915 if child_shape.plain {
919 if plain_scalar_passes(child_shape, &ac.get()[i]) {
920 i += 1;
921 continue;
922 }
923 if let Cur::Ref(a) = &ac {
924 let v = &a[i];
925 if child_shape.kind == Kind::Object && matches!(v, Value::Obj(_)) {
926 let k = if w.paths { index_key(i, &mut buf) } else { "" };
927 w.push(PathPart::Index(i));
928 validate_object(
929 child_shape,
930 child_shape.silent,
931 Cur::Ref(v),
932 k,
933 true,
934 w,
935 verr,
936 );
937 w.pop();
938 i += 1;
939 continue;
940 }
941 }
942 }
943 let k = index_key(i, &mut buf);
944 w.push(PathPart::Index(i));
945 let child = match &mut ac {
946 Cur::Mut(a) => Cur::Mut(&mut a[i]),
947 Cur::Ref(a) => Cur::Ref(&a[i]),
948 };
949 let keep = if child_shape.is_ignore() {
950 validate_ignored(child_shape, child, k, true, w, verr)
951 } else {
952 validate_node(child_shape, child, k, true, w, verr)
953 };
954 w.pop();
955 if !keep && child_shape.is_ignore() {
956 drop_at.push(i);
957 }
958 i += 1;
959 }
960 if let Cur::Mut(a) = &mut ac {
961 for idx in drop_at {
962 a[idx] = Value::Undefined;
963 }
964 }
965 }
966 true
967}
968
969pub(crate) fn validate_ignored(
972 n: &Node,
973 cur: Cur<'_>,
974 key: &str,
975 parent_is_array: bool,
976 w: &mut Walk<'_>,
977 _verr: &mut ValidationError,
978) -> bool {
979 let mut sub = ValidationError::default();
980 let kept = validate_node_with(
981 n,
982 &n.befores,
983 &n.afters,
984 false,
985 cur,
986 key,
987 parent_is_array,
988 w,
989 &mut sub,
990 );
991 !sub.has_any() && kept
992}
993
994fn branch_passes(
996 sn: &Node,
997 value: &Value,
998 key: &str,
999 parent_is_array: bool,
1000 w: &mut Walk<'_>,
1001) -> bool {
1002 let saved = (w.is_match, w.ctx.terse);
1003 w.is_match = true;
1004 w.ctx.terse = true;
1005 let mut sub = ValidationError {
1006 terse: true,
1007 ..Default::default()
1008 };
1009 validate_node(sn, Cur::Ref(value), key, parent_is_array, w, &mut sub);
1010 w.is_match = saved.0;
1011 w.ctx.terse = saved.1;
1012 !sub.has_any()
1013}
1014
1015#[allow(clippy::too_many_arguments)]
1016fn list_error(
1017 n: &Node,
1018 silent: bool,
1019 value: &Value,
1020 key: &str,
1021 parent_is_array: bool,
1022 w: &Walk<'_>,
1023 verr: &mut ValidationError,
1024 why: &str,
1025 mark: i64,
1026 words: &str,
1027 fault_applies: bool,
1028) {
1029 let names: Vec<String> = n.list.iter().map(|sn| stringify_node(sn, true)).collect();
1030 let at = at_of(w, key, n, value, parent_is_array, "");
1031 let text = format!(
1032 "Value \"$VALUE\" for property \"$PATH\" does not satisfy {}: {}",
1033 words,
1034 names.join(", ")
1035 );
1036 let mut err = make_err(&at, why, mark, &text);
1037 if fault_applies && !err.terse {
1038 if let Some(f) = &n.fault_msg {
1039 err.text = expand_err_text(f, &err.path, value, at.absent);
1040 }
1041 }
1042 if !silent {
1043 verr.add(err);
1044 }
1045}
1046
1047#[allow(clippy::too_many_arguments)]
1051fn evaluate_list(
1052 n: &Node,
1053 silent: bool,
1054 mut cur: Cur<'_>,
1055 key: &str,
1056 parent_is_array: bool,
1057 _absent: bool,
1058 w: &mut Walk<'_>,
1059 verr: &mut ValidationError,
1060) -> bool {
1061 match n.list_mode {
1062 ListMode::One => {
1063 let winner = n
1064 .list
1065 .iter()
1066 .position(|sn| branch_passes(sn, cur.get(), key, parent_is_array, w));
1067 match winner {
1068 Some(i) => {
1069 let mut sub = ValidationError::default();
1071 validate_node(
1072 &n.list[i],
1073 cur.reborrow(),
1074 key,
1075 parent_is_array,
1076 w,
1077 &mut sub,
1078 )
1079 }
1080 None => {
1081 list_error(
1082 n,
1083 silent,
1084 cur.get(),
1085 key,
1086 parent_is_array,
1087 w,
1088 verr,
1089 "One",
1090 4030,
1091 "one of",
1092 true,
1093 );
1094 true
1095 }
1096 }
1097 }
1098 ListMode::Some => {
1099 let original = cur.get().clone();
1103 let mut matched = false;
1104 let mut kept = true;
1105 for sn in &n.list {
1106 if !branch_passes(sn, &original, key, parent_is_array, w) {
1107 continue;
1108 }
1109 matched = true;
1110 cur.set(original.clone());
1111 let mut sub = ValidationError::default();
1112 kept = validate_node(sn, cur.reborrow(), key, parent_is_array, w, &mut sub);
1113 }
1114 if !matched {
1115 list_error(
1116 n,
1117 silent,
1118 &original,
1119 key,
1120 parent_is_array,
1121 w,
1122 verr,
1123 "Some",
1124 4031,
1125 "any of",
1126 true,
1127 );
1128 return true;
1129 }
1130 kept
1131 }
1132 _ => {
1133 let original = cur.get().clone();
1136 let mut pass_all = true;
1137 let mut kept = true;
1138 for sn in &n.list {
1139 let before = cur.get().clone();
1140 let mut sub = ValidationError::default();
1141 let k = validate_node(sn, cur.reborrow(), key, parent_is_array, w, &mut sub);
1142 if sub.has_any() {
1143 pass_all = false;
1144 cur.set(before);
1145 } else {
1146 kept = k;
1147 }
1148 }
1149 if !pass_all {
1150 cur.set(original.clone());
1151 list_error(
1152 n,
1153 silent,
1154 &original,
1155 key,
1156 parent_is_array,
1157 w,
1158 verr,
1159 "All",
1160 4032,
1161 "all of",
1162 false,
1163 );
1164 return true;
1165 }
1166 if original.is_undefined() {
1169 cur.set(original);
1170 }
1171 kept
1172 }
1173 }
1174}
1175
1176#[cfg(test)]
1177mod tests {
1178 use super::*;
1179 use crate::builders::*;
1180 use crate::node::{Token, Validator};
1181 use crate::spec::{arr, obj, Spec};
1182 use crate::Schema;
1183 use regex::Regex;
1184 use std::sync::Arc;
1185
1186 fn chk(
1187 name: &str,
1188 f: impl Fn(&mut State<'_>, &mut Update) -> bool + Send + Sync + 'static,
1189 ) -> Validator {
1190 Validator {
1191 name: name.into(),
1192 func: Arc::new(f),
1193 args: vec![],
1194 suffix: None,
1195 inner: None,
1196 }
1197 }
1198
1199 fn j(s: &str) -> Value {
1200 Value::from(serde_json::from_str::<serde_json::Value>(s).unwrap())
1201 }
1202
1203 fn run(s: &Schema, input: &str) -> String {
1204 match s.validate(j(input)) {
1205 Ok(v) => serde_json::Value::from(v).to_string(),
1206 Err(e) => format!("ERR {}", e),
1207 }
1208 }
1209
1210 fn before(mut n: Node, v: Validator) -> Node {
1211 n.befores.push(v);
1212 n
1213 }
1214
1215 fn after(mut n: Node, v: Validator) -> Node {
1216 n.afters.push(v);
1217 n
1218 }
1219
1220 fn at_a(n: impl Into<Spec>) -> Schema {
1221 Schema::new(obj([("a", n.into())]))
1222 }
1223
1224 fn fail() -> Validator {
1225 chk("Odd", |_, _| false)
1226 }
1227
1228 #[test]
1229 fn index_keys_need_no_allocation() {
1230 let mut buf = [0u8; 20];
1231 assert_eq!(index_key(0, &mut buf), "0");
1232 assert_eq!(index_key(7, &mut buf), "7");
1233 assert_eq!(index_key(1234567890123, &mut buf), "1234567890123");
1234 }
1235
1236 #[test]
1237 fn plain_nodes_take_the_direct_path() {
1238 let s = Schema::new(obj([
1241 ("a", obj([("b", Spec::from(Token::Number))])),
1242 ("c", arr([obj([("d", Spec::from(Token::String))])])),
1243 ("e", arr([Spec::from(Token::Integer)])),
1244 ("f", Spec::from(Token::Boolean)),
1245 ]));
1246 assert!(s.valid(&j(
1247 r#"{"a":{"b":1},"c":[{"d":"x"},{"d":"y"}],"e":[1,2],"f":true}"#
1248 )));
1249 let bad = j(r#"{"a":{"b":"x"},"c":[{"d":"x"},{"d":2}],"e":[1,2.5],"f":1}"#);
1250 assert!(!s.valid(&bad));
1251 let paths: Vec<String> = s.error(&bad).iter().map(|e| e.path.clone()).collect();
1252 assert_eq!(paths, vec!["a.b", "c.1.d", "e.1", "f"]);
1253 assert_eq!(
1255 run(&s, r#"{"a":{"b":1},"c":[],"e":[],"f":false}"#),
1256 r#"{"a":{"b":1},"c":[],"e":[],"f":false}"#
1257 );
1258 let e = Schema::new(obj([("s", Spec::from(Token::String))]));
1260 assert!(!e.valid(&j(r#"{"s":""}"#)));
1261 assert!(
1262 Schema::new(obj([("s", Spec::from(empty(Token::String)))])).valid(&j(r#"{"s":""}"#))
1263 );
1264 }
1265
1266 #[test]
1267 fn unprepared_object_keys_are_allocated() {
1268 let n = crate::normalize::normalize(obj([("a", Token::Number)]));
1271 assert!(n.obj_keys.is_empty());
1272 let mut ctx = crate::Context::new();
1273 let defs = HashMap::new();
1274 let mut w = Walk {
1275 ctx: &mut ctx,
1276 defs: &defs,
1277 is_match: false,
1278 path: Vec::new(),
1279 paths: true,
1280 };
1281 let mut verr = ValidationError::default();
1282 let mut val = j(r#"{"a":"x"}"#);
1283 validate_node(&n, Cur::Mut(&mut val), "", false, &mut w, &mut verr);
1284 assert_eq!(
1286 verr.to_string(),
1287 "Validation failed for object \"{a:x}\" because the property \"a\" is not allowed.\n\
1288 Validation failed for property \"a\" with string \"x\" because the string is not of type number."
1289 );
1290 }
1291
1292 #[test]
1293 fn marks() {
1294 assert_eq!(required_mark_for(Kind::Object), MARK_OBJECT_REQUIRED);
1295 assert_eq!(required_mark_for(Kind::Array), MARK_ARRAY_REQUIRED);
1296 assert_eq!(required_mark_for(Kind::String), MARK_SCALAR_REQUIRED);
1297 assert_eq!(type_mark_for(Kind::Object), MARK_OBJECT_TYPE);
1298 assert_eq!(type_mark_for(Kind::Array), MARK_ARRAY_TYPE);
1299 assert_eq!(type_mark_for(Kind::Check), MARK_CHECK_TYPE);
1300 assert_eq!(type_mark_for(Kind::String), MARK_SCALAR_TYPE);
1301 }
1302
1303 #[test]
1304 fn custom_check_errors() {
1305 let s = at_a(before(buildize(Token::Number), fail()));
1306 assert_eq!(
1307 run(&s, r#"{"a":1}"#),
1308 "ERR Validation failed for property \"a\" with number \"1\" because check \"Odd\" failed."
1309 );
1310 assert!(!s.valid(&j(r#"{"a":1}"#)));
1311 assert_eq!(s.error(&j(r#"{"a":1}"#))[0].mark, MARK_CUSTOM_CHECK_ERR);
1312
1313 let s = at_a(before(fault("bad $PATH $VALUE", Token::Number), fail()));
1314 assert_eq!(run(&s, r#"{"a":1}"#), "ERR bad a 1");
1315 assert!(!s.valid(&j(r#"{"a":1}"#)));
1316
1317 let mut quiet = buildize(Token::Number);
1318 quiet.silent = true;
1319 let s = at_a(before(quiet, fail()));
1320 assert_eq!(run(&s, r#"{"a":1}"#), r#"{"a":1}"#);
1321
1322 let text = chk("T", |_, u| {
1323 u.err = Some(UpdateErr::Text("no $PATH=$VALUE".into()));
1324 false
1325 });
1326 let s = at_a(before(buildize(Token::Number), text));
1327 assert_eq!(run(&s, r#"{"a":1}"#), "ERR no a=1");
1328 let e = &s.error(&j(r#"{"a":1}"#))[0];
1329 assert_eq!(
1330 (e.mark, e.why.as_str()),
1331 (MARK_CUSTOM_CHECK_TEXT, WHY_CHECK)
1332 );
1333
1334 let marked = chk("M", |_, u| {
1335 u.err = Some(UpdateErr::Text("m".into()));
1336 u.why = Some("odd".into());
1337 u.mark = 99;
1338 false
1339 });
1340 let e = &at_a(before(buildize(Token::Number), marked)).error(&j(r#"{"a":1}"#))[0];
1341 assert_eq!((e.mark, e.why.as_str(), e.text.as_str()), (99, "odd", "m"));
1342 let marked = chk("M", |_, u| {
1343 u.why = Some("odd".into());
1344 u.mark = 98;
1345 false
1346 });
1347 let e = &at_a(before(buildize(Token::Number), marked)).error(&j(r#"{"a":1}"#))[0];
1348 assert_eq!((e.mark, e.why.as_str()), (98, "odd"));
1349
1350 let field = chk("F", |_, u| {
1351 u.err = Some(UpdateErr::Field(Box::new(FieldError {
1352 text: "f".into(),
1353 ..Default::default()
1354 })));
1355 false
1356 });
1357 let s = at_a(before(buildize(Token::Number), field));
1358 assert_eq!(run(&s, r#"{"a":1}"#), "ERR f");
1359 let e = &s.error(&j(r#"{"a":1}"#))[0];
1360 assert_eq!((e.path.as_str(), e.mark), ("a", MARK_CUSTOM_CHECK_TEXT));
1361
1362 let fields = chk("F", |_, u| {
1363 u.err = Some(UpdateErr::Fields(vec![
1364 FieldError {
1365 text: "f1".into(),
1366 ..Default::default()
1367 },
1368 FieldError {
1369 text: "f2".into(),
1370 path: "z".into(),
1371 mark: 7,
1372 ..Default::default()
1373 },
1374 ]));
1375 false
1376 });
1377 let s = at_a(before(buildize(Token::Number), fields));
1378 assert_eq!(run(&s, r#"{"a":1}"#), "ERR f1\nf2");
1379 let es = s.error(&j(r#"{"a":1}"#));
1380 assert_eq!((es[1].path.as_str(), es[1].mark), ("z", 7));
1381 }
1382
1383 #[test]
1384 fn befores_replace_value_or_node_and_may_stop() {
1385 let dbl = chk("Dbl", |s, u| {
1386 if let Value::Num(x) = s.value {
1387 u.val = Some(Value::Num(x * 2.0));
1388 }
1389 true
1390 });
1391 let s = at_a(before(buildize(Token::Number), dbl));
1392 assert_eq!(run(&s, r#"{"a":2}"#), r#"{"a":4}"#);
1393 assert!(s.valid(&j(r#"{"a":2}"#)));
1394
1395 let to_str = chk("Str", |_, u| {
1396 u.val = Some(Value::Str("x".into()));
1397 true
1398 });
1399 let s = at_a(before(buildize(Token::Number), to_str));
1400 assert_eq!(
1401 run(&s, r#"{"a":2}"#),
1402 "ERR Validation failed for property \"a\" with string \"x\" because the string is not of type number."
1403 );
1404 assert!(!s.valid(&j(r#"{"a":2}"#)));
1405
1406 let swap = chk("Swap", |_, u| {
1407 u.node = Some(Arc::new(buildize(Token::String)));
1408 true
1409 });
1410 let s = at_a(before(buildize(Token::Number), swap));
1411 assert_eq!(run(&s, r#"{"a":"x"}"#), r#"{"a":"x"}"#);
1412
1413 let stop = chk("Stop", |_, u| {
1414 u.done = true;
1415 true
1416 });
1417 let s = at_a(before(buildize(Token::Number), stop));
1418 assert_eq!(run(&s, r#"{"a":"x"}"#), r#"{"a":"x"}"#);
1419
1420 let s = at_a(before(optional(Token::Number), fail()));
1422 assert_eq!(run(&s, "{}"), r#"{"a":0}"#);
1423 let insist = chk("I", |_, u| {
1425 u.done = true;
1426 false
1427 });
1428 let s = at_a(before(optional(Token::Number), insist));
1429 assert_eq!(s.error(&j("{}")).len(), 1);
1430 let s = at_a(before(required(Token::Number), fail()));
1432 assert_eq!(s.error(&j("{}")).len(), 1);
1433 let peek = chk("Peek", |s, _| {
1435 s.absent && s.key == "a" && s.path_str() == "a" && !s.is_match && !s.parent_is_array
1436 });
1437 let s = at_a(before(optional(Token::Number), peek));
1438 assert_eq!(run(&s, "{}"), r#"{"a":0}"#);
1439 }
1440
1441 #[test]
1442 fn afters_run_after_structure() {
1443 let s = at_a(after(buildize(Token::Number), fail()));
1444 assert_eq!(s.error(&j(r#"{"a":1}"#))[0].check, "Odd");
1445
1446 let inc = chk("Inc", |s, u| {
1447 if let Value::Num(x) = s.value {
1448 u.val = Some(Value::Num(x + 1.0));
1449 }
1450 true
1451 });
1452 let s = at_a(after(buildize(Token::Number), inc));
1453 assert_eq!(run(&s, r#"{"a":1}"#), r#"{"a":2}"#);
1454 assert!(s.valid(&j(r#"{"a":1}"#)));
1455
1456 let fill = chk("Fill", |_, u| {
1457 u.val = Some(Value::Num(9.0));
1458 true
1459 });
1460 let s = at_a(after(skip(Token::Number), fill));
1461 assert_eq!(run(&s, "{}"), r#"{"a":9}"#);
1462
1463 let s = at_a(after(optional(Token::Number), fail()));
1465 assert_eq!(
1466 run(&s, "{}"),
1467 "ERR Validation failed for property \"a\" with number \"0\" because check \"Odd\" failed."
1468 );
1469 let s = at_a(after(skip(Token::Number), fail()));
1470 assert_eq!(run(&s, "{}"), "{}");
1471 }
1472
1473 #[test]
1474 fn structural_rules() {
1475 assert_eq!(
1476 run(&Schema::new(one([Spec::from(Token::Number)])), "1"),
1477 "1"
1478 );
1479 assert_eq!(
1480 run(&Schema::new(Spec::from(Node::of(Kind::List))), "1"),
1481 "1"
1482 );
1483
1484 assert_eq!(
1485 run(&at_a(nullable(Token::String)), r#"{"a":null}"#),
1486 r#"{"a":null}"#
1487 );
1488
1489 let s = at_a(never(1));
1490 assert_eq!(s.error(&j(r#"{"a":1}"#))[0].why, WHY_NEVER);
1491 assert_eq!(s.error(&j("{}"))[0].why, WHY_NEVER);
1492 assert!(!s.valid(&j("{}")));
1493 assert_eq!(run(&at_a(never(1).fault("nope")), r#"{"a":1}"#), "ERR nope");
1494
1495 let re = || Regex::new("^a+$").unwrap();
1496 let s = at_a(buildize(re()));
1497 assert_eq!(
1498 run(&s, r#"{"a":"b"}"#),
1499 "ERR Validation failed for property \"a\" with string \"b\" because the string did not match /^a+$/."
1500 );
1501 assert_eq!(
1502 run(&s, r#"{"a":1}"#),
1503 "ERR Validation failed for property \"a\" with number \"1\" because the number is not of type string."
1504 );
1505 assert_eq!(
1507 run(&s, "{}"),
1508 "ERR Validation failed for property \"a\" with value \"undefined\" because the value is not of type string."
1509 );
1510 assert_eq!(run(&s, r#"{"a":"aa"}"#), r#"{"a":"aa"}"#);
1511 assert_eq!(run(&at_a(optional(re())), "{}"), "{}");
1512 assert_eq!(run(&at_a(fault("F", re())), r#"{"a":1}"#), "ERR F");
1513 assert!(!at_a(fault("F", re())).valid(&j(r#"{"a":1}"#)));
1514 let mut quiet = buildize(re());
1515 quiet.silent = true;
1516 assert_eq!(run(&at_a(quiet), r#"{"a":1}"#), r#"{"a":1}"#);
1517
1518 let s = at_a(obj([("b", Spec::from(Token::String))]));
1521 assert!(!s.valid(&j("{}")));
1522 assert_eq!(s.error(&j("{}"))[0].path, "a.b");
1523 let s = at_a(arr([Spec::from(Token::String), Spec::from(1)]));
1524 assert!(!s.valid(&j("{}")));
1525 assert_eq!(run(&at_a(buildize(Token::Any)), "{}"), "{}");
1526 let s = Schema::new(obj([("b", Spec::from(Token::String))]));
1528 assert!(!s.valid(&Value::Undefined));
1529 assert_eq!(s.error(&Value::Undefined)[0].path, "b");
1530 let s = Schema::new(arr([Spec::from(Token::String), Spec::from(1)]));
1531 assert!(!s.valid(&Value::Undefined));
1532 assert_eq!(s.error(&Value::Undefined)[0].path, "0");
1533 assert!(Schema::new(obj([("b", Spec::from(1))])).valid(&Value::Undefined));
1534 }
1535
1536 #[test]
1537 fn leaf_type_errors() {
1538 let cases: Vec<(Node, &str, &str)> = vec![
1539 (
1540 buildize(Token::Integer),
1541 r#"{"a":1.5}"#,
1542 "number \"1.5\" because the number is not of type integer.",
1543 ),
1544 (
1545 buildize(Token::Boolean),
1546 r#"{"a":1}"#,
1547 "number \"1\" because the number is not of type boolean.",
1548 ),
1549 (
1550 buildize(Spec::Value(Value::Date(0))),
1551 r#"{"a":1}"#,
1552 "number \"1\" because the number is not of type date.",
1553 ),
1554 (
1555 buildize(num_bigint::BigInt::from(1)),
1556 r#"{"a":1}"#,
1557 "number \"1\" because the number is not of type bigint.",
1558 ),
1559 (
1560 buildize(f64::NAN),
1561 r#"{"a":1}"#,
1562 "number \"1\" because the number is not of type nan.",
1563 ),
1564 (
1565 buildize(Spec::Value(Value::Null)),
1566 r#"{"a":1}"#,
1567 "number \"1\" because the number is not of type null.",
1568 ),
1569 (
1570 buildize(Spec::Value(Value::Func(1))),
1571 r#"{"a":1}"#,
1572 "number \"1\" because the number is not of type function.",
1573 ),
1574 ];
1575 for (n, input, tail) in cases {
1576 assert_eq!(
1577 run(&at_a(n), input),
1578 format!("ERR Validation failed for property \"a\" with {}", tail)
1579 );
1580 }
1581 let s = at_a(buildize(Spec::Value(Value::Date(0))));
1582 let dated = Value::Obj([("a".to_string(), Value::Date(5))].into_iter().collect());
1583 assert_eq!(s.validate(dated.clone()).unwrap(), dated);
1584 }
1585
1586 #[test]
1587 fn objects() {
1588 let inner = || obj([("a", Spec::from(1))]);
1589 let s = Schema::new(obj([("o", Spec::from(fault("F $PATH", inner())))]));
1590 assert_eq!(run(&s, r#"{"o":{"z":1}}"#), "ERR F o");
1591 assert!(!s.valid(&j(r#"{"o":{"z":1}}"#)));
1592 let mut quiet = buildize(inner());
1593 quiet.silent = true;
1594 let s = Schema::new(obj([("o", Spec::from(quiet))]));
1595 assert_eq!(run(&s, r#"{"o":{"z":1}}"#), r#"{"o":{"z":1,"a":1}}"#);
1596
1597 let s = Schema::new(obj([("o", inner())]));
1598 assert!(s.valid(&j(r#"{"o":{"a":2}}"#)));
1599 assert!(!s.valid(&j(r#"{"o":{"a":"x"}}"#)));
1600 assert!(s.valid(&j(r#"{"o":{}}"#)));
1601 assert!(!s.valid(&j(r#"{"o":1}"#)));
1602
1603 let s = at_a(ignore(Token::Number));
1604 assert_eq!(run(&s, r#"{"a":"x"}"#), "{}");
1605 assert_eq!(run(&s, r#"{"a":5}"#), r#"{"a":5}"#);
1606 assert_eq!(run(&s, "{}"), "{}");
1607 assert!(s.valid(&j(r#"{"a":"x"}"#)));
1608 assert!(s.valid(&j(r#"{"a":5}"#)));
1609
1610 let s = Schema::new(child(Token::Number, inner()));
1611 assert_eq!(run(&s, r#"{"a":1,"z":2}"#), r#"{"a":1,"z":2}"#);
1612 assert!(!s.valid(&j(r#"{"a":1,"z":"x"}"#)));
1613 let s = Schema::new(child(ignore(Token::Number), inner()));
1614 assert_eq!(run(&s, r#"{"a":1,"z":"x"}"#), r#"{"a":1}"#);
1615 assert!(s.valid(&j(r#"{"a":1,"z":"x"}"#)));
1616 }
1617
1618 #[test]
1619 fn arrays() {
1620 let s = at_a(fault("F", arr([Spec::from(Token::Number)])));
1621 assert_eq!(run(&s, r#"{"a":1}"#), "ERR F");
1622 let tuple = || arr([Spec::from(1), Spec::from(2)]);
1623 assert_eq!(run(&at_a(fault("T", tuple())), r#"{"a":[1,2,3]}"#), "ERR T");
1624 assert!(!at_a(fault("T", tuple())).valid(&j(r#"{"a":[1,2,3]}"#)));
1625 let mut quiet = buildize(tuple());
1626 quiet.silent = true;
1627 assert_eq!(run(&at_a(quiet), r#"{"a":[1,2,3]}"#), r#"{"a":[1,2,3]}"#);
1628
1629 let s = at_a(tuple());
1630 assert!(s.valid(&j(r#"{"a":[1,2]}"#)));
1631 assert!(!s.valid(&j(r#"{"a":["x"]}"#)));
1632 assert!(s.valid(&j(r#"{"a":[]}"#)));
1633 let s = at_a(arr([Spec::from(Token::String), Spec::from(2)]));
1634 assert!(!s.valid(&j(r#"{"a":[]}"#)));
1635
1636 let s = at_a(arr([Spec::from(ignore(Token::Number)), Spec::from(2)]));
1637 assert_eq!(run(&s, r#"{"a":["x",2]}"#), r#"{"a":[null,2]}"#);
1638 assert_eq!(run(&s, r#"{"a":[1]}"#), r#"{"a":[1,2]}"#);
1639 assert!(s.valid(&j(r#"{"a":["x",2]}"#)));
1640
1641 let s = at_a(arr([Spec::from(1), Spec::from(skip(Token::Number))]));
1642 assert_eq!(run(&s, r#"{"a":[]}"#), r#"{"a":[1]}"#);
1643
1644 let s = at_a(arr([Spec::from(Token::Number)]));
1645 assert!(!s.valid(&j(r#"{"a":[1,"x"]}"#)));
1646 assert!(s.valid(&j(r#"{"a":[1,2]}"#)));
1647 let s = at_a(arr([Spec::from(ignore(Token::Number))]));
1648 assert_eq!(run(&s, r#"{"a":[1,"x"]}"#), r#"{"a":[1,null]}"#);
1649 assert!(s.valid(&j(r#"{"a":[1,"x"]}"#)));
1650 }
1651
1652 #[test]
1653 fn root_ignore_drops_a_bad_value() {
1654 let s = Schema::new(ignore(Token::Number));
1655 assert_eq!(run(&s, "\"x\""), "null");
1656 assert_eq!(run(&s, "5"), "5");
1657 assert!(s.valid(&j("\"x\"")));
1658 assert!(s.error(&j("\"x\"")).is_empty());
1659 assert_eq!(s.node().kind, Kind::Number);
1660 }
1661}