1#[cfg(test)]
3pub(crate) mod test;
4
5#[cfg(test)]
6mod test_path;
7
8#[cfg(test)]
9mod test_parse_with_schema;
10
11#[cfg(test)]
12mod test_source_json;
13
14#[cfg(test)]
15mod test_path_node;
16
17#[cfg(test)]
18mod test_path_node_matches_str;
19
20#[cfg(test)]
21mod test_path_matches_glob;
22
23pub mod decode;
24pub mod parser;
25pub(crate) mod schema;
26pub(crate) mod walk;
27pub mod write;
28
29use std::{
30 collections::BTreeMap,
31 fmt::{self, Write as _},
32 sync::Arc,
33};
34
35use tracing::{trace, Level};
36
37use crate::{
38 warning::{self, IntoCaveat},
39 Verdict,
40};
41use parser::ErrorKind;
42use parser::{Parser, Span};
43
44#[doc(inline)]
45pub use parser::{line_col, Error, ErrorReport, LineCol};
46pub(crate) use parser::{parse, RawStr};
47
48const PATH_SEPARATOR: char = '.';
49const PATH_ROOT: &str = "$";
50
51#[doc(hidden)]
54#[macro_export]
55macro_rules! required_field_or_bail {
56 ($elem:expr, $fields:expr, $field_name:literal, $warnings:expr) => {
57 match $fields.get($field_name) {
58 Some(field_elem) => field_elem,
59 None => {
60 return $warnings.bail(
61 Warning::FieldRequired {
62 field_name: $field_name.into(),
63 },
64 $elem,
65 );
66 }
67 }
68 };
69}
70
71#[doc(hidden)]
74#[macro_export]
75macro_rules! required_field {
76 ($elem:expr, $fields:expr, $field_name:literal, $warnings:expr) => {{
77 let field = $fields.get($field_name);
78
79 if field.is_none() {
80 $warnings.insert(
81 Warning::FieldRequired {
82 field_name: $field_name.into(),
83 },
84 $elem,
85 );
86 }
87
88 field
89 }};
90}
91
92#[doc(hidden)]
95#[macro_export]
96macro_rules! expect_object_or_bail {
97 ($elem:expr, $warnings:expr) => {
98 match $elem.as_object_fields() {
99 Some(fields) => fields,
100 None => {
101 return $warnings.bail(
102 Warning::FieldInvalidType {
103 expected_type: json::ValueKind::Object,
104 },
105 $elem,
106 );
107 }
108 }
109 };
110}
111
112#[doc(hidden)]
115#[macro_export]
116macro_rules! expect_array_or_bail {
117 ($elem:expr, $warnings:expr) => {
118 match $elem.as_array() {
119 Some(fields) => fields,
120 None => {
121 return $warnings.bail(
122 Warning::FieldInvalidType {
123 expected_type: json::ValueKind::Array,
124 },
125 $elem,
126 );
127 }
128 }
129 };
130}
131
132#[doc(hidden)]
136#[macro_export]
137macro_rules! parse_required_or_bail {
138 ($elem:expr, $fields:expr, $elem_name:literal, $target:ty, $warnings:expr) => {{
139 #[allow(
140 unused,
141 reason = "the macro uses the import but maybe the outside scope does too."
142 )]
143 use $crate::json::FromJson;
144 use $crate::warning::GatherWarnings as _;
145
146 let elem = $crate::required_field_or_bail!($elem, $fields, $elem_name, $warnings);
147 <$target as FromJson>::from_json(elem)?.gather_warnings_into(&mut $warnings)
148 }};
149}
150
151#[doc(hidden)]
155#[macro_export]
156macro_rules! parse_required {
157 ($elem:expr, $fields:expr, $elem_name:literal, $target:ty, $warnings:expr) => {{
158 #[allow(
159 unused,
160 reason = "the macro uses the import but maybe the outside scope does too."
161 )]
162 use $crate::json::FromJson;
163 use $crate::warning::GatherWarnings as _;
164
165 let elem = $crate::required_field!($elem, $fields, $elem_name, $warnings);
166
167 if let Some(elem) = elem {
168 let value =
169 <$target as FromJson>::from_json(elem)?.gather_warnings_into(&mut $warnings);
170 Some(value)
171 } else {
172 None
173 }
174 }};
175}
176
177#[doc(hidden)]
180#[macro_export]
181macro_rules! parse_nullable_or_bail {
182 ($fields:expr, $elem_name:literal, $target:ty, $warnings:expr) => {{
183 #[allow(
184 unused,
185 reason = "the macro uses the import but maybe the outside scope does too."
186 )]
187 use $crate::json::FromJson as _;
188 use $crate::warning::GatherWarnings as _;
189
190 match $fields.get($elem_name) {
191 Some(elem) => Option::<$target>::from_json(elem)?.gather_warnings_into(&mut $warnings),
192 None => None,
193 }
194 }};
195}
196
197pub(crate) trait FromJson<'buf>: Sized {
199 type Warning: crate::Warning;
200
201 fn from_json(elem: &Element<'buf>) -> Verdict<Self, Self::Warning>;
203}
204
205impl<'buf, T> FromJson<'buf> for Option<T>
209where
210 T: FromJson<'buf> + IntoCaveat,
211{
212 type Warning = T::Warning;
213
214 fn from_json(elem: &Element<'buf>) -> Verdict<Self, Self::Warning> {
215 let value = elem.as_value();
216
217 if value.is_null() {
218 Ok(None.into_caveat(warning::Set::new()))
219 } else {
220 let v = T::from_json(elem)?;
221 Ok(v.map(Some))
222 }
223 }
224}
225
226#[derive(Clone, Debug, Eq, PartialEq)]
230pub struct Element<'buf> {
231 id: ElemId,
233
234 path_node: PathNodeRef<'buf>,
236
237 span: Span,
241
242 value: Value<'buf>,
244}
245
246#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq, Ord, PartialOrd)]
250pub(crate) struct ElemId(usize);
251
252impl fmt::Display for ElemId {
253 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
254 fmt::Display::fmt(&self.0, f)
255 }
256}
257
258impl<'buf> Element<'buf> {
259 fn new(id: ElemId, path: PathNodeRef<'buf>, span: Span, value: Value<'buf>) -> Element<'buf> {
261 Element {
262 id,
263 path_node: path,
264 span,
265 value,
266 }
267 }
268
269 pub(crate) const fn id(&self) -> ElemId {
271 self.id
272 }
273
274 pub fn path(&self) -> PathRef<'buf> {
276 PathRef(self.path_node())
277 }
278
279 pub(crate) fn path_node(&self) -> PathNodeRef<'buf> {
281 Arc::clone(&self.path_node)
282 }
283
284 pub fn span(&self) -> Span {
286 self.span
287 }
288
289 pub fn source_json(&self, source_json: &'buf str) -> SourceStr<'buf> {
303 if let PathNode::Object { key, .. } = *self.path_node {
304 let span = Span {
306 start: key.span().start,
307 end: self.span.end,
309 };
310 let field_str = &source_json
311 .get(span.start..span.end)
312 .expect("The disconnection between the source JSON and the `Element` will be fixed in a future PR");
313 let field = RawStr::from_str(field_str, span);
314 let (key, value) = field_str
315 .split_once(':')
316 .expect("An objects field always contains a delimiting `:`");
317
318 SourceStr::Field { field, key, value }
319 } else {
320 let span = self.span;
321 let s = source_json
322 .get(span.start..span.end)
323 .expect("The disconnection between the source JSON and the `Element` will be fixed in a future PR");
324 SourceStr::Value(RawStr::from_str(s, span))
325 }
326 }
327
328 pub fn source_json_value(&self, source_json: &'buf str) -> &'buf str {
341 source_json
342 .get(self.span.start..self.span.end)
343 .expect("The disconnection between the source JSON and the `Element` will be fixed in a future PR")
344 }
345
346 pub(crate) fn value(&self) -> &Value<'buf> {
348 &self.value
349 }
350
351 pub(crate) fn as_value(&self) -> &Value<'buf> {
353 &self.value
354 }
355
356 pub(crate) fn to_raw_str(&self) -> Option<RawStr<'buf>> {
358 self.value.to_raw_str()
359 }
360
361 pub(crate) fn as_object_fields(&self) -> Option<&[Field<'buf>]> {
363 self.value.as_object_fields()
364 }
365
366 pub(crate) fn as_array(&self) -> Option<&[Element<'buf>]> {
367 self.value.as_array()
368 }
369
370 pub fn as_number_str(&self) -> Option<&str> {
371 self.value.as_number()
372 }
373}
374
375#[derive(Debug)]
376pub enum SourceStr<'buf> {
377 Value(RawStr<'buf>),
379
380 Field {
382 field: RawStr<'buf>,
384
385 key: &'buf str,
387
388 value: &'buf str,
390 },
391}
392
393impl fmt::Display for SourceStr<'_> {
394 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
395 match self {
396 SourceStr::Value(s) => f.write_str(s.as_raw()),
397 SourceStr::Field { field, .. } => f.write_str(field.as_raw()),
398 }
399 }
400}
401
402impl PartialEq<&str> for SourceStr<'_> {
404 fn eq(&self, other: &&str) -> bool {
405 match self {
406 SourceStr::Value(s) => s.as_raw() == *other,
407 SourceStr::Field { field, .. } => field.as_raw() == *other,
408 }
409 }
410}
411
412impl PartialEq<String> for SourceStr<'_> {
414 fn eq(&self, other: &String) -> bool {
415 self.eq(&&**other)
416 }
417}
418
419impl PartialOrd for Element<'_> {
420 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
421 Some(self.cmp(other))
422 }
423}
424
425impl Ord for Element<'_> {
426 fn cmp(&self, other: &Self) -> std::cmp::Ordering {
427 self.path_node.cmp(&other.path_node)
428 }
429}
430
431impl fmt::Display for Element<'_> {
432 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
433 write!(f, "{} = {}", self.path_node, self.value)
434 }
435}
436
437#[derive(Clone, Debug, Eq, PartialEq)]
439pub(crate) struct Field<'buf>(Element<'buf>);
440
441impl<'buf> Field<'buf> {
442 #[expect(
443 clippy::unreachable,
444 reason = "A Field is created by the parser when the type is an Object."
445 )]
446 pub(crate) fn key(&self) -> RawStr<'buf> {
447 let PathNode::Object { key, .. } = *self.0.path_node else {
448 unreachable!();
449 };
450
451 key
452 }
453
454 pub(crate) fn into_element(self) -> Element<'buf> {
456 self.0
457 }
458
459 pub(crate) fn element(&self) -> &Element<'buf> {
461 &self.0
462 }
463}
464
465#[derive(Clone, Debug, Eq, PartialEq)]
467pub(crate) enum Value<'buf> {
468 Null,
470
471 True,
473
474 False,
476
477 String(RawStr<'buf>),
479
480 Number(&'buf str),
485
486 Array(Vec<Element<'buf>>),
491
492 Object(Vec<Field<'buf>>),
498}
499
500impl<'buf> Value<'buf> {
501 pub(crate) fn kind(&self) -> ValueKind {
502 match self {
503 Value::Null => ValueKind::Null,
504 Value::True | Value::False => ValueKind::Bool,
505 Value::String(_) => ValueKind::String,
506 Value::Number(_) => ValueKind::Number,
507 Value::Array(_) => ValueKind::Array,
508 Value::Object(_) => ValueKind::Object,
509 }
510 }
511
512 pub(crate) fn is_null(&self) -> bool {
513 matches!(self, Value::Null)
514 }
515
516 pub(crate) fn is_scalar(&self) -> bool {
518 matches!(
519 self,
520 Value::Null | Value::True | Value::False | Value::String(_) | Value::Number(_)
521 )
522 }
523
524 pub(crate) fn as_array(&self) -> Option<&[Element<'buf>]> {
525 match self {
526 Value::Array(elems) => Some(elems),
527 _ => None,
528 }
529 }
530
531 pub(crate) fn as_number(&self) -> Option<&str> {
532 match self {
533 Value::Number(s) => Some(s),
534 _ => None,
535 }
536 }
537
538 pub(crate) fn to_raw_str(&self) -> Option<RawStr<'buf>> {
540 match self {
541 Value::String(s) => Some(*s),
542 _ => None,
543 }
544 }
545
546 pub(crate) fn as_object_fields(&self) -> Option<&[Field<'buf>]> {
548 match self {
549 Value::Object(fields) => Some(fields),
550 _ => None,
551 }
552 }
553}
554
555impl fmt::Display for Value<'_> {
556 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
557 match self {
558 Self::Null => write!(f, "null"),
559 Self::True => write!(f, "true"),
560 Self::False => write!(f, "false"),
561 Self::String(s) => write!(f, "{s}"),
562 Self::Number(s) => write!(f, "{s}"),
563 Self::Array(..) => f.write_str("[...]"),
564 Self::Object(..) => f.write_str("{...}"),
565 }
566 }
567}
568
569#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd)]
571pub enum ValueKind {
572 Null,
573 Bool,
574 Number,
575 String,
576 Array,
577 Object,
578}
579
580impl fmt::Display for ValueKind {
581 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
582 match self {
583 ValueKind::Null => write!(f, "null"),
584 ValueKind::Bool => write!(f, "bool"),
585 ValueKind::Number => write!(f, "number"),
586 ValueKind::String => write!(f, "string"),
587 ValueKind::Array => write!(f, "array"),
588 ValueKind::Object => write!(f, "object"),
589 }
590 }
591}
592
593#[derive(Copy, Clone, Debug, Eq, PartialEq)]
597pub(crate) enum ObjectKind {
598 Object,
599 Array,
600}
601
602pub type RawMap<'buf> = BTreeMap<RawStr<'buf>, Element<'buf>>;
603pub type RawRefMap<'a, 'buf> = BTreeMap<RawStr<'buf>, &'a Element<'buf>>;
604
605#[expect(dead_code, reason = "pending use in `tariff::lint`")]
606pub(crate) trait FieldsIntoExt<'buf> {
607 fn into_map(self) -> RawMap<'buf>;
608}
609
610pub(crate) trait FieldsAsExt<'buf> {
611 fn as_raw_map(&self) -> RawRefMap<'_, 'buf>;
612 fn find_field(&self, key: &str) -> Option<&Field<'buf>>;
613}
614
615impl<'buf> FieldsIntoExt<'buf> for Vec<Field<'buf>> {
616 fn into_map(self) -> RawMap<'buf> {
617 self.into_iter()
618 .map(|field| (field.key(), field.into_element()))
619 .collect()
620 }
621}
622
623impl<'buf> FieldsAsExt<'buf> for Vec<Field<'buf>> {
624 fn as_raw_map(&self) -> RawRefMap<'_, 'buf> {
625 self.iter()
626 .map(|field| (field.key(), field.element()))
627 .collect()
628 }
629
630 fn find_field(&self, key: &str) -> Option<&Field<'buf>> {
631 self.iter().find(|field| field.key().as_raw() == key)
632 }
633}
634
635impl<'buf> FieldsAsExt<'buf> for [Field<'buf>] {
636 fn as_raw_map(&self) -> RawRefMap<'_, 'buf> {
637 self.iter()
638 .map(|field| (field.key(), field.element()))
639 .collect()
640 }
641
642 fn find_field(&self, key: &str) -> Option<&Field<'buf>> {
643 self.iter().find(|field| field.key().as_raw() == key)
644 }
645}
646
647#[derive(Clone, Debug)]
650pub struct UnexpectedFields<'buf>(Vec<PathNodeRef<'buf>>);
651
652impl fmt::Display for UnexpectedFields<'_> {
653 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
654 if f.alternate() {
655 f.write_str("[\n")?;
657 for entry in &self.0 {
658 writeln!(f, "\t\"{entry}\",")?;
659 }
660 f.write_str("]\n")?;
661 } else {
662 f.write_char('[')?;
664 for entry in &self.0 {
665 write!(f, "{entry},")?;
666 }
667 f.write_char(']')?;
668 }
669
670 Ok(())
671 }
672}
673
674impl<'buf> UnexpectedFields<'buf> {
675 pub(crate) fn empty() -> Self {
677 Self(vec![])
678 }
679
680 pub(crate) fn from_vec(v: Vec<PathNodeRef<'buf>>) -> Self {
682 Self(v)
683 }
684
685 pub fn to_strings(&self) -> Vec<String> {
687 self.0.iter().map(ToString::to_string).collect()
688 }
689
690 pub fn into_strings(self) -> Vec<String> {
692 self.0.into_iter().map(|path| path.to_string()).collect()
693 }
694
695 pub fn is_empty(&self) -> bool {
697 self.0.is_empty()
698 }
699
700 pub fn len(&self) -> usize {
702 self.0.len()
703 }
704
705 pub fn iter<'a>(&'a self) -> UnexpectedFieldsIter<'a, 'buf> {
707 UnexpectedFieldsIter(self.0.iter())
708 }
709}
710
711impl<'buf> IntoIterator for UnexpectedFields<'buf> {
712 type Item = PathRef<'buf>;
713
714 type IntoIter = UnexpectedFieldsIntoIter<'buf>;
715
716 fn into_iter(self) -> Self::IntoIter {
717 UnexpectedFieldsIntoIter(self.0.into_iter())
718 }
719}
720
721pub struct UnexpectedFieldsIntoIter<'buf>(std::vec::IntoIter<PathNodeRef<'buf>>);
722
723impl<'buf> Iterator for UnexpectedFieldsIntoIter<'buf> {
724 type Item = PathRef<'buf>;
725
726 fn next(&mut self) -> Option<Self::Item> {
727 let path_node = self.0.next()?;
728
729 Some(PathRef(path_node))
730 }
731}
732
733impl<'a, 'buf> IntoIterator for &'a UnexpectedFields<'buf> {
734 type Item = PathRef<'buf>;
735
736 type IntoIter = UnexpectedFieldsIter<'a, 'buf>;
737
738 fn into_iter(self) -> Self::IntoIter {
739 self.iter()
740 }
741}
742
743pub struct UnexpectedFieldsIter<'a, 'buf>(std::slice::Iter<'a, PathNodeRef<'buf>>);
745
746impl<'buf> Iterator for UnexpectedFieldsIter<'_, 'buf> {
747 type Item = PathRef<'buf>;
748
749 fn next(&mut self) -> Option<Self::Item> {
750 let path_node = self.0.next()?;
751
752 Some(PathRef(Arc::clone(path_node)))
753 }
754}
755
756pub struct PathRef<'buf>(PathNodeRef<'buf>);
764
765impl fmt::Debug for PathRef<'_> {
766 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
767 write!(f, "{self}")
768 }
769}
770
771impl<'buf> PathRef<'buf> {
772 pub fn components(&self) -> PathComponents<'buf> {
774 PathComponents(PathIter::new(Arc::clone(&self.0)))
775 }
776}
777
778pub struct PathComponents<'buf>(PathIter<'buf>);
780
781impl<'buf> Iterator for PathComponents<'buf> {
782 type Item = PathComponent<'buf>;
783
784 fn next(&mut self) -> Option<Self::Item> {
785 let path_node = self.0.next()?;
786 Some(PathComponent(path_node))
787 }
788}
789
790impl PartialEq<&str> for PathRef<'_> {
792 fn eq(&self, other: &&str) -> bool {
793 match_path_node(&self.0, other, |_| false)
794 }
795}
796
797impl PartialEq<String> for PathRef<'_> {
799 fn eq(&self, other: &String) -> bool {
800 match_path_node(&self.0, other, |_| false)
801 }
802}
803
804impl fmt::Display for PathRef<'_> {
805 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
806 fmt::Display::fmt(&self.0, f)
807 }
808}
809
810pub(crate) type PathNodeRef<'buf> = Arc<PathNode<'buf>>;
812
813#[derive(Clone, Debug, Default, Eq, PartialEq, Ord, PartialOrd)]
823pub(crate) enum PathNode<'buf> {
824 #[default]
826 Root,
827 Array {
829 parent: PathNodeRef<'buf>,
830 index: usize,
831 },
832 Object {
834 parent: PathNodeRef<'buf>,
835 key: RawStr<'buf>,
836 },
837}
838
839pub enum PathNodeKind {
842 Root,
844 Array,
846 Object,
848}
849
850#[derive(Clone, Debug, Eq, PartialEq, Ord, PartialOrd)]
859pub struct Path(Vec<PathPiece>);
860
861impl Path {
862 const fn root() -> Self {
864 Self(vec![])
865 }
866
867 fn from_node(path: PathNodeRef<'_>) -> Self {
869 let paths: Vec<_> = PathIter::new(path).collect();
870
871 let pieces = paths
872 .into_iter()
873 .rev()
874 .filter_map(|path_node| match *path_node {
875 PathNode::Root => None,
876 PathNode::Array { index, .. } => Some(PathPiece::Array(index)),
877 PathNode::Object { key, .. } => Some(PathPiece::Object(key.to_string())),
878 })
879 .collect();
880
881 Self(pieces)
882 }
883}
884
885impl PartialEq<&str> for Path {
887 fn eq(&self, other: &&str) -> bool {
888 match_path(self, other)
889 }
890}
891
892impl PartialEq<String> for Path {
894 fn eq(&self, other: &String) -> bool {
895 match_path(self, other)
896 }
897}
898
899impl fmt::Display for Path {
900 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
901 let iter = self.0.iter();
902
903 write!(f, "$")?;
904
905 for path in iter {
906 write!(f, ".{path}")?;
907 }
908
909 Ok(())
910 }
911}
912
913#[derive(Clone, Debug, Eq, PartialEq, Ord, PartialOrd)]
917enum PathPiece {
918 Array(usize),
920 Object(String),
922}
923
924impl fmt::Display for PathPiece {
925 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
926 match self {
927 PathPiece::Array(index) => write!(f, "{index}"),
928 PathPiece::Object(key) => write!(f, "{key}"),
929 }
930 }
931}
932
933pub struct PathComponent<'buf>(PathNodeRef<'buf>);
935
936impl PathComponent<'_> {
937 pub fn kind(&self) -> PathNodeKind {
939 match *self.0 {
940 PathNode::Root => PathNodeKind::Root,
941 PathNode::Array { .. } => PathNodeKind::Array,
942 PathNode::Object { .. } => PathNodeKind::Object,
943 }
944 }
945}
946
947impl fmt::Display for PathComponent<'_> {
948 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
949 match *self.0 {
950 PathNode::Root => f.write_str(PATH_ROOT),
951 PathNode::Array { index, .. } => write!(f, "{index}"),
952 PathNode::Object { key, .. } => write!(f, "{key}"),
953 }
954 }
955}
956
957impl fmt::Display for PathNode<'_> {
958 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
959 let paths: Vec<_> = PathIter::new(Arc::new(self.clone())).collect();
960 let mut iter = paths.into_iter().rev();
961
962 if f.alternate() {
963 for path in iter {
965 match *path {
966 PathNode::Root => f.write_str("")?,
967 PathNode::Array { .. } | PathNode::Object { .. } => f.write_str("...|")?,
968 }
969 }
970 } else {
971 if let Some(path) = iter.next() {
972 write!(f, "{}", PathComponent(path))?;
973 }
974
975 for path in iter {
976 write!(f, ".{}", PathComponent(path))?;
977 }
978 }
979 Ok(())
980 }
981}
982
983impl<'buf> PathNode<'buf> {
984 pub(crate) fn is_root(&self) -> bool {
986 matches!(self, PathNode::Root)
987 }
988
989 pub(crate) fn is_array(&self) -> bool {
991 matches!(self, PathNode::Array { .. })
992 }
993
994 pub(crate) fn as_object_key(&self) -> Option<&RawStr<'buf>> {
996 match self {
997 PathNode::Object { key, .. } => Some(key),
998 PathNode::Root | PathNode::Array { .. } => None,
999 }
1000 }
1001}
1002
1003fn match_path_node<F>(path: &PathNode<'_>, s: &str, mut skip: F) -> bool
1009where
1010 F: FnMut(&str) -> bool,
1011{
1012 let mut parts = s.rsplit(PATH_SEPARATOR);
1013 let mut paths_iter = PathIter::new(Arc::new(path.clone()));
1014
1015 loop {
1016 let node_segment = paths_iter.next();
1017 let str_segment = parts.next();
1018
1019 let (node_segment, str_segment) = match (node_segment, str_segment) {
1020 (None, None) => return true,
1022 (None, Some(_)) | (Some(_), None) => return false,
1024 (Some(a), Some(b)) => (a, b),
1026 };
1027
1028 if skip(str_segment) {
1030 continue;
1031 }
1032
1033 let yip = match *node_segment {
1034 PathNode::Root => str_segment == PATH_ROOT,
1035 PathNode::Array { index, .. } => {
1036 let Ok(b) = str_segment.parse::<usize>() else {
1037 return false;
1038 };
1039
1040 index == b
1041 }
1042 PathNode::Object { key, .. } => key.as_raw() == str_segment,
1043 };
1044
1045 if !yip {
1047 return false;
1048 }
1049 }
1050}
1051
1052fn match_path(path: &Path, s: &str) -> bool {
1054 let mut parts = s.split(PATH_SEPARATOR);
1055 let mut paths_iter = path.0.iter();
1056
1057 let Some(str_segment) = parts.next() else {
1058 return false;
1059 };
1060
1061 if str_segment != PATH_ROOT {
1064 return false;
1065 }
1066
1067 loop {
1068 let node_segment = paths_iter.next();
1069 let str_segment = parts.next();
1070
1071 let (node_segment, str_segment) = match (node_segment, str_segment) {
1072 (None, None) => return true,
1074 (None, Some(_)) | (Some(_), None) => return false,
1076 (Some(a), Some(b)) => (a, b),
1078 };
1079
1080 let yip = match node_segment {
1081 PathPiece::Array(index) => {
1082 let Ok(b) = str_segment.parse::<usize>() else {
1083 return false;
1084 };
1085
1086 *index == b
1087 }
1088 PathPiece::Object(key) => key == str_segment,
1089 };
1090
1091 if !yip {
1093 return false;
1094 }
1095 }
1096}
1097
1098impl PartialEq<&str> for PathNode<'_> {
1099 fn eq(&self, other: &&str) -> bool {
1100 match_path_node(self, other, |_| false)
1101 }
1102}
1103
1104impl PartialEq<String> for PathNode<'_> {
1105 fn eq(&self, other: &String) -> bool {
1106 match_path_node(self, other, |_| false)
1107 }
1108}
1109
1110struct PathIter<'buf> {
1112 complete: bool,
1114 path: PathNodeRef<'buf>,
1116}
1117
1118impl<'buf> PathIter<'buf> {
1119 fn new(path: PathNodeRef<'buf>) -> Self {
1121 Self {
1122 complete: false,
1123 path,
1124 }
1125 }
1126}
1127
1128impl<'buf> Iterator for PathIter<'buf> {
1129 type Item = PathNodeRef<'buf>;
1130
1131 fn next(&mut self) -> Option<Self::Item> {
1132 if self.complete {
1133 return None;
1134 }
1135
1136 match &*self.path {
1137 PathNode::Root => {
1138 self.complete = true;
1140 Some(Arc::clone(&self.path))
1141 }
1142 PathNode::Array { parent, .. } | PathNode::Object { parent, .. } => {
1143 let next = Arc::clone(&self.path);
1144 self.path = Arc::clone(parent);
1145 Some(next)
1146 }
1147 }
1148 }
1149}
1150
1151struct DisplayExpectStack<'a>(&'a [schema::Expect]);
1153
1154impl fmt::Display for DisplayExpectStack<'_> {
1155 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1156 let mut iter = self.0.iter().rev();
1157 let last = iter.next();
1158
1159 f.write_str("~")?;
1161
1162 for _ in iter {
1163 f.write_str("...~")?;
1164 }
1165
1166 if let Some(exp) = last {
1167 match exp {
1168 schema::Expect::Scalar => f.write_str("~")?,
1169 schema::Expect::Array(element) => match &**element {
1170 schema::Element::Scalar => f.write_str("~")?,
1171 schema::Element::Array(element) => write!(f, "[{element:?}]")?,
1172 schema::Element::Object(fields) => {
1173 write!(f, "[{{{:}}}])", DisplayExpectFields(&**fields))?;
1174 }
1175 },
1176 schema::Expect::Object(fields) => {
1177 write!(f, "{{{:}}}", DisplayExpectFields(&**fields))?;
1178 }
1179 schema::Expect::UnmatchedScalar => write!(f, "unmatched(scalar)")?,
1180 schema::Expect::UnmatchedArray => write!(f, "unmatched(array)")?,
1181 schema::Expect::UnmatchedObject => write!(f, "unmatched(object)")?,
1182 schema::Expect::OutOfSchema => write!(f, "no_schema")?,
1183 }
1184 }
1185
1186 Ok(())
1187 }
1188}
1189
1190struct DisplayExpectFields<'a, V>(&'a BTreeMap<&'a str, V>);
1192
1193impl<V> fmt::Display for DisplayExpectFields<'_, V> {
1194 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1195 const MAX_FIELDS: usize = 8;
1196
1197 let mut count = 0;
1198 let mut iter = self.0.keys().peekable();
1199
1200 loop {
1201 if count >= MAX_FIELDS {
1202 f.write_str("...")?;
1203 break;
1204 }
1205
1206 let Some(field) = iter.next() else {
1207 break;
1208 };
1209
1210 let Some(n) = count.checked_add(1) else {
1211 break;
1212 };
1213 count = n;
1214
1215 write!(f, "{field}")?;
1216
1217 let Some(_) = iter.peek() else {
1218 break;
1219 };
1220
1221 f.write_str(", ")?;
1222 }
1223
1224 Ok(())
1225 }
1226}
1227
1228#[derive(Debug)]
1229struct UnbalancedExpectStack;
1230
1231impl fmt::Display for UnbalancedExpectStack {
1232 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1233 f.write_str("unbalanced expectation stack")
1234 }
1235}
1236
1237impl std::error::Error for UnbalancedExpectStack {}
1238
1239pub(crate) fn parse_with_schema<'buf>(
1242 json: &'buf str,
1243 schema: &schema::Element,
1244) -> Result<ParseReport<'buf>, Error> {
1245 let parser = Parser::new(json);
1246 let mut unexpected_fields = vec![];
1247 let mut expectation_stack = vec![schema.to_expectation()];
1249
1250 for event in parser {
1251 match event? {
1252 parser::Event::Open { kind, parent_path } => {
1253 let Some(expectation) = expectation_stack.pop() else {
1256 return Err(ErrorKind::Internal(Box::new(UnbalancedExpectStack))
1257 .into_partial_error_without_token()
1258 .with_root_path());
1259 };
1260
1261 if tracing::enabled!(Level::DEBUG) {
1262 match kind {
1263 ObjectKind::Array => {
1264 trace!("{parent_path} [ {}", DisplayExpectStack(&expectation_stack));
1265 }
1266 ObjectKind::Object => trace!(
1267 "{parent_path} {{ {}",
1268 DisplayExpectStack(&expectation_stack)
1269 ),
1270 }
1271 }
1272
1273 match expectation {
1274 schema::Expect::Array(elem) => {
1275 if parent_path.is_root() {
1278 let next = match kind {
1279 ObjectKind::Array => schema::Expect::Array(elem),
1280 ObjectKind::Object => schema::Expect::UnmatchedArray,
1281 };
1282
1283 expectation_stack.push(next);
1284 trace!("{}", DisplayExpectStack(&expectation_stack));
1285 continue;
1286 }
1287
1288 if !parent_path.is_array() {
1289 expectation_stack.push(schema::Expect::UnmatchedArray);
1290 trace!("{}", DisplayExpectStack(&expectation_stack));
1291 continue;
1292 }
1293
1294 expectation_stack.push(schema::Expect::Array(Arc::clone(&elem)));
1295 expectation_stack.push(elem.to_expectation());
1297 }
1298 schema::Expect::Object(fields) => {
1299 if parent_path.is_root() {
1302 let next = match kind {
1303 ObjectKind::Array => schema::Expect::UnmatchedObject,
1304 ObjectKind::Object => schema::Expect::Object(fields),
1305 };
1306
1307 expectation_stack.push(next);
1308 trace!("{}", DisplayExpectStack(&expectation_stack));
1309 continue;
1310 }
1311 let Some(key) = parent_path.as_object_key() else {
1312 expectation_stack.push(schema::Expect::UnmatchedObject);
1313 trace!("{}", DisplayExpectStack(&expectation_stack));
1314 continue;
1315 };
1316
1317 let next = if let Some(elem) = fields.get(key.as_raw()) {
1318 open_object(kind, elem.as_ref())
1319 } else {
1320 unexpected_fields.push(parent_path);
1321 schema::Expect::OutOfSchema
1322 };
1323
1324 expectation_stack.push(schema::Expect::Object(fields));
1325 expectation_stack.push(next);
1326 }
1327 schema::Expect::OutOfSchema => {
1328 expectation_stack.push(expectation);
1336 expectation_stack.push(schema::Expect::OutOfSchema);
1337 }
1338 schema::Expect::UnmatchedArray | schema::Expect::UnmatchedObject => {
1339 expectation_stack.push(expectation);
1340 expectation_stack.push(schema::Expect::OutOfSchema);
1341 }
1342 _ => {
1343 expectation_stack.push(expectation);
1344 }
1345 }
1346
1347 trace!("{}", DisplayExpectStack(&expectation_stack));
1348 }
1349 parser::Event::Element { kind, parent_path } => {
1350 let Some(expectation) = expectation_stack.pop() else {
1353 return Err(ErrorKind::Internal(Box::new(UnbalancedExpectStack))
1354 .into_partial_error_without_token()
1355 .with_root_path());
1356 };
1357
1358 if let ValueKind::Array | ValueKind::Object = kind {
1361 if tracing::enabled!(Level::DEBUG) {
1362 match kind {
1363 ValueKind::Array => {
1364 trace!(
1365 "{parent_path} ] {}",
1366 DisplayExpectStack(&expectation_stack)
1367 );
1368 }
1369 ValueKind::Object => trace!(
1370 "{parent_path} }} {}",
1371 DisplayExpectStack(&expectation_stack)
1372 ),
1373 _ => (),
1374 }
1375 }
1376 continue;
1377 }
1378
1379 match expectation {
1380 #[expect(
1381 clippy::unreachable,
1382 reason = "The parser only emits an `Event::Complete` for a scalar object at the root"
1383 )]
1384 schema::Expect::Object(fields) => match &*parent_path {
1385 PathNode::Root => unreachable!(),
1386 PathNode::Array { .. } => {
1387 expectation_stack.push(schema::Expect::UnmatchedObject);
1388 }
1389 PathNode::Object { parent, key } => {
1390 trace!("{parent:#}.{key}");
1391
1392 if !fields.contains_key(key.as_raw()) {
1393 unexpected_fields.push(parent_path);
1394 }
1395
1396 expectation_stack.push(schema::Expect::Object(fields));
1397 }
1398 },
1399 schema::Expect::OutOfSchema => {
1400 unexpected_fields.push(parent_path);
1401 expectation_stack.push(expectation);
1402 }
1403 _ => {
1404 expectation_stack.push(expectation);
1405 }
1406 }
1407 }
1408 parser::Event::Complete(element) => {
1409 if element.value().is_scalar() {
1410 unexpected_fields.push(element.path_node());
1411 }
1412
1413 return Ok(ParseReport {
1416 element,
1417 unexpected_fields: UnexpectedFields::from_vec(unexpected_fields),
1418 });
1419 }
1420 }
1421 }
1422
1423 Err(ErrorKind::UnexpectedEOF
1424 .into_partial_error_without_token()
1425 .with_root_path())
1426}
1427
1428fn open_object(kind: ObjectKind, elem: Option<&Arc<schema::Element>>) -> schema::Expect {
1429 let Some(schema) = elem else {
1430 return schema::Expect::OutOfSchema;
1431 };
1432
1433 match (kind, &**schema) {
1434 (ObjectKind::Object | ObjectKind::Array, schema::Element::Scalar) => {
1435 schema::Expect::UnmatchedScalar
1436 }
1437 (ObjectKind::Object, schema::Element::Array(_)) => schema::Expect::UnmatchedArray,
1438 (ObjectKind::Object, schema::Element::Object(fields)) => {
1439 schema::Expect::Object(Arc::clone(fields))
1440 }
1441 (ObjectKind::Array, schema::Element::Array(element)) => {
1442 schema::Expect::Array(Arc::clone(element))
1443 }
1444 (ObjectKind::Array, schema::Element::Object(_)) => schema::Expect::UnmatchedObject,
1445 }
1446}
1447
1448#[derive(Debug)]
1451pub(crate) struct ParseReport<'buf> {
1452 pub element: Element<'buf>,
1454
1455 pub unexpected_fields: UnexpectedFields<'buf>,
1457}