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