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 ReasonableStr, 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 pub fn is_null(&self) -> bool {
376 self.value.is_null()
377 }
378}
379
380#[derive(Debug)]
381pub enum SourceStr<'buf> {
382 Value(RawStr<'buf>),
384
385 Field {
387 field: RawStr<'buf>,
389
390 key: &'buf str,
392
393 value: &'buf str,
395 },
396}
397
398impl fmt::Display for SourceStr<'_> {
399 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
400 match self {
401 SourceStr::Value(s) => f.write_str(s.as_raw()),
402 SourceStr::Field { field, .. } => f.write_str(field.as_raw()),
403 }
404 }
405}
406
407impl PartialEq<&str> for SourceStr<'_> {
409 fn eq(&self, other: &&str) -> bool {
410 match self {
411 SourceStr::Value(s) => s.as_raw() == *other,
412 SourceStr::Field { field, .. } => field.as_raw() == *other,
413 }
414 }
415}
416
417impl PartialEq<String> for SourceStr<'_> {
419 fn eq(&self, other: &String) -> bool {
420 self.eq(&&**other)
421 }
422}
423
424impl PartialOrd for Element<'_> {
425 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
426 Some(self.cmp(other))
427 }
428}
429
430impl Ord for Element<'_> {
431 fn cmp(&self, other: &Self) -> std::cmp::Ordering {
432 self.path_node.cmp(&other.path_node)
433 }
434}
435
436impl fmt::Display for Element<'_> {
437 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
438 write!(f, "{} = {}", self.path_node, self.value)
439 }
440}
441
442#[derive(Clone, Debug, Eq, PartialEq)]
444pub(crate) struct Field<'buf>(Element<'buf>);
445
446impl<'buf> Field<'buf> {
447 #[expect(
448 clippy::unreachable,
449 reason = "A Field is created by the parser when the type is an Object."
450 )]
451 pub(crate) fn key(&self) -> RawStr<'buf> {
452 let PathNode::Object { key, .. } = *self.0.path_node else {
453 unreachable!();
454 };
455
456 key
457 }
458
459 pub(crate) fn into_element(self) -> Element<'buf> {
461 self.0
462 }
463
464 pub(crate) fn element(&self) -> &Element<'buf> {
466 &self.0
467 }
468}
469
470#[derive(Clone, Debug, Eq, PartialEq)]
472pub(crate) enum Value<'buf> {
473 Null,
475
476 True,
478
479 False,
481
482 String(RawStr<'buf>),
484
485 Number(&'buf str),
490
491 Array(Vec<Element<'buf>>),
496
497 Object(Vec<Field<'buf>>),
503}
504
505impl<'buf> Value<'buf> {
506 pub(crate) fn kind(&self) -> ValueKind {
507 match self {
508 Value::Null => ValueKind::Null,
509 Value::True | Value::False => ValueKind::Bool,
510 Value::String(_) => ValueKind::String,
511 Value::Number(_) => ValueKind::Number,
512 Value::Array(_) => ValueKind::Array,
513 Value::Object(_) => ValueKind::Object,
514 }
515 }
516
517 pub(crate) fn is_null(&self) -> bool {
518 matches!(self, Value::Null)
519 }
520
521 pub(crate) fn is_scalar(&self) -> bool {
523 matches!(
524 self,
525 Value::Null | Value::True | Value::False | Value::String(_) | Value::Number(_)
526 )
527 }
528
529 pub(crate) fn as_array(&self) -> Option<&[Element<'buf>]> {
530 match self {
531 Value::Array(elems) => Some(elems),
532 _ => None,
533 }
534 }
535
536 pub(crate) fn as_number(&self) -> Option<&str> {
537 match self {
538 Value::Number(s) => Some(s),
539 _ => None,
540 }
541 }
542
543 pub(crate) fn to_raw_str(&self) -> Option<RawStr<'buf>> {
545 match self {
546 Value::String(s) => Some(*s),
547 _ => None,
548 }
549 }
550
551 pub(crate) fn as_object_fields(&self) -> Option<&[Field<'buf>]> {
553 match self {
554 Value::Object(fields) => Some(fields),
555 _ => None,
556 }
557 }
558}
559
560impl fmt::Display for Value<'_> {
561 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
562 match self {
563 Self::Null => write!(f, "null"),
564 Self::True => write!(f, "true"),
565 Self::False => write!(f, "false"),
566 Self::String(s) => write!(f, "{s}"),
567 Self::Number(s) => write!(f, "{s}"),
568 Self::Array(..) => f.write_str("[...]"),
569 Self::Object(..) => f.write_str("{...}"),
570 }
571 }
572}
573
574#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd)]
576pub enum ValueKind {
577 Null,
578 Bool,
579 Number,
580 String,
581 Array,
582 Object,
583}
584
585impl fmt::Display for ValueKind {
586 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
587 match self {
588 ValueKind::Null => write!(f, "null"),
589 ValueKind::Bool => write!(f, "bool"),
590 ValueKind::Number => write!(f, "number"),
591 ValueKind::String => write!(f, "string"),
592 ValueKind::Array => write!(f, "array"),
593 ValueKind::Object => write!(f, "object"),
594 }
595 }
596}
597
598#[derive(Copy, Clone, Debug, Eq, PartialEq)]
602pub(crate) enum ObjectKind {
603 Object,
604 Array,
605}
606
607pub type RawMap<'buf> = BTreeMap<RawStr<'buf>, Element<'buf>>;
608pub type RawRefMap<'a, 'buf> = BTreeMap<RawStr<'buf>, &'a Element<'buf>>;
609
610#[expect(dead_code, reason = "pending use in `tariff::lint`")]
611pub(crate) trait FieldsIntoExt<'buf> {
612 fn into_map(self) -> RawMap<'buf>;
613}
614
615pub(crate) trait FieldsAsExt<'buf> {
616 fn as_raw_map(&self) -> RawRefMap<'_, 'buf>;
617 fn find_field(&self, key: &str) -> Option<&Field<'buf>>;
618}
619
620impl<'buf> FieldsIntoExt<'buf> for Vec<Field<'buf>> {
621 fn into_map(self) -> RawMap<'buf> {
622 self.into_iter()
623 .map(|field| (field.key(), field.into_element()))
624 .collect()
625 }
626}
627
628impl<'buf> FieldsAsExt<'buf> for Vec<Field<'buf>> {
629 fn as_raw_map(&self) -> RawRefMap<'_, 'buf> {
630 self.iter()
631 .map(|field| (field.key(), field.element()))
632 .collect()
633 }
634
635 fn find_field(&self, key: &str) -> Option<&Field<'buf>> {
636 self.iter().find(|field| field.key().as_raw() == key)
637 }
638}
639
640impl<'buf> FieldsAsExt<'buf> for [Field<'buf>] {
641 fn as_raw_map(&self) -> RawRefMap<'_, 'buf> {
642 self.iter()
643 .map(|field| (field.key(), field.element()))
644 .collect()
645 }
646
647 fn find_field(&self, key: &str) -> Option<&Field<'buf>> {
648 self.iter().find(|field| field.key().as_raw() == key)
649 }
650}
651
652#[derive(Clone, Debug)]
655pub struct UnexpectedFields<'buf>(Vec<PathNodeRef<'buf>>);
656
657impl fmt::Display for UnexpectedFields<'_> {
658 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
659 if f.alternate() {
660 f.write_str("[\n")?;
662 for entry in &self.0 {
663 writeln!(f, "\t\"{entry}\",")?;
664 }
665 f.write_str("]\n")?;
666 } else {
667 f.write_char('[')?;
669 for entry in &self.0 {
670 write!(f, "{entry},")?;
671 }
672 f.write_char(']')?;
673 }
674
675 Ok(())
676 }
677}
678
679impl<'buf> UnexpectedFields<'buf> {
680 pub(crate) fn empty() -> Self {
682 Self(vec![])
683 }
684
685 pub(crate) fn from_vec(v: Vec<PathNodeRef<'buf>>) -> Self {
687 Self(v)
688 }
689
690 pub fn to_strings(&self) -> Vec<String> {
692 self.0.iter().map(ToString::to_string).collect()
693 }
694
695 pub fn into_strings(self) -> Vec<String> {
697 self.0.into_iter().map(|path| path.to_string()).collect()
698 }
699
700 pub fn is_empty(&self) -> bool {
702 self.0.is_empty()
703 }
704
705 pub fn len(&self) -> usize {
707 self.0.len()
708 }
709
710 pub fn iter<'a>(&'a self) -> UnexpectedFieldsIter<'a, 'buf> {
712 UnexpectedFieldsIter(self.0.iter())
713 }
714}
715
716impl<'buf> IntoIterator for UnexpectedFields<'buf> {
717 type Item = PathRef<'buf>;
718
719 type IntoIter = UnexpectedFieldsIntoIter<'buf>;
720
721 fn into_iter(self) -> Self::IntoIter {
722 UnexpectedFieldsIntoIter(self.0.into_iter())
723 }
724}
725
726pub struct UnexpectedFieldsIntoIter<'buf>(std::vec::IntoIter<PathNodeRef<'buf>>);
727
728impl<'buf> Iterator for UnexpectedFieldsIntoIter<'buf> {
729 type Item = PathRef<'buf>;
730
731 fn next(&mut self) -> Option<Self::Item> {
732 let path_node = self.0.next()?;
733
734 Some(PathRef(path_node))
735 }
736}
737
738impl<'a, 'buf> IntoIterator for &'a UnexpectedFields<'buf> {
739 type Item = PathRef<'buf>;
740
741 type IntoIter = UnexpectedFieldsIter<'a, 'buf>;
742
743 fn into_iter(self) -> Self::IntoIter {
744 self.iter()
745 }
746}
747
748pub struct UnexpectedFieldsIter<'a, 'buf>(std::slice::Iter<'a, PathNodeRef<'buf>>);
750
751impl<'buf> Iterator for UnexpectedFieldsIter<'_, 'buf> {
752 type Item = PathRef<'buf>;
753
754 fn next(&mut self) -> Option<Self::Item> {
755 let path_node = self.0.next()?;
756
757 Some(PathRef(Arc::clone(path_node)))
758 }
759}
760
761pub struct PathRef<'buf>(PathNodeRef<'buf>);
769
770impl fmt::Debug for PathRef<'_> {
771 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
772 write!(f, "{self}")
773 }
774}
775
776impl<'buf> PathRef<'buf> {
777 pub fn components(&self) -> PathComponents<'buf> {
779 PathComponents(PathIter::new(Arc::clone(&self.0)))
780 }
781}
782
783pub struct PathComponents<'buf>(PathIter<'buf>);
785
786impl<'buf> Iterator for PathComponents<'buf> {
787 type Item = PathComponent<'buf>;
788
789 fn next(&mut self) -> Option<Self::Item> {
790 let path_node = self.0.next()?;
791 Some(PathComponent(path_node))
792 }
793}
794
795impl PartialEq<&str> for PathRef<'_> {
797 fn eq(&self, other: &&str) -> bool {
798 match_path_node(&self.0, other, |_| false)
799 }
800}
801
802impl PartialEq<String> for PathRef<'_> {
804 fn eq(&self, other: &String) -> bool {
805 match_path_node(&self.0, other, |_| false)
806 }
807}
808
809impl fmt::Display for PathRef<'_> {
810 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
811 fmt::Display::fmt(&self.0, f)
812 }
813}
814
815pub(crate) type PathNodeRef<'buf> = Arc<PathNode<'buf>>;
817
818#[derive(Clone, Debug, Default, Eq, PartialEq, Ord, PartialOrd)]
828pub(crate) enum PathNode<'buf> {
829 #[default]
831 Root,
832 Array {
834 parent: PathNodeRef<'buf>,
835 index: usize,
836 },
837 Object {
839 parent: PathNodeRef<'buf>,
840 key: RawStr<'buf>,
841 },
842}
843
844pub enum PathNodeKind {
847 Root,
849 Array,
851 Object,
853}
854
855#[derive(Clone, Debug, Eq, PartialEq, Ord, PartialOrd)]
864pub struct Path(Vec<PathPiece>);
865
866impl Path {
867 const fn root() -> Self {
869 Self(vec![])
870 }
871
872 fn from_node(path: PathNodeRef<'_>) -> Self {
874 let paths: Vec<_> = PathIter::new(path).collect();
875
876 let pieces = paths
877 .into_iter()
878 .rev()
879 .filter_map(|path_node| match *path_node {
880 PathNode::Root => None,
881 PathNode::Array { index, .. } => Some(PathPiece::Array(index)),
882 PathNode::Object { key, .. } => Some(PathPiece::Object(key.to_string())),
883 })
884 .collect();
885
886 Self(pieces)
887 }
888}
889
890impl PartialEq<&str> for Path {
892 fn eq(&self, other: &&str) -> bool {
893 match_path(self, other)
894 }
895}
896
897impl PartialEq<String> for Path {
899 fn eq(&self, other: &String) -> bool {
900 match_path(self, other)
901 }
902}
903
904impl fmt::Display for Path {
905 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
906 let iter = self.0.iter();
907
908 write!(f, "$")?;
909
910 for path in iter {
911 write!(f, ".{path}")?;
912 }
913
914 Ok(())
915 }
916}
917
918#[derive(Clone, Debug, Eq, PartialEq, Ord, PartialOrd)]
922enum PathPiece {
923 Array(usize),
925 Object(String),
927}
928
929impl fmt::Display for PathPiece {
930 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
931 match self {
932 PathPiece::Array(index) => write!(f, "{index}"),
933 PathPiece::Object(key) => write!(f, "{key}"),
934 }
935 }
936}
937
938pub struct PathComponent<'buf>(PathNodeRef<'buf>);
940
941impl PathComponent<'_> {
942 pub fn kind(&self) -> PathNodeKind {
944 match *self.0 {
945 PathNode::Root => PathNodeKind::Root,
946 PathNode::Array { .. } => PathNodeKind::Array,
947 PathNode::Object { .. } => PathNodeKind::Object,
948 }
949 }
950}
951
952impl fmt::Display for PathComponent<'_> {
953 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
954 match *self.0 {
955 PathNode::Root => f.write_str(PATH_ROOT),
956 PathNode::Array { index, .. } => write!(f, "{index}"),
957 PathNode::Object { key, .. } => write!(f, "{key}"),
958 }
959 }
960}
961
962impl fmt::Display for PathNode<'_> {
963 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
964 let paths: Vec<_> = PathIter::new(Arc::new(self.clone())).collect();
965 let mut iter = paths.into_iter().rev();
966
967 if f.alternate() {
968 for path in iter {
970 match *path {
971 PathNode::Root => f.write_str("")?,
972 PathNode::Array { .. } | PathNode::Object { .. } => f.write_str("...|")?,
973 }
974 }
975 } else {
976 if let Some(path) = iter.next() {
977 write!(f, "{}", PathComponent(path))?;
978 }
979
980 for path in iter {
981 write!(f, ".{}", PathComponent(path))?;
982 }
983 }
984 Ok(())
985 }
986}
987
988impl<'buf> PathNode<'buf> {
989 pub(crate) fn is_root(&self) -> bool {
991 matches!(self, PathNode::Root)
992 }
993
994 pub(crate) fn is_array(&self) -> bool {
996 matches!(self, PathNode::Array { .. })
997 }
998
999 pub(crate) fn as_object_key(&self) -> Option<&RawStr<'buf>> {
1001 match self {
1002 PathNode::Object { key, .. } => Some(key),
1003 PathNode::Root | PathNode::Array { .. } => None,
1004 }
1005 }
1006}
1007
1008fn match_path_node<F>(path: &PathNode<'_>, s: &str, mut skip: F) -> bool
1014where
1015 F: FnMut(&str) -> bool,
1016{
1017 let mut parts = s.rsplit(PATH_SEPARATOR);
1018 let mut paths_iter = PathIter::new(Arc::new(path.clone()));
1019
1020 loop {
1021 let node_segment = paths_iter.next();
1022 let str_segment = parts.next();
1023
1024 let (node_segment, str_segment) = match (node_segment, str_segment) {
1025 (None, None) => return true,
1027 (None, Some(_)) | (Some(_), None) => return false,
1029 (Some(a), Some(b)) => (a, b),
1031 };
1032
1033 if skip(str_segment) {
1035 continue;
1036 }
1037
1038 let yip = match *node_segment {
1039 PathNode::Root => str_segment == PATH_ROOT,
1040 PathNode::Array { index, .. } => {
1041 let Ok(b) = str_segment.parse::<usize>() else {
1042 return false;
1043 };
1044
1045 index == b
1046 }
1047 PathNode::Object { key, .. } => key.as_raw() == str_segment,
1048 };
1049
1050 if !yip {
1052 return false;
1053 }
1054 }
1055}
1056
1057fn match_path(path: &Path, s: &str) -> bool {
1059 let mut parts = s.split(PATH_SEPARATOR);
1060 let mut paths_iter = path.0.iter();
1061
1062 let Some(str_segment) = parts.next() else {
1063 return false;
1064 };
1065
1066 if str_segment != PATH_ROOT {
1069 return false;
1070 }
1071
1072 loop {
1073 let node_segment = paths_iter.next();
1074 let str_segment = parts.next();
1075
1076 let (node_segment, str_segment) = match (node_segment, str_segment) {
1077 (None, None) => return true,
1079 (None, Some(_)) | (Some(_), None) => return false,
1081 (Some(a), Some(b)) => (a, b),
1083 };
1084
1085 let yip = match node_segment {
1086 PathPiece::Array(index) => {
1087 let Ok(b) = str_segment.parse::<usize>() else {
1088 return false;
1089 };
1090
1091 *index == b
1092 }
1093 PathPiece::Object(key) => key == str_segment,
1094 };
1095
1096 if !yip {
1098 return false;
1099 }
1100 }
1101}
1102
1103impl PartialEq<&str> for PathNode<'_> {
1104 fn eq(&self, other: &&str) -> bool {
1105 match_path_node(self, other, |_| false)
1106 }
1107}
1108
1109impl PartialEq<String> for PathNode<'_> {
1110 fn eq(&self, other: &String) -> bool {
1111 match_path_node(self, other, |_| false)
1112 }
1113}
1114
1115struct PathIter<'buf> {
1117 complete: bool,
1119 path: PathNodeRef<'buf>,
1121}
1122
1123impl<'buf> PathIter<'buf> {
1124 fn new(path: PathNodeRef<'buf>) -> Self {
1126 Self {
1127 complete: false,
1128 path,
1129 }
1130 }
1131}
1132
1133impl<'buf> Iterator for PathIter<'buf> {
1134 type Item = PathNodeRef<'buf>;
1135
1136 fn next(&mut self) -> Option<Self::Item> {
1137 if self.complete {
1138 return None;
1139 }
1140
1141 match &*self.path {
1142 PathNode::Root => {
1143 self.complete = true;
1145 Some(Arc::clone(&self.path))
1146 }
1147 PathNode::Array { parent, .. } | PathNode::Object { parent, .. } => {
1148 let next = Arc::clone(&self.path);
1149 self.path = Arc::clone(parent);
1150 Some(next)
1151 }
1152 }
1153 }
1154}
1155
1156struct DisplayExpectStack<'a>(&'a [schema::Expect]);
1158
1159impl fmt::Display for DisplayExpectStack<'_> {
1160 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1161 let mut iter = self.0.iter().rev();
1162 let last = iter.next();
1163
1164 f.write_str("~")?;
1166
1167 for _ in iter {
1168 f.write_str("...~")?;
1169 }
1170
1171 if let Some(exp) = last {
1172 match exp {
1173 schema::Expect::Scalar => f.write_str("~")?,
1174 schema::Expect::Array(element) => match &**element {
1175 schema::Element::Scalar => f.write_str("~")?,
1176 schema::Element::Array(element) => write!(f, "[{element:?}]")?,
1177 schema::Element::Object(fields) => {
1178 write!(f, "[{{{:}}}])", DisplayExpectFields(&**fields))?;
1179 }
1180 },
1181 schema::Expect::Object(fields) => {
1182 write!(f, "{{{:}}}", DisplayExpectFields(&**fields))?;
1183 }
1184 schema::Expect::UnmatchedScalar => write!(f, "unmatched(scalar)")?,
1185 schema::Expect::UnmatchedArray => write!(f, "unmatched(array)")?,
1186 schema::Expect::UnmatchedObject => write!(f, "unmatched(object)")?,
1187 schema::Expect::OutOfSchema => write!(f, "no_schema")?,
1188 }
1189 }
1190
1191 Ok(())
1192 }
1193}
1194
1195struct DisplayExpectFields<'a, V>(&'a BTreeMap<&'a str, V>);
1197
1198impl<V> fmt::Display for DisplayExpectFields<'_, V> {
1199 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1200 const MAX_FIELDS: usize = 8;
1201
1202 let mut count = 0;
1203 let mut iter = self.0.keys().peekable();
1204
1205 loop {
1206 if count >= MAX_FIELDS {
1207 f.write_str("...")?;
1208 break;
1209 }
1210
1211 let Some(field) = iter.next() else {
1212 break;
1213 };
1214
1215 let Some(n) = count.checked_add(1) else {
1216 break;
1217 };
1218 count = n;
1219
1220 write!(f, "{field}")?;
1221
1222 let Some(_) = iter.peek() else {
1223 break;
1224 };
1225
1226 f.write_str(", ")?;
1227 }
1228
1229 Ok(())
1230 }
1231}
1232
1233#[derive(Debug)]
1234struct UnbalancedExpectStack;
1235
1236impl fmt::Display for UnbalancedExpectStack {
1237 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1238 f.write_str("unbalanced expectation stack")
1239 }
1240}
1241
1242impl std::error::Error for UnbalancedExpectStack {}
1243
1244pub(crate) fn parse_with_schema<'buf>(
1247 json: ReasonableStr<'buf>,
1248 schema: &schema::Element,
1249) -> Result<ParseReport<'buf>, Error> {
1250 let parser = Parser::new(json.into_inner());
1251 let mut unexpected_fields = vec![];
1252 let mut expectation_stack = vec![schema.to_expectation()];
1254
1255 for event in parser {
1256 match event? {
1257 parser::Event::Open { kind, parent_path } => {
1258 let Some(expectation) = expectation_stack.pop() else {
1261 return Err(ErrorKind::Internal(Box::new(UnbalancedExpectStack))
1262 .into_partial_error_without_token()
1263 .with_root_path());
1264 };
1265
1266 if tracing::enabled!(Level::DEBUG) {
1267 match kind {
1268 ObjectKind::Array => {
1269 trace!("{parent_path} [ {}", DisplayExpectStack(&expectation_stack));
1270 }
1271 ObjectKind::Object => trace!(
1272 "{parent_path} {{ {}",
1273 DisplayExpectStack(&expectation_stack)
1274 ),
1275 }
1276 }
1277
1278 match expectation {
1279 schema::Expect::Array(elem) => {
1280 if parent_path.is_root() {
1283 let next = match kind {
1284 ObjectKind::Array => schema::Expect::Array(elem),
1285 ObjectKind::Object => schema::Expect::UnmatchedArray,
1286 };
1287
1288 expectation_stack.push(next);
1289 trace!("{}", DisplayExpectStack(&expectation_stack));
1290 continue;
1291 }
1292
1293 if !parent_path.is_array() {
1294 expectation_stack.push(schema::Expect::UnmatchedArray);
1295 trace!("{}", DisplayExpectStack(&expectation_stack));
1296 continue;
1297 }
1298
1299 expectation_stack.push(schema::Expect::Array(Arc::clone(&elem)));
1300 expectation_stack.push(elem.to_expectation());
1302 }
1303 schema::Expect::Object(fields) => {
1304 if parent_path.is_root() {
1307 let next = match kind {
1308 ObjectKind::Array => schema::Expect::UnmatchedObject,
1309 ObjectKind::Object => schema::Expect::Object(fields),
1310 };
1311
1312 expectation_stack.push(next);
1313 trace!("{}", DisplayExpectStack(&expectation_stack));
1314 continue;
1315 }
1316 let Some(key) = parent_path.as_object_key() else {
1317 expectation_stack.push(schema::Expect::UnmatchedObject);
1318 trace!("{}", DisplayExpectStack(&expectation_stack));
1319 continue;
1320 };
1321
1322 let next = if let Some(elem) = fields.get(key.as_raw()) {
1323 open_object(kind, elem.as_ref())
1324 } else {
1325 unexpected_fields.push(parent_path);
1326 schema::Expect::OutOfSchema
1327 };
1328
1329 expectation_stack.push(schema::Expect::Object(fields));
1330 expectation_stack.push(next);
1331 }
1332 schema::Expect::OutOfSchema => {
1333 expectation_stack.push(expectation);
1341 expectation_stack.push(schema::Expect::OutOfSchema);
1342 }
1343 schema::Expect::UnmatchedArray | schema::Expect::UnmatchedObject => {
1344 expectation_stack.push(expectation);
1345 expectation_stack.push(schema::Expect::OutOfSchema);
1346 }
1347 _ => {
1348 expectation_stack.push(expectation);
1349 }
1350 }
1351
1352 trace!("{}", DisplayExpectStack(&expectation_stack));
1353 }
1354 parser::Event::Element { kind, parent_path } => {
1355 let Some(expectation) = expectation_stack.pop() else {
1358 return Err(ErrorKind::Internal(Box::new(UnbalancedExpectStack))
1359 .into_partial_error_without_token()
1360 .with_root_path());
1361 };
1362
1363 if let ValueKind::Array | ValueKind::Object = kind {
1366 if tracing::enabled!(Level::DEBUG) {
1367 match kind {
1368 ValueKind::Array => {
1369 trace!(
1370 "{parent_path} ] {}",
1371 DisplayExpectStack(&expectation_stack)
1372 );
1373 }
1374 ValueKind::Object => trace!(
1375 "{parent_path} }} {}",
1376 DisplayExpectStack(&expectation_stack)
1377 ),
1378 _ => (),
1379 }
1380 }
1381 continue;
1382 }
1383
1384 match expectation {
1385 #[expect(
1386 clippy::unreachable,
1387 reason = "The parser only emits an `Event::Complete` for a scalar object at the root"
1388 )]
1389 schema::Expect::Object(fields) => match &*parent_path {
1390 PathNode::Root => unreachable!(),
1391 PathNode::Array { .. } => {
1392 expectation_stack.push(schema::Expect::UnmatchedObject);
1393 }
1394 PathNode::Object { parent, key } => {
1395 trace!("{parent:#}.{key}");
1396
1397 if !fields.contains_key(key.as_raw()) {
1398 unexpected_fields.push(parent_path);
1399 }
1400
1401 expectation_stack.push(schema::Expect::Object(fields));
1402 }
1403 },
1404 schema::Expect::OutOfSchema => {
1405 unexpected_fields.push(parent_path);
1406 expectation_stack.push(expectation);
1407 }
1408 _ => {
1409 expectation_stack.push(expectation);
1410 }
1411 }
1412 }
1413 parser::Event::Complete(element) => {
1414 if element.value().is_scalar() {
1415 unexpected_fields.push(element.path_node());
1416 }
1417
1418 return Ok(ParseReport {
1421 element,
1422 unexpected_fields: UnexpectedFields::from_vec(unexpected_fields),
1423 });
1424 }
1425 }
1426 }
1427
1428 Err(ErrorKind::UnexpectedEOF
1429 .into_partial_error_without_token()
1430 .with_root_path())
1431}
1432
1433fn open_object(kind: ObjectKind, elem: Option<&Arc<schema::Element>>) -> schema::Expect {
1434 let Some(schema) = elem else {
1435 return schema::Expect::OutOfSchema;
1436 };
1437
1438 match (kind, &**schema) {
1439 (ObjectKind::Object | ObjectKind::Array, schema::Element::Scalar) => {
1440 schema::Expect::UnmatchedScalar
1441 }
1442 (ObjectKind::Object, schema::Element::Array(_)) => schema::Expect::UnmatchedArray,
1443 (ObjectKind::Object, schema::Element::Object(fields)) => {
1444 schema::Expect::Object(Arc::clone(fields))
1445 }
1446 (ObjectKind::Array, schema::Element::Array(element)) => {
1447 schema::Expect::Array(Arc::clone(element))
1448 }
1449 (ObjectKind::Array, schema::Element::Object(_)) => schema::Expect::UnmatchedObject,
1450 }
1451}
1452
1453#[derive(Debug)]
1456pub(crate) struct ParseReport<'buf> {
1457 pub element: Element<'buf>,
1459
1460 pub unexpected_fields: UnexpectedFields<'buf>,
1462}