1#[cfg(test)]
4pub(crate) mod test;
5
6#[cfg(test)]
7mod test_path;
8
9#[cfg(test)]
10mod test_parse_with_schema;
11
12#[cfg(test)]
13mod test_source_json;
14
15#[cfg(test)]
16mod test_path_node;
17
18#[cfg(test)]
19mod test_path_node_matches_str;
20
21#[cfg(test)]
22mod test_path_matches_glob;
23
24pub mod decode;
25pub mod parser;
26pub(crate) mod schema;
27pub(crate) mod walk;
28pub mod write;
29
30use std::{
31 collections::BTreeMap,
32 fmt::{self, Write as _},
33 sync::Arc,
34};
35
36use tracing::{trace, Level};
37
38use crate::{
39 warning::{self, IntoCaveat},
40 ReasonableStr, Verdict,
41};
42use parser::ErrorKind;
43use parser::{Parser, Span};
44
45#[doc(inline)]
46pub use parser::{line_col, Error, ErrorReport, LineCol};
47pub(crate) use parser::{parse, RawStr};
48
49const PATH_SEPARATOR: char = '.';
50const PATH_ROOT: &str = "$";
51
52#[doc(hidden)]
55#[macro_export]
56macro_rules! required_field_or_bail {
57 ($elem:expr, $fields:expr, $field_name:literal, $warnings:expr) => {
58 match $fields.get($field_name) {
59 Some(field_elem) => field_elem,
60 None => {
61 return $warnings.bail(
62 Warning::FieldRequired {
63 field_name: $field_name.into(),
64 },
65 $elem,
66 );
67 }
68 }
69 };
70}
71
72#[doc(hidden)]
75#[macro_export]
76macro_rules! required_field {
77 ($elem:expr, $fields:expr, $field_name:literal, $warnings:expr) => {{
78 let field = $fields.get($field_name);
79
80 if field.is_none() {
81 $warnings.insert(
82 Warning::FieldRequired {
83 field_name: $field_name.into(),
84 },
85 $elem,
86 );
87 }
88
89 field
90 }};
91}
92
93#[doc(hidden)]
96#[macro_export]
97macro_rules! expect_object_or_bail {
98 ($elem:expr, $warnings:expr) => {
99 match $elem.as_object_fields() {
100 Some(fields) => fields,
101 None => {
102 return $warnings.bail(
103 Warning::FieldInvalidType {
104 expected_type: json::ValueKind::Object,
105 },
106 $elem,
107 );
108 }
109 }
110 };
111}
112
113#[doc(hidden)]
116#[macro_export]
117macro_rules! expect_array_or_bail {
118 ($elem:expr, $warnings:expr) => {
119 match $elem.as_array() {
120 Some(fields) => fields,
121 None => {
122 return $warnings.bail(
123 Warning::FieldInvalidType {
124 expected_type: json::ValueKind::Array,
125 },
126 $elem,
127 );
128 }
129 }
130 };
131}
132
133#[doc(hidden)]
137#[macro_export]
138macro_rules! parse_required_or_bail {
139 ($elem:expr, $fields:expr, $elem_name:literal, $target:ty, $warnings:expr) => {{
140 #[expect(clippy::allow_attributes, reason = "The allow attribute is needed here as the callers scope determines if the imports are used or not")]
141 #[allow(
142 unused,
143 reason = "The macro uses the import but maybe the outside scope does too."
144 )]
145 use $crate::json::FromJson;
146 use $crate::warning::GatherWarnings as _;
147
148 let elem = $crate::required_field_or_bail!($elem, $fields, $elem_name, $warnings);
149 <$target as FromJson>::from_json(elem)?.gather_warnings_into(&mut $warnings)
150 }};
151}
152
153#[doc(hidden)]
157#[macro_export]
158macro_rules! parse_required {
159 ($elem:expr, $fields:expr, $elem_name:literal, $target:ty, $warnings:expr) => {{
160 #[expect(
161 clippy::allow_attributes,
162 reason = "The allow attribute is needed here as the callers scope determines if the imports are used or not"
163 )]
164 #[allow(
165 unused,
166 reason = "The macro uses the import but maybe the outside scope does too."
167 )]
168 use $crate::json::FromJson;
169 use $crate::warning::GatherWarnings as _;
170
171 let elem = $crate::required_field!($elem, $fields, $elem_name, $warnings);
172
173 if let Some(elem) = elem {
174 let value =
175 <$target as FromJson>::from_json(elem)?.gather_warnings_into(&mut $warnings);
176 Some(value)
177 } else {
178 None
179 }
180 }};
181}
182
183#[doc(hidden)]
186#[macro_export]
187macro_rules! parse_nullable_or_bail {
188 ($fields:expr, $elem_name:literal, $target:ty, $warnings:expr) => {{
189 #[expect(
190 clippy::allow_attributes,
191 reason = "The allow attribute is needed here as the callers scope determines if the imports are used or not"
192 )]
193 #[allow(
194 unused,
195 reason = "The macro uses the import but maybe the outside scope does too."
196 )]
197 use $crate::json::FromJson as _;
198 use $crate::warning::GatherWarnings as _;
199
200 match $fields.get($elem_name) {
201 Some(elem) => Option::<$target>::from_json(elem)?.gather_warnings_into(&mut $warnings),
202 None => None,
203 }
204 }};
205}
206
207pub(crate) trait FromJson<'buf>: Sized {
209 type Warning: crate::Warning;
210
211 fn from_json(elem: &Element<'buf>) -> Verdict<Self, Self::Warning>;
213}
214
215impl<'buf, T> FromJson<'buf> for Option<T>
219where
220 T: FromJson<'buf> + IntoCaveat,
221{
222 type Warning = T::Warning;
223
224 fn from_json(elem: &Element<'buf>) -> Verdict<Self, Self::Warning> {
225 let value = elem.as_value();
226
227 if value.is_null() {
228 Ok(None.into_caveat(warning::Set::new()))
229 } else {
230 let v = T::from_json(elem)?;
231 Ok(v.map(Some))
232 }
233 }
234}
235
236#[derive(Clone, Debug, Eq, PartialEq)]
240pub struct Element<'buf> {
241 id: ElemId,
243
244 path_node: PathNodeRef<'buf>,
246
247 span: Span,
251
252 value: Value<'buf>,
254}
255
256#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq, Ord, PartialOrd)]
260pub(crate) struct ElemId(usize);
261
262impl fmt::Display for ElemId {
263 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
264 fmt::Display::fmt(&self.0, f)
265 }
266}
267
268impl<'buf> Element<'buf> {
269 fn new(id: ElemId, path: PathNodeRef<'buf>, span: Span, value: Value<'buf>) -> Element<'buf> {
271 Element {
272 id,
273 path_node: path,
274 span,
275 value,
276 }
277 }
278
279 pub(crate) const fn id(&self) -> ElemId {
281 self.id
282 }
283
284 pub fn path(&self) -> PathRef<'buf> {
286 PathRef(self.path_node())
287 }
288
289 pub(crate) fn path_node(&self) -> PathNodeRef<'buf> {
291 Arc::clone(&self.path_node)
292 }
293
294 pub fn span(&self) -> Span {
296 self.span
297 }
298
299 pub fn source_json(&self, source_json: &'buf str) -> SourceStr<'buf> {
313 if let PathNode::Object { key, .. } = *self.path_node {
314 let span = Span {
316 start: key.span().start,
317 end: self.span.end,
318 };
319 let field_str = &source_json
320 .get(span.start..span.end)
321 .expect("The disconnection between the source JSON and the `Element` will be fixed in a future PR");
322 let field = RawStr::from_str(field_str, span);
323 let (key, value) = field_str
324 .split_once(':')
325 .expect("An objects field always contains a delimiting `:`");
326
327 SourceStr::Field { field, key, value }
328 } else {
329 let span = self.span;
330 let s = source_json
331 .get(span.start..span.end)
332 .expect("The disconnection between the source JSON and the `Element` will be fixed in a future PR");
333 SourceStr::Value(RawStr::from_str(s, span))
334 }
335 }
336
337 pub fn source_json_value(&self, source_json: &'buf str) -> &'buf str {
350 source_json
351 .get(self.span.start..self.span.end)
352 .expect("The disconnection between the source JSON and the `Element` will be fixed in a future PR")
353 }
354
355 pub(crate) fn value(&self) -> &Value<'buf> {
357 &self.value
358 }
359
360 pub(crate) fn as_value(&self) -> &Value<'buf> {
362 &self.value
363 }
364
365 pub(crate) fn to_raw_str(&self) -> Option<RawStr<'buf>> {
367 self.value.to_raw_str()
368 }
369
370 pub(crate) fn as_object_fields(&self) -> Option<&[Field<'buf>]> {
372 self.value.as_object_fields()
373 }
374
375 pub(crate) fn as_array(&self) -> Option<&[Element<'buf>]> {
376 self.value.as_array()
377 }
378
379 pub fn as_number_str(&self) -> Option<&str> {
380 self.value.as_number()
381 }
382
383 pub fn is_null(&self) -> bool {
385 self.value.is_null()
386 }
387}
388
389#[derive(Debug)]
390pub enum SourceStr<'buf> {
391 Value(RawStr<'buf>),
393
394 Field {
396 field: RawStr<'buf>,
398
399 key: &'buf str,
401
402 value: &'buf str,
404 },
405}
406
407impl fmt::Display for SourceStr<'_> {
408 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
409 match self {
410 SourceStr::Value(s) => f.write_str(s.as_raw()),
411 SourceStr::Field { field, .. } => f.write_str(field.as_raw()),
412 }
413 }
414}
415
416impl PartialEq<&str> for SourceStr<'_> {
418 fn eq(&self, other: &&str) -> bool {
419 match self {
420 SourceStr::Value(s) => s.as_raw() == *other,
421 SourceStr::Field { field, .. } => field.as_raw() == *other,
422 }
423 }
424}
425
426impl PartialEq<String> for SourceStr<'_> {
428 fn eq(&self, other: &String) -> bool {
429 self.eq(&&**other)
430 }
431}
432
433impl PartialOrd for Element<'_> {
434 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
435 Some(self.cmp(other))
436 }
437}
438
439impl Ord for Element<'_> {
440 fn cmp(&self, other: &Self) -> std::cmp::Ordering {
441 self.path_node.cmp(&other.path_node)
442 }
443}
444
445impl fmt::Display for Element<'_> {
446 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
447 write!(f, "{} = {}", self.path_node, self.value)
448 }
449}
450
451#[derive(Clone, Debug, Eq, PartialEq)]
453pub(crate) struct Field<'buf>(Element<'buf>);
454
455impl<'buf> Field<'buf> {
456 pub(crate) fn key(&self) -> RawStr<'buf> {
457 let PathNode::Object { key, .. } = *self.0.path_node else {
458 unreachable!("A Field is created by the parser when the type is an Object.");
459 };
460
461 key
462 }
463
464 pub(crate) fn into_element(self) -> Element<'buf> {
466 self.0
467 }
468
469 pub(crate) fn element(&self) -> &Element<'buf> {
471 &self.0
472 }
473}
474
475#[derive(Clone, Debug, Eq, PartialEq)]
477pub(crate) enum Value<'buf> {
478 Null,
480
481 True,
483
484 False,
486
487 String(RawStr<'buf>),
489
490 Number(&'buf str),
495
496 Array(Vec<Element<'buf>>),
501
502 Object(Vec<Field<'buf>>),
508}
509
510impl<'buf> Value<'buf> {
511 pub(crate) fn kind(&self) -> ValueKind {
512 match self {
513 Value::Null => ValueKind::Null,
514 Value::True | Value::False => ValueKind::Bool,
515 Value::String(_) => ValueKind::String,
516 Value::Number(_) => ValueKind::Number,
517 Value::Array(_) => ValueKind::Array,
518 Value::Object(_) => ValueKind::Object,
519 }
520 }
521
522 pub(crate) fn is_null(&self) -> bool {
523 matches!(self, Value::Null)
524 }
525
526 pub(crate) fn is_scalar(&self) -> bool {
528 matches!(
529 self,
530 Value::Null | Value::True | Value::False | Value::String(_) | Value::Number(_)
531 )
532 }
533
534 pub(crate) fn as_array(&self) -> Option<&[Element<'buf>]> {
535 if let Value::Array(elems) = self {
536 Some(elems)
537 } else {
538 None
539 }
540 }
541
542 pub(crate) fn as_number(&self) -> Option<&str> {
543 if let Value::Number(s) = self {
544 Some(s)
545 } else {
546 None
547 }
548 }
549
550 pub(crate) fn to_raw_str(&self) -> Option<RawStr<'buf>> {
552 if let Value::String(s) = self {
553 Some(*s)
554 } else {
555 None
556 }
557 }
558
559 pub(crate) fn as_object_fields(&self) -> Option<&[Field<'buf>]> {
561 if let Value::Object(fields) = self {
562 Some(fields)
563 } else {
564 None
565 }
566 }
567}
568
569impl fmt::Display for Value<'_> {
570 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
571 match self {
572 Self::Null => write!(f, "null"),
573 Self::True => write!(f, "true"),
574 Self::False => write!(f, "false"),
575 Self::String(s) => write!(f, "{s}"),
576 Self::Number(s) => write!(f, "{s}"),
577 Self::Array(..) => f.write_str("[...]"),
578 Self::Object(..) => f.write_str("{...}"),
579 }
580 }
581}
582
583#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd)]
585pub enum ValueKind {
586 Null,
587 Bool,
588 Number,
589 String,
590 Array,
591 Object,
592}
593
594impl fmt::Display for ValueKind {
595 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
596 match self {
597 ValueKind::Null => write!(f, "null"),
598 ValueKind::Bool => write!(f, "bool"),
599 ValueKind::Number => write!(f, "number"),
600 ValueKind::String => write!(f, "string"),
601 ValueKind::Array => write!(f, "array"),
602 ValueKind::Object => write!(f, "object"),
603 }
604 }
605}
606
607#[derive(Copy, Clone, Debug, Eq, PartialEq)]
611pub(crate) enum ObjectKind {
612 Object,
613 Array,
614}
615
616pub type RawMap<'buf> = BTreeMap<RawStr<'buf>, Element<'buf>>;
617pub type RawRefMap<'a, 'buf> = BTreeMap<RawStr<'buf>, &'a Element<'buf>>;
618
619#[expect(dead_code, reason = "pending use in `tariff::lint`")]
620pub(crate) trait FieldsIntoExt<'buf> {
621 fn into_map(self) -> RawMap<'buf>;
622}
623
624pub(crate) trait FieldsAsExt<'buf> {
625 fn as_raw_map(&self) -> RawRefMap<'_, 'buf>;
626 fn find_field(&self, key: &str) -> Option<&Field<'buf>>;
627}
628
629impl<'buf> FieldsIntoExt<'buf> for Vec<Field<'buf>> {
630 fn into_map(self) -> RawMap<'buf> {
631 self.into_iter()
632 .map(|field| (field.key(), field.into_element()))
633 .collect()
634 }
635}
636
637impl<'buf> FieldsAsExt<'buf> for Vec<Field<'buf>> {
638 fn as_raw_map(&self) -> RawRefMap<'_, 'buf> {
639 self.iter()
640 .map(|field| (field.key(), field.element()))
641 .collect()
642 }
643
644 fn find_field(&self, key: &str) -> Option<&Field<'buf>> {
645 self.iter().find(|field| field.key().as_raw() == key)
646 }
647}
648
649impl<'buf> FieldsAsExt<'buf> for [Field<'buf>] {
650 fn as_raw_map(&self) -> RawRefMap<'_, 'buf> {
651 self.iter()
652 .map(|field| (field.key(), field.element()))
653 .collect()
654 }
655
656 fn find_field(&self, key: &str) -> Option<&Field<'buf>> {
657 self.iter().find(|field| field.key().as_raw() == key)
658 }
659}
660
661#[derive(Clone, Debug)]
664pub struct UnexpectedFields<'buf>(Vec<PathNodeRef<'buf>>);
665
666impl fmt::Display for UnexpectedFields<'_> {
667 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
668 if f.alternate() {
669 f.write_str("[\n")?;
671 for entry in &self.0 {
672 writeln!(f, "\t\"{entry}\",")?;
673 }
674 f.write_str("]\n")?;
675 } else {
676 f.write_char('[')?;
678 for entry in &self.0 {
679 write!(f, "{entry},")?;
680 }
681 f.write_char(']')?;
682 }
683
684 Ok(())
685 }
686}
687
688impl<'buf> UnexpectedFields<'buf> {
689 pub(crate) fn empty() -> Self {
691 Self(vec![])
692 }
693
694 pub(crate) fn from_vec(v: Vec<PathNodeRef<'buf>>) -> Self {
696 Self(v)
697 }
698
699 pub fn to_strings(&self) -> Vec<String> {
701 self.0.iter().map(ToString::to_string).collect()
702 }
703
704 pub fn into_strings(self) -> Vec<String> {
706 self.0.into_iter().map(|path| path.to_string()).collect()
707 }
708
709 pub fn is_empty(&self) -> bool {
711 self.0.is_empty()
712 }
713
714 pub fn len(&self) -> usize {
716 self.0.len()
717 }
718
719 pub fn iter<'a>(&'a self) -> UnexpectedFieldsIter<'a, 'buf> {
721 UnexpectedFieldsIter(self.0.iter())
722 }
723}
724
725impl<'buf> IntoIterator for UnexpectedFields<'buf> {
726 type Item = PathRef<'buf>;
727
728 type IntoIter = UnexpectedFieldsIntoIter<'buf>;
729
730 fn into_iter(self) -> Self::IntoIter {
731 UnexpectedFieldsIntoIter(self.0.into_iter())
732 }
733}
734
735pub struct UnexpectedFieldsIntoIter<'buf>(std::vec::IntoIter<PathNodeRef<'buf>>);
736
737impl<'buf> Iterator for UnexpectedFieldsIntoIter<'buf> {
738 type Item = PathRef<'buf>;
739
740 fn next(&mut self) -> Option<Self::Item> {
741 let path_node = self.0.next()?;
742
743 Some(PathRef(path_node))
744 }
745}
746
747impl<'a, 'buf> IntoIterator for &'a UnexpectedFields<'buf> {
748 type Item = PathRef<'buf>;
749
750 type IntoIter = UnexpectedFieldsIter<'a, 'buf>;
751
752 fn into_iter(self) -> Self::IntoIter {
753 self.iter()
754 }
755}
756
757pub struct UnexpectedFieldsIter<'a, 'buf>(std::slice::Iter<'a, PathNodeRef<'buf>>);
759
760impl<'buf> Iterator for UnexpectedFieldsIter<'_, 'buf> {
761 type Item = PathRef<'buf>;
762
763 fn next(&mut self) -> Option<Self::Item> {
764 let path_node = self.0.next()?;
765
766 Some(PathRef(Arc::clone(path_node)))
767 }
768}
769
770pub struct PathRef<'buf>(PathNodeRef<'buf>);
778
779impl fmt::Debug for PathRef<'_> {
780 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
781 write!(f, "{self}")
782 }
783}
784
785impl<'buf> PathRef<'buf> {
786 pub fn components(&self) -> PathComponents<'buf> {
788 PathComponents(PathIter::new(Arc::clone(&self.0)))
789 }
790}
791
792pub struct PathComponents<'buf>(PathIter<'buf>);
794
795impl<'buf> Iterator for PathComponents<'buf> {
796 type Item = PathComponent<'buf>;
797
798 fn next(&mut self) -> Option<Self::Item> {
799 let path_node = self.0.next()?;
800 Some(PathComponent(path_node))
801 }
802}
803
804impl PartialEq<&str> for PathRef<'_> {
806 fn eq(&self, other: &&str) -> bool {
807 match_path_node(&self.0, other, |_| false)
808 }
809}
810
811impl PartialEq<String> for PathRef<'_> {
813 fn eq(&self, other: &String) -> bool {
814 match_path_node(&self.0, other, |_| false)
815 }
816}
817
818impl fmt::Display for PathRef<'_> {
819 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
820 fmt::Display::fmt(&self.0, f)
821 }
822}
823
824pub(crate) type PathNodeRef<'buf> = Arc<PathNode<'buf>>;
826
827#[derive(Clone, Debug, Default, Eq, PartialEq, Ord, PartialOrd)]
837pub(crate) enum PathNode<'buf> {
838 #[default]
840 Root,
841 Array {
843 parent: PathNodeRef<'buf>,
844 index: usize,
845 },
846 Object {
848 parent: PathNodeRef<'buf>,
849 key: RawStr<'buf>,
850 },
851}
852
853pub enum PathNodeKind {
856 Root,
858 Array,
860 Object,
862}
863
864#[derive(Clone, Debug, Eq, PartialEq, Ord, PartialOrd)]
873pub struct Path(Vec<PathPiece>);
874
875impl Path {
876 const fn root() -> Self {
878 Self(vec![])
879 }
880
881 fn from_node(path: PathNodeRef<'_>) -> Self {
883 let paths: Vec<_> = PathIter::new(path).collect();
884
885 let pieces = paths
886 .into_iter()
887 .rev()
888 .filter_map(|path_node| match *path_node {
889 PathNode::Root => None,
890 PathNode::Array { index, .. } => Some(PathPiece::Array(index)),
891 PathNode::Object { key, .. } => Some(PathPiece::Object(key.to_string())),
892 })
893 .collect();
894
895 Self(pieces)
896 }
897}
898
899impl PartialEq<&str> for Path {
901 fn eq(&self, other: &&str) -> bool {
902 match_path(self, other)
903 }
904}
905
906impl PartialEq<String> for Path {
908 fn eq(&self, other: &String) -> bool {
909 match_path(self, other)
910 }
911}
912
913impl fmt::Display for Path {
914 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
915 let iter = self.0.iter();
916
917 write!(f, "$")?;
918
919 for path in iter {
920 write!(f, ".{path}")?;
921 }
922
923 Ok(())
924 }
925}
926
927#[derive(Clone, Debug, Eq, PartialEq, Ord, PartialOrd)]
931enum PathPiece {
932 Array(usize),
934 Object(String),
936}
937
938impl fmt::Display for PathPiece {
939 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
940 match self {
941 PathPiece::Array(index) => write!(f, "{index}"),
942 PathPiece::Object(key) => write!(f, "{key}"),
943 }
944 }
945}
946
947pub struct PathComponent<'buf>(PathNodeRef<'buf>);
949
950impl PathComponent<'_> {
951 pub fn kind(&self) -> PathNodeKind {
953 match *self.0 {
954 PathNode::Root => PathNodeKind::Root,
955 PathNode::Array { .. } => PathNodeKind::Array,
956 PathNode::Object { .. } => PathNodeKind::Object,
957 }
958 }
959}
960
961impl fmt::Display for PathComponent<'_> {
962 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
963 match *self.0 {
964 PathNode::Root => f.write_str(PATH_ROOT),
965 PathNode::Array { index, .. } => write!(f, "{index}"),
966 PathNode::Object { key, .. } => write!(f, "{key}"),
967 }
968 }
969}
970
971impl fmt::Display for PathNode<'_> {
972 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
973 let paths: Vec<_> = PathIter::new(Arc::new(self.clone())).collect();
974 let mut iter = paths.into_iter().rev();
975
976 if f.alternate() {
977 for path in iter {
979 match *path {
980 PathNode::Root => f.write_str("")?,
981 PathNode::Array { .. } | PathNode::Object { .. } => f.write_str("...|")?,
982 }
983 }
984 } else {
985 if let Some(path) = iter.next() {
986 write!(f, "{}", PathComponent(path))?;
987 }
988
989 for path in iter {
990 write!(f, ".{}", PathComponent(path))?;
991 }
992 }
993 Ok(())
994 }
995}
996
997impl<'buf> PathNode<'buf> {
998 pub(crate) fn is_root(&self) -> bool {
1000 matches!(self, PathNode::Root)
1001 }
1002
1003 pub(crate) fn is_array(&self) -> bool {
1005 matches!(self, PathNode::Array { .. })
1006 }
1007
1008 pub(crate) fn as_object_key(&self) -> Option<&RawStr<'buf>> {
1010 match self {
1011 PathNode::Object { key, .. } => Some(key),
1012 PathNode::Root | PathNode::Array { .. } => None,
1013 }
1014 }
1015}
1016
1017fn match_path_node<F>(path: &PathNode<'_>, s: &str, mut skip: F) -> bool
1023where
1024 F: FnMut(&str) -> bool,
1025{
1026 let mut parts = s.rsplit(PATH_SEPARATOR);
1027 let mut paths_iter = PathIter::new(Arc::new(path.clone()));
1028
1029 loop {
1030 let node_segment = paths_iter.next();
1031 let str_segment = parts.next();
1032
1033 let (node_segment, str_segment) = match (node_segment, str_segment) {
1034 (None, None) => return true,
1036 (None, Some(_)) | (Some(_), None) => return false,
1038 (Some(a), Some(b)) => (a, b),
1040 };
1041
1042 if skip(str_segment) {
1044 continue;
1045 }
1046
1047 let yip = match *node_segment {
1048 PathNode::Root => str_segment == PATH_ROOT,
1049 PathNode::Array { index, .. } => {
1050 let Ok(b) = str_segment.parse::<usize>() else {
1051 return false;
1052 };
1053
1054 index == b
1055 }
1056 PathNode::Object { key, .. } => key.as_raw() == str_segment,
1057 };
1058
1059 if !yip {
1061 return false;
1062 }
1063 }
1064}
1065
1066fn match_path(path: &Path, s: &str) -> bool {
1068 let mut parts = s.split(PATH_SEPARATOR);
1069 let mut paths_iter = path.0.iter();
1070
1071 let Some(str_segment) = parts.next() else {
1072 return false;
1073 };
1074
1075 if str_segment != PATH_ROOT {
1078 return false;
1079 }
1080
1081 loop {
1082 let node_segment = paths_iter.next();
1083 let str_segment = parts.next();
1084
1085 let (node_segment, str_segment) = match (node_segment, str_segment) {
1086 (None, None) => return true,
1088 (None, Some(_)) | (Some(_), None) => return false,
1090 (Some(a), Some(b)) => (a, b),
1092 };
1093
1094 let yip = match node_segment {
1095 PathPiece::Array(index) => {
1096 let Ok(b) = str_segment.parse::<usize>() else {
1097 return false;
1098 };
1099
1100 *index == b
1101 }
1102 PathPiece::Object(key) => key == str_segment,
1103 };
1104
1105 if !yip {
1107 return false;
1108 }
1109 }
1110}
1111
1112impl PartialEq<&str> for PathNode<'_> {
1113 fn eq(&self, other: &&str) -> bool {
1114 match_path_node(self, other, |_| false)
1115 }
1116}
1117
1118impl PartialEq<String> for PathNode<'_> {
1119 fn eq(&self, other: &String) -> bool {
1120 match_path_node(self, other, |_| false)
1121 }
1122}
1123
1124struct PathIter<'buf> {
1126 complete: bool,
1128 path: PathNodeRef<'buf>,
1130}
1131
1132impl<'buf> PathIter<'buf> {
1133 fn new(path: PathNodeRef<'buf>) -> Self {
1135 Self {
1136 complete: false,
1137 path,
1138 }
1139 }
1140}
1141
1142impl<'buf> Iterator for PathIter<'buf> {
1143 type Item = PathNodeRef<'buf>;
1144
1145 fn next(&mut self) -> Option<Self::Item> {
1146 if self.complete {
1147 return None;
1148 }
1149
1150 match &*self.path {
1151 PathNode::Root => {
1152 self.complete = true;
1154 Some(Arc::clone(&self.path))
1155 }
1156 PathNode::Array { parent, .. } | PathNode::Object { parent, .. } => {
1157 let next = Arc::clone(&self.path);
1158 self.path = Arc::clone(parent);
1159 Some(next)
1160 }
1161 }
1162 }
1163}
1164
1165struct DisplayExpectStack<'a>(&'a [schema::Expect]);
1167
1168impl fmt::Display for DisplayExpectStack<'_> {
1169 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1170 let mut iter = self.0.iter().rev();
1171 let last = iter.next();
1172
1173 f.write_str("~")?;
1175
1176 for _ in iter {
1177 f.write_str("...~")?;
1178 }
1179
1180 if let Some(exp) = last {
1181 match exp {
1182 schema::Expect::Scalar => f.write_str("~")?,
1183 schema::Expect::Array(element) => match &**element {
1184 schema::Element::Scalar => f.write_str("~")?,
1185 schema::Element::Array(element) => write!(f, "[{element:?}]")?,
1186 schema::Element::Object(fields) => {
1187 write!(f, "[{{{:}}}])", DisplayExpectFields(&**fields))?;
1188 }
1189 },
1190 schema::Expect::Object(fields) => {
1191 write!(f, "{{{:}}}", DisplayExpectFields(&**fields))?;
1192 }
1193 schema::Expect::UnmatchedScalar => write!(f, "unmatched(scalar)")?,
1194 schema::Expect::UnmatchedArray => write!(f, "unmatched(array)")?,
1195 schema::Expect::UnmatchedObject => write!(f, "unmatched(object)")?,
1196 schema::Expect::OutOfSchema => write!(f, "no_schema")?,
1197 }
1198 }
1199
1200 Ok(())
1201 }
1202}
1203
1204struct DisplayExpectFields<'a, V>(&'a BTreeMap<&'a str, V>);
1206
1207impl<V> fmt::Display for DisplayExpectFields<'_, V> {
1208 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1209 const MAX_FIELDS: usize = 8;
1210
1211 let mut count = 0;
1212 let mut iter = self.0.keys().peekable();
1213
1214 loop {
1215 if count >= MAX_FIELDS {
1216 f.write_str("...")?;
1217 break;
1218 }
1219
1220 let Some(field) = iter.next() else {
1221 break;
1222 };
1223
1224 let Some(n) = count.checked_add(1) else {
1225 break;
1226 };
1227 count = n;
1228
1229 write!(f, "{field}")?;
1230
1231 let Some(_) = iter.peek() else {
1232 break;
1233 };
1234
1235 f.write_str(", ")?;
1236 }
1237
1238 Ok(())
1239 }
1240}
1241
1242#[derive(Debug)]
1243struct UnbalancedExpectStack;
1244
1245impl fmt::Display for UnbalancedExpectStack {
1246 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1247 f.write_str("unbalanced expectation stack")
1248 }
1249}
1250
1251impl std::error::Error for UnbalancedExpectStack {}
1252
1253#[expect(
1256 clippy::cognitive_complexity,
1257 reason = "Lifetimes make splitting this function more effort than it's worth"
1258)]
1259pub(crate) fn parse_with_schema<'buf>(
1260 json: ReasonableStr<'buf>,
1261 schema: &schema::Element,
1262) -> Result<ParseReport<'buf>, Error> {
1263 let parser = Parser::new(json.into_inner());
1264 let mut unexpected_fields = vec![];
1265 let mut expectation_stack = vec![schema.to_expectation()];
1267
1268 for event in parser {
1269 match event? {
1270 parser::Event::Open { kind, parent_path } => {
1271 let Some(expectation) = expectation_stack.pop() else {
1274 return Err(ErrorKind::Internal(Box::new(UnbalancedExpectStack))
1275 .into_partial_error_without_token()
1276 .with_root_path());
1277 };
1278
1279 if tracing::enabled!(Level::DEBUG) {
1280 match kind {
1281 ObjectKind::Array => {
1282 trace!("{parent_path} [ {}", DisplayExpectStack(&expectation_stack));
1283 }
1284 ObjectKind::Object => trace!(
1285 "{parent_path} {{ {}",
1286 DisplayExpectStack(&expectation_stack)
1287 ),
1288 }
1289 }
1290
1291 match expectation {
1292 schema::Expect::Array(elem) => {
1293 if parent_path.is_root() {
1296 let next = match kind {
1297 ObjectKind::Array => schema::Expect::Array(elem),
1298 ObjectKind::Object => schema::Expect::UnmatchedArray,
1299 };
1300
1301 expectation_stack.push(next);
1302 trace!("{}", DisplayExpectStack(&expectation_stack));
1303 continue;
1304 }
1305
1306 if !parent_path.is_array() {
1307 expectation_stack.push(schema::Expect::UnmatchedArray);
1308 trace!("{}", DisplayExpectStack(&expectation_stack));
1309 continue;
1310 }
1311
1312 expectation_stack.push(schema::Expect::Array(Arc::clone(&elem)));
1313 expectation_stack.push(elem.to_expectation());
1315 }
1316 schema::Expect::Object(fields) => {
1317 if parent_path.is_root() {
1320 let next = match kind {
1321 ObjectKind::Array => schema::Expect::UnmatchedObject,
1322 ObjectKind::Object => schema::Expect::Object(fields),
1323 };
1324
1325 expectation_stack.push(next);
1326 trace!("{}", DisplayExpectStack(&expectation_stack));
1327 continue;
1328 }
1329 let Some(key) = parent_path.as_object_key() else {
1330 expectation_stack.push(schema::Expect::UnmatchedObject);
1331 trace!("{}", DisplayExpectStack(&expectation_stack));
1332 continue;
1333 };
1334
1335 let next = if let Some(elem) = fields.get(key.as_raw()) {
1336 open_object(kind, elem.as_ref())
1337 } else {
1338 unexpected_fields.push(parent_path);
1339 schema::Expect::OutOfSchema
1340 };
1341
1342 expectation_stack.push(schema::Expect::Object(fields));
1343 expectation_stack.push(next);
1344 }
1345 schema::Expect::OutOfSchema => {
1346 expectation_stack.push(expectation);
1354 expectation_stack.push(schema::Expect::OutOfSchema);
1355 }
1356 schema::Expect::UnmatchedArray | schema::Expect::UnmatchedObject => {
1357 expectation_stack.push(expectation);
1358 expectation_stack.push(schema::Expect::OutOfSchema);
1359 }
1360 schema::Expect::Scalar | schema::Expect::UnmatchedScalar => {
1361 expectation_stack.push(expectation);
1362 }
1363 }
1364
1365 trace!("{}", DisplayExpectStack(&expectation_stack));
1366 }
1367 parser::Event::Element { kind, parent_path } => {
1368 let Some(expectation) = expectation_stack.pop() else {
1371 return Err(ErrorKind::Internal(Box::new(UnbalancedExpectStack))
1372 .into_partial_error_without_token()
1373 .with_root_path());
1374 };
1375
1376 if let ValueKind::Array | ValueKind::Object = kind {
1379 if tracing::enabled!(Level::DEBUG) {
1380 match kind {
1381 ValueKind::Array => {
1382 trace!(
1383 "{parent_path} ] {}",
1384 DisplayExpectStack(&expectation_stack)
1385 );
1386 }
1387 ValueKind::Object => trace!(
1388 "{parent_path} }} {}",
1389 DisplayExpectStack(&expectation_stack)
1390 ),
1391 ValueKind::Null
1392 | ValueKind::Bool
1393 | ValueKind::Number
1394 | ValueKind::String => (),
1395 }
1396 }
1397 continue;
1398 }
1399
1400 match expectation {
1401 schema::Expect::Object(fields) => match &*parent_path {
1402 PathNode::Root => unreachable!("The parser only emits an `Event::Complete` for a scalar object at the root"),
1403 PathNode::Array { .. } => {
1404 expectation_stack.push(schema::Expect::UnmatchedObject);
1405 }
1406 PathNode::Object { parent, key } => {
1407 trace!("{parent:#}.{key}");
1408
1409 if !fields.contains_key(key.as_raw()) {
1410 unexpected_fields.push(parent_path);
1411 }
1412
1413 expectation_stack.push(schema::Expect::Object(fields));
1414 }
1415 },
1416 schema::Expect::OutOfSchema => {
1417 unexpected_fields.push(parent_path);
1418 expectation_stack.push(expectation);
1419 }
1420 schema::Expect::UnmatchedArray | schema::Expect::Array(_) | schema::Expect::Scalar | schema::Expect::UnmatchedScalar | schema::Expect::UnmatchedObject => {
1421 expectation_stack.push(expectation);
1422 }
1423 }
1424 }
1425 parser::Event::Complete(element) => {
1426 if element.value().is_scalar() {
1427 unexpected_fields.push(element.path_node());
1428 }
1429
1430 return Ok(ParseReport {
1433 element,
1434 unexpected_fields: UnexpectedFields::from_vec(unexpected_fields),
1435 });
1436 }
1437 }
1438 }
1439
1440 Err(ErrorKind::UnexpectedEOF
1441 .into_partial_error_without_token()
1442 .with_root_path())
1443}
1444
1445fn open_object(kind: ObjectKind, elem: Option<&Arc<schema::Element>>) -> schema::Expect {
1446 let Some(schema) = elem else {
1447 return schema::Expect::OutOfSchema;
1448 };
1449
1450 match (kind, &**schema) {
1451 (ObjectKind::Object | ObjectKind::Array, schema::Element::Scalar) => {
1452 schema::Expect::UnmatchedScalar
1453 }
1454 (ObjectKind::Object, schema::Element::Array(_)) => schema::Expect::UnmatchedArray,
1455 (ObjectKind::Object, schema::Element::Object(fields)) => {
1456 schema::Expect::Object(Arc::clone(fields))
1457 }
1458 (ObjectKind::Array, schema::Element::Array(element)) => {
1459 schema::Expect::Array(Arc::clone(element))
1460 }
1461 (ObjectKind::Array, schema::Element::Object(_)) => schema::Expect::UnmatchedObject,
1462 }
1463}
1464
1465#[derive(Debug)]
1468pub(crate) struct ParseReport<'buf> {
1469 pub element: Element<'buf>,
1471
1472 pub unexpected_fields: UnexpectedFields<'buf>,
1474}