Skip to main content

ocpi_tariffs/
json.rs

1//! Types and functions for parsing JSON in a flexible and pedantic manner.
2#[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/// Return the `json::Element` If the given field exists(`Some`).
52/// Otherwise, add a `Warning::FieldRequired` to the set of `Warning`s and return them as an `Err`.
53#[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/// Return the `json::Element` If the given field exists(`Some`).
72/// Otherwise, add a `Warning::FieldRequired` to the set of `Warning`s and return them as an `Err`.
73#[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/// Return the `Field`s of the given `json::Element` if it's a JSON object.
93/// Otherwise, add a `Warning::FieldInvalidType` to the set of `Warning`s and return then as an `Err`.
94#[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/// Return the `json::Element`s of the given `json::Element` if it's a JSON array.
113/// Otherwise, add a `Warning::FieldInvalidType` to the set of `Warning`s and return then as an `Err`.
114#[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/// Get a field by name and fail if it doesn't exist.
133///
134/// Convert the value of the field to the `$target` type.
135#[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/// Get a field by name and return `None` if it doesn't exist.
152///
153/// Convert the value of the field to the `$target` type.
154#[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/// Get an optional field by name and convert the field value to the `$target` type using the
178/// blanket impl `Option<$target>` that can handle `null` JSON values.
179#[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
197/// A trait for converting `Element`s to Rust types.
198pub(crate) trait FromJson<'buf>: Sized {
199    type Warning: crate::Warning;
200
201    /// Convert the given `Element` to `Self`.
202    fn from_json(elem: &Element<'buf>) -> Verdict<Self, Self::Warning>;
203}
204
205/// Implement a `null` aware variant of all types that implement `FromJson`.
206///
207/// If the value of the `json::Element` is `null` then return a `None`.
208impl<'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/// A JSON [`Element`] composed of a `Path` and it's [`Value`].
227///
228/// The `Span` is included so that the [`Element`]'s source `&str` can be acquired from the source JSON if needed.
229#[derive(Clone, Debug, Eq, PartialEq)]
230pub struct Element<'buf> {
231    /// Used to reference the Element from `Warning`s.
232    id: ElemId,
233
234    /// The `Path` to this [`Element`].
235    path_node: PathNodeRef<'buf>,
236
237    /// The `Span` of this [`Element`].
238    ///
239    /// The `Span` defines the range of bytes that delimits this JSON [`Element`].
240    span: Span,
241
242    /// The `Value` of this [`Element`].
243    value: Value<'buf>,
244}
245
246/// A simple integer index used to ID the given [`Element`] within a JSON file.
247///
248/// The Id is unique until `usize::MAX` [`Element`]s are parsed.
249#[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    /// Create a new `Element`.
260    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    /// Return the unique Id for this `Element`.
270    pub(crate) const fn id(&self) -> ElemId {
271        self.id
272    }
273
274    /// Return the `Path` to this `Element`.
275    pub fn path(&self) -> PathRef<'buf> {
276        PathRef(self.path_node())
277    }
278
279    /// Return the `PathNode` to this `Element`.
280    pub(crate) fn path_node(&self) -> PathNodeRef<'buf> {
281        Arc::clone(&self.path_node)
282    }
283
284    /// Return the `Span` of the `Element`'s `&str` is the source JSON.
285    pub fn span(&self) -> Span {
286        self.span
287    }
288
289    /// Return the source JSON `&str` of the entire Object field if the `Element` is an Object.
290    /// Otherwise, return the span of the [`Value`].
291    ///
292    /// In the case of an array like `["one", "two"]`, calling this method on the second `Element`
293    /// will return `"two"`.
294    ///
295    /// In the case of an object like `{"one": 1, "two": 2}`, calling this method on the second
296    /// `Element` will return `"\"two\": 2"`.
297    ///
298    /// # Panics
299    ///
300    /// If a source JSON is used that this `Element` didn't not originate from there is a chance
301    /// that this function will panic.
302    pub fn source_json(&self, source_json: &'buf str) -> SourceStr<'buf> {
303        if let PathNode::Object { key, .. } = *self.path_node {
304            // The span of an objects field starts from the start of the key...
305            let span = Span {
306                start: key.span().start,
307                // ... and ends at the end of the value.
308                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    /// Return the source JSON `&str` for the [`Value`].
329    ///
330    /// In the case of an array like `["one", "two"]`, calling this method on the second `Element`
331    /// will return `"two"`.
332    ///
333    /// In the case of an object like `{"one": 1, "two": 2}`, calling this method on the second
334    /// `Element` will return `"2"`.
335    ///
336    /// # Panics
337    ///
338    /// If a source JSON is used that this `Element` didn't not originate from there is a chance
339    /// that this function will panic.
340    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    /// Return the `Value` of the `Element`.
347    pub(crate) fn value(&self) -> &Value<'buf> {
348        &self.value
349    }
350
351    /// Return the `&Value`.
352    pub(crate) fn as_value(&self) -> &Value<'buf> {
353        &self.value
354    }
355
356    /// Return `Some(&str)` if the `Value` is a `String`.
357    pub(crate) fn to_raw_str(&self) -> Option<RawStr<'buf>> {
358        self.value.to_raw_str()
359    }
360
361    /// Return `Some(&[Field])` if the `Value` is a `Object`.
362    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    /// Return true if the `Element`s `Value` is null.
375    pub fn is_null(&self) -> bool {
376        self.value.is_null()
377    }
378}
379
380#[derive(Debug)]
381pub enum SourceStr<'buf> {
382    /// The source `&str` of the given [`Value`].
383    Value(RawStr<'buf>),
384
385    /// The key-value pair of the given [`Element`] where the [`PathNode`] is referring to an object.
386    Field {
387        /// The entire field as a `&str`. This is the `&str` from the beginning of the key to the end of the value.
388        field: RawStr<'buf>,
389
390        /// The key excluding the separating `:`.
391        key: &'buf str,
392
393        /// The [`Value`] as `&str`.
394        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
407/// The `SourceStr` can be compared with other strings just like a `String`.
408impl 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
417/// The `SourceStr` can be compared with other strings just like a `String`.
418impl 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/// A JSON `Object`'s field that upholds the invariant that the `Element`'s `Path` is as `Object`.
443#[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    /// Consume the `Field` and return the inner `Element`.
460    pub(crate) fn into_element(self) -> Element<'buf> {
461        self.0
462    }
463
464    /// Consume the `Field` and return the inner `Element`.
465    pub(crate) fn element(&self) -> &Element<'buf> {
466        &self.0
467    }
468}
469
470/// A JSON `Value` that borrows it's content from the source JSON `&str`.
471#[derive(Clone, Debug, Eq, PartialEq)]
472pub(crate) enum Value<'buf> {
473    /// A `"null"` value.
474    Null,
475
476    /// A `"true"` value.
477    True,
478
479    /// A `"false"` value.
480    False,
481
482    /// The value of the `String` has the quotes trimmed.
483    String(RawStr<'buf>),
484
485    /// A JSON `Number` in string format.
486    ///
487    /// The string is not guaranteed to be a valid number. Only that it's not a `null`, `bool` or `string` value.
488    /// Convert the string into the number format you want.
489    Number(&'buf str),
490
491    /// A JSON `Array` parsed into a `Vec` of `Elements`.
492    ///
493    /// The inner `Element`'s path also encodes the index.
494    /// E.g. `$.elements.2`: This path refers to third OCPI tariff element.
495    Array(Vec<Element<'buf>>),
496
497    /// A JSON `Object` where each of the fields are parsed into a `Vec` of `Elements`.
498    ///
499    /// The inner `Element`'s path encodes the fields key.
500    /// E.g. `$.elements.2.restrictions` This path refers to the `restrictions` `Object`
501    /// of the third OCPI tariff element.
502    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    /// Return true if the `Value` can't contain child elements.
522    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    /// Return `Some(&str)` if the `Value` is a `String`.
544    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    /// Return `Some(&[Field])` if the `Value` is a `Object`.
552    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/// A light-weight type identity for a JSON `Value`'s content.
575#[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/// Used to distinguish the type of compound object.
599///
600/// This is used to track which type of object an `Element` is in when parsing.
601#[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/// A collection of paths that were unexpected according to the schema used while parsing the JSON
653/// for an OCPI object.
654#[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            // Print each path on a newline.
661            f.write_str("[\n")?;
662            for entry in &self.0 {
663                writeln!(f, "\t\"{entry}\",")?;
664            }
665            f.write_str("]\n")?;
666        } else {
667            // Print all paths on a single line.
668            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    /// Create an empty `UnexpectedFields` collection.
681    pub(crate) fn empty() -> Self {
682        Self(vec![])
683    }
684
685    /// Create a collection of `UnexpectedFields` from a `Vec`
686    pub(crate) fn from_vec(v: Vec<PathNodeRef<'buf>>) -> Self {
687        Self(v)
688    }
689
690    /// Return the field paths as a `Vec` of `String`s.
691    pub fn to_strings(&self) -> Vec<String> {
692        self.0.iter().map(ToString::to_string).collect()
693    }
694
695    /// Return the field paths as a `Vec` of `String`s.
696    pub fn into_strings(self) -> Vec<String> {
697        self.0.into_iter().map(|path| path.to_string()).collect()
698    }
699
700    /// Return true if the list of unexpected fields is empty.
701    pub fn is_empty(&self) -> bool {
702        self.0.is_empty()
703    }
704
705    /// Return the number of unexpected fields.
706    pub fn len(&self) -> usize {
707        self.0.len()
708    }
709
710    /// Return an Iterator over the unexpected fields.
711    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
748/// An `Iterator` over each unexpected field as a `PathRef`.
749pub 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
761/// A path to a JSON `Element` where the path components are borrowed from the source JSON `&str`.
762///
763/// The Display impl outputs strings like:
764///
765/// - `$` The root is represented by a dollar.
766/// - `$.object_key` Dots separate the path elements.
767/// - `$.object_key.2` Arrays are represented as integers.
768pub 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    /// Return an [`Iterator`] over the components of this path.
778    pub fn components(&self) -> PathComponents<'buf> {
779        PathComponents(PathIter::new(Arc::clone(&self.0)))
780    }
781}
782
783/// An [`Iterator`] over the components of a path.
784pub 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
795/// The `PathRef` can be compared with other strings just like a `String`.
796impl PartialEq<&str> for PathRef<'_> {
797    fn eq(&self, other: &&str) -> bool {
798        match_path_node(&self.0, other, |_| false)
799    }
800}
801
802/// The `PathRef` can be compared with other strings just like a `String`.
803impl 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
815/// The path to a JSON `Element`.
816pub(crate) type PathNodeRef<'buf> = Arc<PathNode<'buf>>;
817
818/// A single node of a complete path.
819///
820/// Path's are structured as a linked list from the leaf of the path back to the root through the parents.
821///
822/// The Display impl of the `Path` outputs strings like:
823///
824/// - `$` The root is represented by a dollar.
825/// - `$.object_key` Dots separate the path elements.
826/// - `$.object_key.2` Arrays are represented as integers.
827#[derive(Clone, Debug, Default, Eq, PartialEq, Ord, PartialOrd)]
828pub(crate) enum PathNode<'buf> {
829    /// The root of the JSON `Element` tree.
830    #[default]
831    Root,
832    /// An `Array` element referenced by index.
833    Array {
834        parent: PathNodeRef<'buf>,
835        index: usize,
836    },
837    /// An `Object` field referenced be key value.
838    Object {
839        parent: PathNodeRef<'buf>,
840        key: RawStr<'buf>,
841    },
842}
843
844/// A lightweight enum used to indicate the kind of component being visited when using the
845/// [`PathComponents`] [`Iterator`].
846pub enum PathNodeKind {
847    /// The root of the JSON `Element` tree.
848    Root,
849    /// An `Array` element referenced by index.
850    Array,
851    /// An `Object` field referenced be key value.
852    Object,
853}
854
855/// A path to a JSON `Element` where the path components are heap allocated and so do not require
856/// a lifetime back to the source JSON `&str`.
857///
858/// The Display impl outputs strings like:
859///
860/// - `$` The root is represented by a dollar.
861/// - `$.object_key` Dots separate the path elements.
862/// - `$.object_key.2` Arrays are represented as integers.
863#[derive(Clone, Debug, Eq, PartialEq, Ord, PartialOrd)]
864pub struct Path(Vec<PathPiece>);
865
866impl Path {
867    /// Create a root `Path`.
868    const fn root() -> Self {
869        Self(vec![])
870    }
871
872    /// Create an `Path` by iterating over a [`PathNode`].
873    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
890/// The `Path` can be compared with other strings just like a `String`.
891impl PartialEq<&str> for Path {
892    fn eq(&self, other: &&str) -> bool {
893        match_path(self, other)
894    }
895}
896
897/// The `Path` can be compared with other strings just like a `String`.
898impl 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/// A piece/component of a [`Path`].
919///
920/// The `PathComponent` name is already taken and this type is private.
921#[derive(Clone, Debug, Eq, PartialEq, Ord, PartialOrd)]
922enum PathPiece {
923    /// An `Array` element referenced by index.
924    Array(usize),
925    /// An `Object` field referenced be key value.
926    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
938/// A single component of a [`PathRef`].
939pub struct PathComponent<'buf>(PathNodeRef<'buf>);
940
941impl PathComponent<'_> {
942    /// Return the kind of component this is.
943    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            // Print out each path element as a debugging tab-stop.
969            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    /// Returns true if the `Path` refers to the root.
990    pub(crate) fn is_root(&self) -> bool {
991        matches!(self, PathNode::Root)
992    }
993
994    /// Returns true if the `Path` refers to an `Array`.
995    pub(crate) fn is_array(&self) -> bool {
996        matches!(self, PathNode::Array { .. })
997    }
998
999    /// Return a key as `Some(&str)` if the `Path` refers to an `Object`.
1000    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
1008/// Return true if the given `PathNode` matches the given `&str`.
1009///
1010/// If the `skip` function returns true, that path component is skipped.
1011/// The `skip` function allows this single function to implement comparisons between `PathNode` and `&str`;
1012/// and comparisons between `PathNode` and `PathGlob`.
1013fn 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            // If we have exhausted both iterators then the `&str` is equal to the path.
1026            (None, None) => return true,
1027            // If either of the iterators are a different size, then they don't match.
1028            (None, Some(_)) | (Some(_), None) => return false,
1029            // If both iterators have another item, continue on to try match them.
1030            (Some(a), Some(b)) => (a, b),
1031        };
1032
1033        // If the skip function says to skip a path segment, then continue to the next segment.
1034        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        // Return false on the first mismatch.
1051        if !yip {
1052            return false;
1053        }
1054    }
1055}
1056
1057/// Return true if the given `Path` matches the given `&str`.
1058fn 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    // The root path segment is not explicitly stored in a `Path` so we just match the first
1067    // `str` segment to the expected `$` nomenclature.
1068    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            // If we have exhausted both iterators then the `&str` is equal to the path.
1078            (None, None) => return true,
1079            // If either of the iterators are a different size, then they don't match.
1080            (None, Some(_)) | (Some(_), None) => return false,
1081            // If both iterators have another item, continue on to try match them.
1082            (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        // Return false on the first mismatch.
1097        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
1115/// Traverse a `Path` from the leaf to the root.
1116struct PathIter<'buf> {
1117    /// The root has been reached.
1118    complete: bool,
1119    /// The current path node to introspect when `Iterator::next` is called.
1120    path: PathNodeRef<'buf>,
1121}
1122
1123impl<'buf> PathIter<'buf> {
1124    /// Create a new `PathIter` from a leaf node.
1125    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                // The iteration is complete once we've arrived at the root node.
1144                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
1156/// Display the expectation stack for debugging
1157struct 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        // Use the `~` to represent a schema stack.
1165        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
1195/// Display the fields of a schema expect stack level.
1196struct 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
1244/// Parse the JSON into a [`ParseReport`] checking the parsed [`Element`]s names against the given
1245/// [`schema`] and reporting fields that are unexpected in the [`ParseReport::unexpected_fields`].
1246pub(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    // The current node of the schema is the last element of this `Vec`.
1253    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                // Take the schema expectation off the stack.
1259                // This is simpler than taking a `&mut` to the last element.
1260                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 the opening element is at the root we only care if the element
1281                        // is an array or not.
1282                        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                        // Each array element should match this expectation
1301                        expectation_stack.push(elem.to_expectation());
1302                    }
1303                    schema::Expect::Object(fields) => {
1304                        // If the opening element is at the root there is no path to inspect.
1305                        // We only care if the element is an object or not.
1306                        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                        // If we're already outside of the schema we put that back on the stack
1334                        // and add a new one for the object that just opened.
1335                        //
1336                        // We need to track the object level even though the schema expectations
1337                        // have been exhausted, as we'll pop these placeholder `OutOfSchema`s
1338                        // off the stack when the object has closed so we land on the correct
1339                        // schema again.
1340                        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                // Take the schema expectation off the stack.
1356                // This is simpler than taking a `&mut` to the last element.
1357                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                // An `Element` of kind `Array` or `Object` means the `Element` is closed
1364                // and has completed construction. The expectation can remain off the stack.
1365                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                // Parsing the JSON is complete.
1419                // Return the `Element` and the unexpected fields collected during parsing
1420                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/// The output of the `parse_with_schema` function where the parsed JSON `Element` is returned
1454/// along with a list of fields that the schema did not define.
1455#[derive(Debug)]
1456pub(crate) struct ParseReport<'buf> {
1457    /// The root JSON [`Element`].
1458    pub element: Element<'buf>,
1459
1460    /// A list of fields that were not expected: The schema did not define them.
1461    pub unexpected_fields: UnexpectedFields<'buf>,
1462}