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    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/// Return the contents of the given `json::Element` as a `Cow<str>` if it's a JSON string.
133/// Otherwise, add a `Warning::FieldInvalidType` to the set of `Warning`s and return then as an `Err`.
134///
135/// Note: All escapes are decoded and this process may produce warnings.
136#[doc(hidden)]
137#[macro_export]
138macro_rules! expect_string_or_bail {
139    ($elem:expr, $warnings:expr) => {{
140        use $crate::warning::GatherWarnings as _;
141
142        match $elem.as_raw_str() {
143            Some(s) => s.decode_escapes($elem).gather_warnings_into(&mut $warnings),
144            None => {
145                return $warnings.bail(
146                    Warning::FieldInvalidType {
147                        expected_type: json::ValueKind::String,
148                    },
149                    $elem,
150                );
151            }
152        }
153    }};
154}
155
156/// Get a field by name and fail if it doesn't exist.
157///
158/// Convert the value of the field to the `$target` type.
159#[doc(hidden)]
160#[macro_export]
161macro_rules! parse_required_or_bail {
162    ($elem:expr, $fields:expr, $elem_name:literal, $target:ty, $warnings:expr) => {{
163        #[allow(
164            unused,
165            reason = "the macro uses the import but maybe the outside scope does too."
166        )]
167        use $crate::json::FromJson;
168        use $crate::warning::GatherWarnings as _;
169
170        let elem = $crate::required_field_or_bail!($elem, $fields, $elem_name, $warnings);
171        <$target as FromJson>::from_json(elem)?.gather_warnings_into(&mut $warnings)
172    }};
173}
174
175/// Get a field by name and return `None` if it doesn't exist.
176///
177/// Convert the value of the field to the `$target` type.
178#[doc(hidden)]
179#[macro_export]
180macro_rules! parse_required {
181    ($elem:expr, $fields:expr, $elem_name:literal, $target:ty, $warnings:expr) => {{
182        #[allow(
183            unused,
184            reason = "the macro uses the import but maybe the outside scope does too."
185        )]
186        use $crate::json::FromJson;
187        use $crate::warning::GatherWarnings as _;
188
189        let elem = $crate::required_field!($elem, $fields, $elem_name, $warnings);
190
191        if let Some(elem) = elem {
192            let value =
193                <$target as FromJson>::from_json(elem)?.gather_warnings_into(&mut $warnings);
194            Some(value)
195        } else {
196            None
197        }
198    }};
199}
200
201/// Get an optional field by name and convert the field value to the `$target` type using the
202/// blanket impl `Option<$target>` that can handle `null` JSON values.
203#[doc(hidden)]
204#[macro_export]
205macro_rules! parse_nullable_or_bail {
206    ($fields:expr, $elem_name:literal, $target:ty, $warnings:expr) => {{
207        #[allow(
208            unused,
209            reason = "the macro uses the import but maybe the outside scope does too."
210        )]
211        use $crate::json::FromJson as _;
212        use $crate::warning::GatherWarnings as _;
213
214        match $fields.get($elem_name) {
215            Some(elem) => Option::<$target>::from_json(elem)?.gather_warnings_into(&mut $warnings),
216            None => None,
217        }
218    }};
219}
220
221/// A trait for converting `Element`s to Rust types.
222pub(crate) trait FromJson<'elem, 'buf>: Sized {
223    type Warning: crate::Warning;
224
225    /// Convert the given `Element` to `Self`.
226    fn from_json(elem: &'elem Element<'buf>) -> Verdict<Self, Self::Warning>;
227}
228
229/// Implement a `null` aware variant of all types that implement `FromJson`.
230///
231/// If the value of the `json::Element` is `null` then return a `None`.
232impl<'a, 'b, T> FromJson<'a, 'b> for Option<T>
233where
234    T: FromJson<'a, 'b> + IntoCaveat,
235{
236    type Warning = T::Warning;
237
238    fn from_json(elem: &'a Element<'b>) -> Verdict<Self, Self::Warning> {
239        let value = elem.as_value();
240
241        if value.is_null() {
242            Ok(None.into_caveat(warning::Set::new()))
243        } else {
244            let v = T::from_json(elem)?;
245            Ok(v.map(Some))
246        }
247    }
248}
249
250/// A JSON [`Element`] composed of a `Path` and it's [`Value`].
251///
252/// The `Span` is included so that the [`Element`]'s source `&str` can be acquired from the source JSON if needed.
253#[derive(Clone, Debug, Eq, PartialEq)]
254pub struct Element<'buf> {
255    /// Used to reference the Element from `Warning`s.
256    id: ElemId,
257
258    /// The `Path` to this [`Element`].
259    path_node: PathNodeRef<'buf>,
260
261    /// The `Span` of this [`Element`].
262    ///
263    /// The `Span` defines the range of bytes that delimits this JSON [`Element`].
264    span: Span,
265
266    /// The `Value` of this [`Element`].
267    value: Value<'buf>,
268}
269
270/// A simple integer index used to ID the given [`Element`] within a JSON file.
271///
272/// The Id is unique until `usize::MAX` [`Element`]s are parsed.
273#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq, Ord, PartialOrd)]
274pub(crate) struct ElemId(usize);
275
276impl fmt::Display for ElemId {
277    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
278        fmt::Display::fmt(&self.0, f)
279    }
280}
281
282impl<'buf> Element<'buf> {
283    /// Create a new `Element`.
284    fn new(id: ElemId, path: PathNodeRef<'buf>, span: Span, value: Value<'buf>) -> Element<'buf> {
285        Element {
286            id,
287            path_node: path,
288            span,
289            value,
290        }
291    }
292
293    /// Return the unique Id for this `Element`.
294    pub(crate) const fn id(&self) -> ElemId {
295        self.id
296    }
297
298    /// Return the `Path` to this `Element`.
299    pub fn path(&self) -> PathRef<'buf> {
300        PathRef(self.path_node())
301    }
302
303    /// Return the `PathNode` to this `Element`.
304    pub(crate) fn path_node(&self) -> PathNodeRef<'buf> {
305        Arc::clone(&self.path_node)
306    }
307
308    /// Return the `Span` of the `Element`'s `&str` is the source JSON.
309    pub fn span(&self) -> Span {
310        self.span
311    }
312
313    /// Return the source JSON `&str` of the entire Object field if the `Element` is an Object.
314    /// Otherwise, return the span of the [`Value`].
315    ///
316    /// In the case of an array like `["one", "two"]`, calling this method on the second `Element`
317    /// will return `"two"`.
318    ///
319    /// In the case of an object like `{"one": 1, "two": 2}`, calling this method on the second
320    /// `Element` will return `"\"two\": 2"`.
321    ///
322    /// # Panics
323    ///
324    /// If a source JSON is used that this `Element` didn't not originate from there is a chance
325    /// that this function will panic.
326    pub fn source_json(&self, source_json: &'buf str) -> SourceStr<'buf> {
327        if let PathNode::Object { key, .. } = *self.path_node {
328            // The span of an objects field starts from the start of the key...
329            let span = Span {
330                start: key.span().start,
331                // ... and ends at the end of the value.
332                end: self.span.end,
333            };
334            let field_str = &source_json
335                .get(span.start..span.end)
336                .expect("The disconnection between the source JSON and the `Element` will be fixed in a future PR");
337            let field = RawStr::from_str(field_str, span);
338            let (key, value) = field_str
339                .split_once(':')
340                .expect("An objects field always contains a delimiting `:`");
341
342            SourceStr::Field { field, key, value }
343        } else {
344            let span = self.span;
345            let s = source_json
346                .get(span.start..span.end)
347                .expect("The disconnection between the source JSON and the `Element` will be fixed in a future PR");
348            SourceStr::Value(RawStr::from_str(s, span))
349        }
350    }
351
352    /// Return the source JSON `&str` for the [`Value`].
353    ///
354    /// In the case of an array like `["one", "two"]`, calling this method on the second `Element`
355    /// will return `"two"`.
356    ///
357    /// In the case of an object like `{"one": 1, "two": 2}`, calling this method on the second
358    /// `Element` will return `"2"`.
359    ///
360    /// # Panics
361    ///
362    /// If a source JSON is used that this `Element` didn't not originate from there is a chance
363    /// that this function will panic.
364    pub fn source_json_value(&self, source_json: &'buf str) -> &'buf str {
365        source_json
366            .get(self.span.start..self.span.end)
367            .expect("The disconnection between the source JSON and the `Element` will be fixed in a future PR")
368    }
369
370    /// Return the `Value` of the `Element`.
371    pub(crate) fn value(&self) -> &Value<'buf> {
372        &self.value
373    }
374
375    /// Return the `&Value`.
376    pub(crate) fn as_value(&self) -> &Value<'buf> {
377        &self.value
378    }
379
380    /// Return `Some(&str)` if the `Value` is a `String`.
381    pub(crate) fn as_raw_str(&self) -> Option<&RawStr<'buf>> {
382        self.value.as_raw_str()
383    }
384
385    /// Return `Some(&[Field])` if the `Value` is a `Object`.
386    pub(crate) fn as_object_fields(&self) -> Option<&[Field<'buf>]> {
387        self.value.as_object_fields()
388    }
389
390    pub(crate) fn as_array(&self) -> Option<&[Element<'buf>]> {
391        self.value.as_array()
392    }
393
394    pub fn as_number_str(&self) -> Option<&str> {
395        self.value.as_number()
396    }
397}
398
399#[derive(Debug)]
400pub enum SourceStr<'buf> {
401    /// The source `&str` of the given [`Value`].
402    Value(RawStr<'buf>),
403
404    /// The key-value pair of the given [`Element`] where the [`PathNode`] is referring to an object.
405    Field {
406        /// The entire field as a `&str`. This is the `&str` from the beginning of the key to the end of the value.
407        field: RawStr<'buf>,
408
409        /// The key excluding the separating `:`.
410        key: &'buf str,
411
412        /// The [`Value`] as `&str`.
413        value: &'buf str,
414    },
415}
416
417impl fmt::Display for SourceStr<'_> {
418    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
419        match self {
420            SourceStr::Value(s) => f.write_str(s.as_raw()),
421            SourceStr::Field { field, .. } => f.write_str(field.as_raw()),
422        }
423    }
424}
425
426/// The `SourceStr` can be compared with other strings just like a `String`.
427impl PartialEq<&str> for SourceStr<'_> {
428    fn eq(&self, other: &&str) -> bool {
429        match self {
430            SourceStr::Value(s) => s.as_raw() == *other,
431            SourceStr::Field { field, .. } => field.as_raw() == *other,
432        }
433    }
434}
435
436/// The `SourceStr` can be compared with other strings just like a `String`.
437impl PartialEq<String> for SourceStr<'_> {
438    fn eq(&self, other: &String) -> bool {
439        self.eq(&&**other)
440    }
441}
442
443impl PartialOrd for Element<'_> {
444    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
445        Some(self.cmp(other))
446    }
447}
448
449impl Ord for Element<'_> {
450    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
451        self.path_node.cmp(&other.path_node)
452    }
453}
454
455impl fmt::Display for Element<'_> {
456    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
457        write!(f, "{} = {}", self.path_node, self.value)
458    }
459}
460
461/// A JSON `Object`'s field that upholds the invariant that the `Element`'s `Path` is as `Object`.
462#[derive(Clone, Debug, Eq, PartialEq)]
463pub(crate) struct Field<'buf>(Element<'buf>);
464
465impl<'buf> Field<'buf> {
466    #[expect(
467        clippy::unreachable,
468        reason = "A Field is created by the parser when the type is an Object."
469    )]
470    pub(crate) fn key(&self) -> RawStr<'buf> {
471        let PathNode::Object { key, .. } = *self.0.path_node else {
472            unreachable!();
473        };
474
475        key
476    }
477
478    /// Consume the `Field` and return the inner `Element`.
479    #[expect(dead_code, reason = "pending use in `tariff::lint`")]
480    pub(crate) fn into_element(self) -> Element<'buf> {
481        self.0
482    }
483
484    /// Consume the `Field` and return the inner `Element`.
485    pub(crate) fn element(&self) -> &Element<'buf> {
486        &self.0
487    }
488}
489
490/// A JSON `Value` that borrows it's content from the source JSON `&str`.
491#[derive(Clone, Debug, Eq, PartialEq)]
492pub(crate) enum Value<'buf> {
493    /// A `"null"` value.
494    Null,
495
496    /// A `"true"` value.
497    True,
498
499    /// A `"false"` value.
500    False,
501
502    /// The value of the `String` has the quotes trimmed.
503    String(RawStr<'buf>),
504
505    /// A JSON `Number` in string format.
506    ///
507    /// The string is not guaranteed to be a valid number. Only that it's not a `null`, `bool` or `string` value.
508    /// Convert the string into the number format you want.
509    Number(&'buf str),
510
511    /// A JSON `Array` parsed into a `Vec` of `Elements`.
512    ///
513    /// The inner `Element`'s path also encodes the index.
514    /// E.g. `$.elements.2`: This path refers to third OCPI tariff element.
515    Array(Vec<Element<'buf>>),
516
517    /// A JSON `Object` where each of the fields are parsed into a `Vec` of `Elements`.
518    ///
519    /// The inner `Element`'s path encodes the fields key.
520    /// E.g. `$.elements.2.restrictions` This path refers to the `restrictions` `Object`
521    /// of the third OCPI tariff element.
522    Object(Vec<Field<'buf>>),
523}
524
525impl<'buf> Value<'buf> {
526    pub(crate) fn kind(&self) -> ValueKind {
527        match self {
528            Value::Null => ValueKind::Null,
529            Value::True | Value::False => ValueKind::Bool,
530            Value::String(_) => ValueKind::String,
531            Value::Number(_) => ValueKind::Number,
532            Value::Array(_) => ValueKind::Array,
533            Value::Object(_) => ValueKind::Object,
534        }
535    }
536
537    pub(crate) fn is_null(&self) -> bool {
538        matches!(self, Value::Null)
539    }
540
541    /// Return true if the `Value` can't contain child elements.
542    pub(crate) fn is_scalar(&self) -> bool {
543        matches!(
544            self,
545            Value::Null | Value::True | Value::False | Value::String(_) | Value::Number(_)
546        )
547    }
548
549    pub(crate) fn as_array(&self) -> Option<&[Element<'buf>]> {
550        match self {
551            Value::Array(elems) => Some(elems),
552            _ => None,
553        }
554    }
555
556    pub(crate) fn as_number(&self) -> Option<&str> {
557        match self {
558            Value::Number(s) => Some(s),
559            _ => None,
560        }
561    }
562
563    /// Return `Some(&str)` if the `Value` is a `String`.
564    pub(crate) fn as_raw_str(&self) -> Option<&RawStr<'buf>> {
565        match self {
566            Value::String(s) => Some(s),
567            _ => None,
568        }
569    }
570
571    /// Return `Some(&[Field])` if the `Value` is a `Object`.
572    pub(crate) fn as_object_fields(&self) -> Option<&[Field<'buf>]> {
573        match self {
574            Value::Object(fields) => Some(fields),
575            _ => None,
576        }
577    }
578}
579
580impl fmt::Display for Value<'_> {
581    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
582        match self {
583            Self::Null => write!(f, "null"),
584            Self::True => write!(f, "true"),
585            Self::False => write!(f, "false"),
586            Self::String(s) => write!(f, "{s}"),
587            Self::Number(s) => write!(f, "{s}"),
588            Self::Array(..) => f.write_str("[...]"),
589            Self::Object(..) => f.write_str("{...}"),
590        }
591    }
592}
593
594/// A light-weight type identity for a JSON `Value`'s content.
595#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd)]
596pub enum ValueKind {
597    Null,
598    Bool,
599    Number,
600    String,
601    Array,
602    Object,
603}
604
605impl fmt::Display for ValueKind {
606    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
607        match self {
608            ValueKind::Null => write!(f, "null"),
609            ValueKind::Bool => write!(f, "bool"),
610            ValueKind::Number => write!(f, "number"),
611            ValueKind::String => write!(f, "string"),
612            ValueKind::Array => write!(f, "array"),
613            ValueKind::Object => write!(f, "object"),
614        }
615    }
616}
617
618/// Used to distinguish the type of compound object.
619///
620/// This is used to track which type of object an `Element` is in when parsing.
621#[derive(Copy, Clone, Debug, Eq, PartialEq)]
622pub(crate) enum ObjectKind {
623    Object,
624    Array,
625}
626
627pub type RawMap<'buf> = BTreeMap<RawStr<'buf>, Element<'buf>>;
628pub type RawRefMap<'a, 'buf> = BTreeMap<RawStr<'buf>, &'a Element<'buf>>;
629
630#[expect(dead_code, reason = "pending use in `tariff::lint`")]
631pub(crate) trait FieldsIntoExt<'buf> {
632    fn into_map(self) -> RawMap<'buf>;
633}
634
635pub(crate) trait FieldsAsExt<'buf> {
636    fn as_raw_map(&self) -> RawRefMap<'_, 'buf>;
637    fn find_field(&self, key: &str) -> Option<&Field<'buf>>;
638}
639
640impl<'buf> FieldsIntoExt<'buf> for Vec<Field<'buf>> {
641    fn into_map(self) -> RawMap<'buf> {
642        self.into_iter()
643            .map(|field| (field.key(), field.into_element()))
644            .collect()
645    }
646}
647
648impl<'buf> FieldsAsExt<'buf> for Vec<Field<'buf>> {
649    fn as_raw_map(&self) -> RawRefMap<'_, 'buf> {
650        self.iter()
651            .map(|field| (field.key(), field.element()))
652            .collect()
653    }
654
655    fn find_field(&self, key: &str) -> Option<&Field<'buf>> {
656        self.iter().find(|field| field.key().as_raw() == key)
657    }
658}
659
660impl<'buf> FieldsAsExt<'buf> for [Field<'buf>] {
661    fn as_raw_map(&self) -> RawRefMap<'_, 'buf> {
662        self.iter()
663            .map(|field| (field.key(), field.element()))
664            .collect()
665    }
666
667    fn find_field(&self, key: &str) -> Option<&Field<'buf>> {
668        self.iter().find(|field| field.key().as_raw() == key)
669    }
670}
671
672/// A collection of paths that were unexpected according to the schema used while parsing the JSON
673/// for an OCPI object.
674#[derive(Clone, Debug)]
675pub struct UnexpectedFields<'buf>(Vec<PathNodeRef<'buf>>);
676
677impl fmt::Display for UnexpectedFields<'_> {
678    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
679        if f.alternate() {
680            // Print each path on a newline.
681            f.write_str("[\n")?;
682            for entry in &self.0 {
683                writeln!(f, "\t\"{entry}\",")?;
684            }
685            f.write_str("]\n")?;
686        } else {
687            // Print all paths on a single line.
688            f.write_char('[')?;
689            for entry in &self.0 {
690                write!(f, "{entry},")?;
691            }
692            f.write_char(']')?;
693        }
694
695        Ok(())
696    }
697}
698
699impl<'buf> UnexpectedFields<'buf> {
700    /// Create an empty `UnexpectedFields` collection.
701    pub(crate) fn empty() -> Self {
702        Self(vec![])
703    }
704
705    /// Create a collection of `UnexpectedFields` from a `Vec`
706    pub(crate) fn from_vec(v: Vec<PathNodeRef<'buf>>) -> Self {
707        Self(v)
708    }
709
710    /// Return the field paths as a `Vec` of `String`s.
711    pub fn to_strings(&self) -> Vec<String> {
712        self.0.iter().map(ToString::to_string).collect()
713    }
714
715    /// Return the field paths as a `Vec` of `String`s.
716    pub fn into_strings(self) -> Vec<String> {
717        self.0.into_iter().map(|path| path.to_string()).collect()
718    }
719
720    /// Return true if the list of unexpected fields is empty.
721    pub fn is_empty(&self) -> bool {
722        self.0.is_empty()
723    }
724
725    /// Return the number of unexpected fields.
726    pub fn len(&self) -> usize {
727        self.0.len()
728    }
729
730    /// Return an Iterator over the unexpected fields.
731    pub fn iter<'a>(&'a self) -> UnexpectedFieldsIter<'a, 'buf> {
732        UnexpectedFieldsIter(self.0.iter())
733    }
734}
735
736impl<'buf> IntoIterator for UnexpectedFields<'buf> {
737    type Item = PathRef<'buf>;
738
739    type IntoIter = UnexpectedFieldsIntoIter<'buf>;
740
741    fn into_iter(self) -> Self::IntoIter {
742        UnexpectedFieldsIntoIter(self.0.into_iter())
743    }
744}
745
746pub struct UnexpectedFieldsIntoIter<'buf>(std::vec::IntoIter<PathNodeRef<'buf>>);
747
748impl<'buf> Iterator for UnexpectedFieldsIntoIter<'buf> {
749    type Item = PathRef<'buf>;
750
751    fn next(&mut self) -> Option<Self::Item> {
752        let path_node = self.0.next()?;
753
754        Some(PathRef(path_node))
755    }
756}
757
758impl<'a, 'buf> IntoIterator for &'a UnexpectedFields<'buf> {
759    type Item = PathRef<'buf>;
760
761    type IntoIter = UnexpectedFieldsIter<'a, 'buf>;
762
763    fn into_iter(self) -> Self::IntoIter {
764        self.iter()
765    }
766}
767
768/// An `Iterator` over each unexpected field as a `PathRef`.
769pub struct UnexpectedFieldsIter<'a, 'buf>(std::slice::Iter<'a, PathNodeRef<'buf>>);
770
771impl<'buf> Iterator for UnexpectedFieldsIter<'_, 'buf> {
772    type Item = PathRef<'buf>;
773
774    fn next(&mut self) -> Option<Self::Item> {
775        let path_node = self.0.next()?;
776
777        Some(PathRef(Arc::clone(path_node)))
778    }
779}
780
781/// A path to a JSON `Element` where the path components are borrowed from the source JSON `&str`.
782///
783/// The Display impl outputs strings like:
784///
785/// - `$` The root is represented by a dollar.
786/// - `$.object_key` Dots separate the path elements.
787/// - `$.object_key.2` Arrays are represented as integers.
788pub struct PathRef<'buf>(PathNodeRef<'buf>);
789
790impl fmt::Debug for PathRef<'_> {
791    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
792        write!(f, "{self}")
793    }
794}
795
796impl<'buf> PathRef<'buf> {
797    /// Return an [`Iterator`] over the components of this path.
798    pub fn components(&self) -> PathComponents<'buf> {
799        PathComponents(PathIter::new(Arc::clone(&self.0)))
800    }
801}
802
803/// An [`Iterator`] over the components of a path.
804pub struct PathComponents<'buf>(PathIter<'buf>);
805
806impl<'buf> Iterator for PathComponents<'buf> {
807    type Item = PathComponent<'buf>;
808
809    fn next(&mut self) -> Option<Self::Item> {
810        let path_node = self.0.next()?;
811        Some(PathComponent(path_node))
812    }
813}
814
815/// The `PathRef` can be compared with other strings just like a `String`.
816impl PartialEq<&str> for PathRef<'_> {
817    fn eq(&self, other: &&str) -> bool {
818        match_path_node(&self.0, other, |_| false)
819    }
820}
821
822/// The `PathRef` can be compared with other strings just like a `String`.
823impl PartialEq<String> for PathRef<'_> {
824    fn eq(&self, other: &String) -> bool {
825        match_path_node(&self.0, other, |_| false)
826    }
827}
828
829impl fmt::Display for PathRef<'_> {
830    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
831        fmt::Display::fmt(&self.0, f)
832    }
833}
834
835/// The path to a JSON `Element`.
836pub(crate) type PathNodeRef<'buf> = Arc<PathNode<'buf>>;
837
838/// A single node of a complete path.
839///
840/// Path's are structured as a linked list from the leaf of the path back to the root through the parents.
841///
842/// The Display impl of the `Path` outputs strings like:
843///
844/// - `$` The root is represented by a dollar.
845/// - `$.object_key` Dots separate the path elements.
846/// - `$.object_key.2` Arrays are represented as integers.
847#[derive(Clone, Debug, Default, Eq, PartialEq, Ord, PartialOrd)]
848pub(crate) enum PathNode<'buf> {
849    /// The root of the JSON `Element` tree.
850    #[default]
851    Root,
852    /// An `Array` element referenced by index.
853    Array {
854        parent: PathNodeRef<'buf>,
855        index: usize,
856    },
857    /// An `Object` field referenced be key value.
858    Object {
859        parent: PathNodeRef<'buf>,
860        key: RawStr<'buf>,
861    },
862}
863
864/// A lightweight enum used to indicate the kind of component being visited when using the
865/// [`PathComponents`] [`Iterator`].
866pub enum PathNodeKind {
867    /// The root of the JSON `Element` tree.
868    Root,
869    /// An `Array` element referenced by index.
870    Array,
871    /// An `Object` field referenced be key value.
872    Object,
873}
874
875/// A path to a JSON `Element` where the path components are heap allocated and so do not require
876/// a lifetime back to the source JSON `&str`.
877///
878/// The Display impl outputs strings like:
879///
880/// - `$` The root is represented by a dollar.
881/// - `$.object_key` Dots separate the path elements.
882/// - `$.object_key.2` Arrays are represented as integers.
883#[derive(Clone, Debug, Eq, PartialEq, Ord, PartialOrd)]
884pub struct Path(Vec<PathPiece>);
885
886impl Path {
887    /// Create a root `Path`.
888    const fn root() -> Self {
889        Self(vec![])
890    }
891
892    /// Create an `Path` by iterating over a [`PathNode`].
893    fn from_node(path: PathNodeRef<'_>) -> Self {
894        let paths: Vec<_> = PathIter::new(path).collect();
895
896        let pieces = paths
897            .into_iter()
898            .rev()
899            .filter_map(|path_node| match *path_node {
900                PathNode::Root => None,
901                PathNode::Array { index, .. } => Some(PathPiece::Array(index)),
902                PathNode::Object { key, .. } => Some(PathPiece::Object(key.to_string())),
903            })
904            .collect();
905
906        Self(pieces)
907    }
908}
909
910/// The `Path` can be compared with other strings just like a `String`.
911impl PartialEq<&str> for Path {
912    fn eq(&self, other: &&str) -> bool {
913        match_path(self, other)
914    }
915}
916
917/// The `Path` can be compared with other strings just like a `String`.
918impl PartialEq<String> for Path {
919    fn eq(&self, other: &String) -> bool {
920        match_path(self, other)
921    }
922}
923
924impl fmt::Display for Path {
925    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
926        let iter = self.0.iter();
927
928        write!(f, "$")?;
929
930        for path in iter {
931            write!(f, ".{path}")?;
932        }
933
934        Ok(())
935    }
936}
937
938/// A piece/component of a [`Path`].
939///
940/// The `PathComponent` name is already taken and this type is private.
941#[derive(Clone, Debug, Eq, PartialEq, Ord, PartialOrd)]
942enum PathPiece {
943    /// An `Array` element referenced by index.
944    Array(usize),
945    /// An `Object` field referenced be key value.
946    Object(String),
947}
948
949impl fmt::Display for PathPiece {
950    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
951        match self {
952            PathPiece::Array(index) => write!(f, "{index}"),
953            PathPiece::Object(key) => write!(f, "{key}"),
954        }
955    }
956}
957
958/// A single component of a [`PathRef`].
959pub struct PathComponent<'buf>(PathNodeRef<'buf>);
960
961impl PathComponent<'_> {
962    /// Return the kind of component this is.
963    pub fn kind(&self) -> PathNodeKind {
964        match *self.0 {
965            PathNode::Root => PathNodeKind::Root,
966            PathNode::Array { .. } => PathNodeKind::Array,
967            PathNode::Object { .. } => PathNodeKind::Object,
968        }
969    }
970}
971
972impl fmt::Display for PathComponent<'_> {
973    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
974        match *self.0 {
975            PathNode::Root => f.write_str(PATH_ROOT),
976            PathNode::Array { index, .. } => write!(f, "{index}"),
977            PathNode::Object { key, .. } => write!(f, "{key}"),
978        }
979    }
980}
981
982impl fmt::Display for PathNode<'_> {
983    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
984        let paths: Vec<_> = PathIter::new(Arc::new(self.clone())).collect();
985        let mut iter = paths.into_iter().rev();
986
987        if f.alternate() {
988            // Print out each path element as a debugging tab-stop.
989            for path in iter {
990                match *path {
991                    PathNode::Root => f.write_str("")?,
992                    PathNode::Array { .. } | PathNode::Object { .. } => f.write_str("...|")?,
993                }
994            }
995        } else {
996            if let Some(path) = iter.next() {
997                write!(f, "{}", PathComponent(path))?;
998            }
999
1000            for path in iter {
1001                write!(f, ".{}", PathComponent(path))?;
1002            }
1003        }
1004        Ok(())
1005    }
1006}
1007
1008impl<'buf> PathNode<'buf> {
1009    /// Returns true if the `Path` refers to the root.
1010    pub(crate) fn is_root(&self) -> bool {
1011        matches!(self, PathNode::Root)
1012    }
1013
1014    /// Returns true if the `Path` refers to an `Array`.
1015    pub(crate) fn is_array(&self) -> bool {
1016        matches!(self, PathNode::Array { .. })
1017    }
1018
1019    /// Return a key as `Some(&str)` if the `Path` refers to an `Object`.
1020    pub(crate) fn as_object_key(&self) -> Option<&RawStr<'buf>> {
1021        match self {
1022            PathNode::Object { key, .. } => Some(key),
1023            PathNode::Root | PathNode::Array { .. } => None,
1024        }
1025    }
1026}
1027
1028/// Return true if the given `PathNode` matches the given `&str`.
1029///
1030/// If the `skip` function returns true, that path component is skipped.
1031/// The `skip` function allows this single function to implement comparisons between `PathNode` and `&str`;
1032/// and comparisons between `PathNode` and `PathGlob`.
1033fn match_path_node<F>(path: &PathNode<'_>, s: &str, mut skip: F) -> bool
1034where
1035    F: FnMut(&str) -> bool,
1036{
1037    let mut parts = s.rsplit(PATH_SEPARATOR);
1038    let mut paths_iter = PathIter::new(Arc::new(path.clone()));
1039
1040    loop {
1041        let node_segment = paths_iter.next();
1042        let str_segment = parts.next();
1043
1044        let (node_segment, str_segment) = match (node_segment, str_segment) {
1045            // If we have exhausted both iterators then the `&str` is equal to the path.
1046            (None, None) => return true,
1047            // If either of the iters are a different size, then they don't match.
1048            (None, Some(_)) | (Some(_), None) => return false,
1049            // If both iters have another item, continue on to try match them.
1050            (Some(a), Some(b)) => (a, b),
1051        };
1052
1053        // If the skip function says to skip a path segment, then continue to the next segment.
1054        if skip(str_segment) {
1055            continue;
1056        }
1057
1058        let yip = match *node_segment {
1059            PathNode::Root => str_segment == PATH_ROOT,
1060            PathNode::Array { index, .. } => {
1061                let Ok(b) = str_segment.parse::<usize>() else {
1062                    return false;
1063                };
1064
1065                index == b
1066            }
1067            PathNode::Object { key, .. } => key.as_raw() == str_segment,
1068        };
1069
1070        // Return false on the first mismatch.
1071        if !yip {
1072            return false;
1073        }
1074    }
1075}
1076
1077/// Return true if the given `Path` matches the given `&str`.
1078fn match_path(path: &Path, s: &str) -> bool {
1079    let mut parts = s.split(PATH_SEPARATOR);
1080    let mut paths_iter = path.0.iter();
1081
1082    let Some(str_segment) = parts.next() else {
1083        return false;
1084    };
1085
1086    // The root path segment is not explicitly stored in a `Path` so we just match the first
1087    // `str` segment to the expected `$` nomenclature.
1088    if str_segment != PATH_ROOT {
1089        return false;
1090    }
1091
1092    loop {
1093        let node_segment = paths_iter.next();
1094        let str_segment = parts.next();
1095
1096        let (node_segment, str_segment) = match (node_segment, str_segment) {
1097            // If we have exhausted both iterators then the `&str` is equal to the path.
1098            (None, None) => return true,
1099            // If either of the iters are a different size, then they don't match.
1100            (None, Some(_)) | (Some(_), None) => return false,
1101            // If both iters have another item, continue on to try match them.
1102            (Some(a), Some(b)) => (a, b),
1103        };
1104
1105        let yip = match node_segment {
1106            PathPiece::Array(index) => {
1107                let Ok(b) = str_segment.parse::<usize>() else {
1108                    return false;
1109                };
1110
1111                *index == b
1112            }
1113            PathPiece::Object(key) => key == str_segment,
1114        };
1115
1116        // Return false on the first mismatch.
1117        if !yip {
1118            return false;
1119        }
1120    }
1121}
1122
1123impl PartialEq<&str> for PathNode<'_> {
1124    fn eq(&self, other: &&str) -> bool {
1125        match_path_node(self, other, |_| false)
1126    }
1127}
1128
1129impl PartialEq<String> for PathNode<'_> {
1130    fn eq(&self, other: &String) -> bool {
1131        match_path_node(self, other, |_| false)
1132    }
1133}
1134
1135/// Traverse a `Path` from the leaf to the root.
1136struct PathIter<'buf> {
1137    /// The root has been reached.
1138    complete: bool,
1139    /// The current path node to introspect when `Iterator::next` is called.
1140    path: PathNodeRef<'buf>,
1141}
1142
1143impl<'buf> PathIter<'buf> {
1144    /// Create a new `PathIter` from a leaf node.
1145    fn new(path: PathNodeRef<'buf>) -> Self {
1146        Self {
1147            complete: false,
1148            path,
1149        }
1150    }
1151}
1152
1153impl<'buf> Iterator for PathIter<'buf> {
1154    type Item = PathNodeRef<'buf>;
1155
1156    fn next(&mut self) -> Option<Self::Item> {
1157        if self.complete {
1158            return None;
1159        }
1160
1161        match &*self.path {
1162            PathNode::Root => {
1163                // The iteration is complete once we've arrived at the root node.
1164                self.complete = true;
1165                Some(Arc::clone(&self.path))
1166            }
1167            PathNode::Array { parent, .. } | PathNode::Object { parent, .. } => {
1168                let next = Arc::clone(&self.path);
1169                self.path = Arc::clone(parent);
1170                Some(next)
1171            }
1172        }
1173    }
1174}
1175
1176/// Display the expectation stack for debugging
1177struct DisplayExpectStack<'a>(&'a [schema::Expect]);
1178
1179impl fmt::Display for DisplayExpectStack<'_> {
1180    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1181        let mut iter = self.0.iter().rev();
1182        let last = iter.next();
1183
1184        // Use the `~` to represent a schema stack.
1185        f.write_str("~")?;
1186
1187        for _ in iter {
1188            f.write_str("...~")?;
1189        }
1190
1191        if let Some(exp) = last {
1192            match exp {
1193                schema::Expect::Scalar => f.write_str("~")?,
1194                schema::Expect::Array(element) => match &**element {
1195                    schema::Element::Scalar => f.write_str("~")?,
1196                    schema::Element::Array(element) => write!(f, "[{element:?}]")?,
1197                    schema::Element::Object(fields) => {
1198                        write!(f, "[{{{:}}}])", DisplayExpectFields(&**fields))?;
1199                    }
1200                },
1201                schema::Expect::Object(fields) => {
1202                    write!(f, "{{{:}}}", DisplayExpectFields(&**fields))?;
1203                }
1204                schema::Expect::UnmatchedScalar => write!(f, "unmatched(scalar)")?,
1205                schema::Expect::UnmatchedArray => write!(f, "unmatched(array)")?,
1206                schema::Expect::UnmatchedObject => write!(f, "unmatched(object)")?,
1207                schema::Expect::OutOfSchema => write!(f, "no_schema")?,
1208            }
1209        }
1210
1211        Ok(())
1212    }
1213}
1214
1215/// Display the fields of a schema expect stack level.
1216struct DisplayExpectFields<'a, V>(&'a BTreeMap<&'a str, V>);
1217
1218impl<V> fmt::Display for DisplayExpectFields<'_, V> {
1219    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1220        const MAX_FIELDS: usize = 8;
1221
1222        let mut count = 0;
1223        let mut iter = self.0.keys().peekable();
1224
1225        loop {
1226            if count >= MAX_FIELDS {
1227                f.write_str("...")?;
1228                break;
1229            }
1230
1231            let Some(field) = iter.next() else {
1232                break;
1233            };
1234
1235            let Some(n) = count.checked_add(1) else {
1236                break;
1237            };
1238            count = n;
1239
1240            write!(f, "{field}")?;
1241
1242            let Some(_) = iter.peek() else {
1243                break;
1244            };
1245
1246            f.write_str(", ")?;
1247        }
1248
1249        Ok(())
1250    }
1251}
1252
1253#[derive(Debug)]
1254struct UnbalancedExpectStack;
1255
1256impl fmt::Display for UnbalancedExpectStack {
1257    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1258        f.write_str("unbalanced expectation stack")
1259    }
1260}
1261
1262impl std::error::Error for UnbalancedExpectStack {}
1263
1264/// Parse the JSON into a [`ParseReport`] checking the parsed [`Element`]s names against the given
1265/// [`schema`] and reporting fields that are unexpected in the [`ParseReport::unexpected_fields`].
1266pub(crate) fn parse_with_schema<'buf>(
1267    json: &'buf str,
1268    schema: &schema::Element,
1269) -> Result<ParseReport<'buf>, Error> {
1270    let parser = Parser::new(json);
1271    let mut unexpected_fields = vec![];
1272    // The current node of the schema is the last element of this `Vec`.
1273    let mut expectation_stack = vec![schema.to_expectation()];
1274
1275    for event in parser {
1276        match event? {
1277            parser::Event::Open { kind, parent_path } => {
1278                // Take the schema expectation off the stack.
1279                // This is simpler than taking a `&mut` to the last element.
1280                let Some(expectation) = expectation_stack.pop() else {
1281                    return Err(ErrorKind::Internal(Box::new(UnbalancedExpectStack))
1282                        .into_partial_error_without_token()
1283                        .with_root_path());
1284                };
1285
1286                if tracing::enabled!(Level::DEBUG) {
1287                    match kind {
1288                        ObjectKind::Array => {
1289                            trace!("{parent_path} [ {}", DisplayExpectStack(&expectation_stack));
1290                        }
1291                        ObjectKind::Object => trace!(
1292                            "{parent_path} {{ {}",
1293                            DisplayExpectStack(&expectation_stack)
1294                        ),
1295                    }
1296                }
1297
1298                match expectation {
1299                    schema::Expect::Array(elem) => {
1300                        // If the opening element is at the root we only care if the element
1301                        // is an array or not.
1302                        if parent_path.is_root() {
1303                            let next = match kind {
1304                                ObjectKind::Array => schema::Expect::Array(elem),
1305                                ObjectKind::Object => schema::Expect::UnmatchedArray,
1306                            };
1307
1308                            expectation_stack.push(next);
1309                            trace!("{}", DisplayExpectStack(&expectation_stack));
1310                            continue;
1311                        }
1312
1313                        if !parent_path.is_array() {
1314                            expectation_stack.push(schema::Expect::UnmatchedArray);
1315                            trace!("{}", DisplayExpectStack(&expectation_stack));
1316                            continue;
1317                        }
1318
1319                        expectation_stack.push(schema::Expect::Array(Arc::clone(&elem)));
1320                        // Each array element should match this expectation
1321                        expectation_stack.push(elem.to_expectation());
1322                    }
1323                    schema::Expect::Object(fields) => {
1324                        // If the opening element is at the root there is no path to inspect.
1325                        // We only care if the element is an object or not.
1326                        if parent_path.is_root() {
1327                            let next = match kind {
1328                                ObjectKind::Array => schema::Expect::UnmatchedObject,
1329                                ObjectKind::Object => schema::Expect::Object(fields),
1330                            };
1331
1332                            expectation_stack.push(next);
1333                            trace!("{}", DisplayExpectStack(&expectation_stack));
1334                            continue;
1335                        }
1336                        let Some(key) = parent_path.as_object_key() else {
1337                            expectation_stack.push(schema::Expect::UnmatchedObject);
1338                            trace!("{}", DisplayExpectStack(&expectation_stack));
1339                            continue;
1340                        };
1341
1342                        let next = if let Some(elem) = fields.get(key.as_raw()) {
1343                            open_object(kind, elem.as_ref())
1344                        } else {
1345                            unexpected_fields.push(parent_path);
1346                            schema::Expect::OutOfSchema
1347                        };
1348
1349                        expectation_stack.push(schema::Expect::Object(fields));
1350                        expectation_stack.push(next);
1351                    }
1352                    schema::Expect::OutOfSchema => {
1353                        // If we're already outside of the schema we put that back on the stack
1354                        // and add a new one for the object that just opened.
1355                        //
1356                        // We need to track the object level even though the schema expectations
1357                        // have been exhausted, as we'll pop these placeholder `OutOfSchema`s
1358                        // off the stack when the object has closed so we land on the correct
1359                        // schema again.
1360                        expectation_stack.push(expectation);
1361                        expectation_stack.push(schema::Expect::OutOfSchema);
1362                    }
1363                    schema::Expect::UnmatchedArray | schema::Expect::UnmatchedObject => {
1364                        expectation_stack.push(expectation);
1365                        expectation_stack.push(schema::Expect::OutOfSchema);
1366                    }
1367                    _ => {
1368                        expectation_stack.push(expectation);
1369                    }
1370                }
1371
1372                trace!("{}", DisplayExpectStack(&expectation_stack));
1373            }
1374            parser::Event::Element { kind, parent_path } => {
1375                // Take the schema expectation off the stack.
1376                // This is simpler than taking a `&mut` to the last element.
1377                let Some(expectation) = expectation_stack.pop() else {
1378                    return Err(ErrorKind::Internal(Box::new(UnbalancedExpectStack))
1379                        .into_partial_error_without_token()
1380                        .with_root_path());
1381                };
1382
1383                // An `Element` of kind `Array` or `Object` means the `Element` is closed
1384                // and has completed construction. The expectation can remain off the stack.
1385                if let ValueKind::Array | ValueKind::Object = kind {
1386                    if tracing::enabled!(Level::DEBUG) {
1387                        match kind {
1388                            ValueKind::Array => {
1389                                trace!(
1390                                    "{parent_path} ] {}",
1391                                    DisplayExpectStack(&expectation_stack)
1392                                );
1393                            }
1394                            ValueKind::Object => trace!(
1395                                "{parent_path} }} {}",
1396                                DisplayExpectStack(&expectation_stack)
1397                            ),
1398                            _ => (),
1399                        }
1400                    }
1401                    continue;
1402                }
1403
1404                match expectation {
1405                    #[expect(
1406                        clippy::unreachable,
1407                        reason = "The parser only emits an `Event::Complete` for a scalar object at the root"
1408                    )]
1409                    schema::Expect::Object(fields) => match &*parent_path {
1410                        PathNode::Root => unreachable!(),
1411                        PathNode::Array { .. } => {
1412                            expectation_stack.push(schema::Expect::UnmatchedObject);
1413                        }
1414                        PathNode::Object { parent, key } => {
1415                            trace!("{parent:#}.{key}");
1416
1417                            if !fields.contains_key(key.as_raw()) {
1418                                unexpected_fields.push(parent_path);
1419                            }
1420
1421                            expectation_stack.push(schema::Expect::Object(fields));
1422                        }
1423                    },
1424                    schema::Expect::OutOfSchema => {
1425                        unexpected_fields.push(parent_path);
1426                        expectation_stack.push(expectation);
1427                    }
1428                    _ => {
1429                        expectation_stack.push(expectation);
1430                    }
1431                }
1432            }
1433            parser::Event::Complete(element) => {
1434                if element.value().is_scalar() {
1435                    unexpected_fields.push(element.path_node());
1436                }
1437
1438                // Parsing the JSON is complete.
1439                // Return the `Element` and the unexpected fields collected during parsing
1440                return Ok(ParseReport {
1441                    element,
1442                    unexpected_fields: UnexpectedFields::from_vec(unexpected_fields),
1443                });
1444            }
1445        }
1446    }
1447
1448    Err(ErrorKind::UnexpectedEOF
1449        .into_partial_error_without_token()
1450        .with_root_path())
1451}
1452
1453fn open_object(kind: ObjectKind, elem: Option<&Arc<schema::Element>>) -> schema::Expect {
1454    let Some(schema) = elem else {
1455        return schema::Expect::OutOfSchema;
1456    };
1457
1458    match (kind, &**schema) {
1459        (ObjectKind::Object | ObjectKind::Array, schema::Element::Scalar) => {
1460            schema::Expect::UnmatchedScalar
1461        }
1462        (ObjectKind::Object, schema::Element::Array(_)) => schema::Expect::UnmatchedArray,
1463        (ObjectKind::Object, schema::Element::Object(fields)) => {
1464            schema::Expect::Object(Arc::clone(fields))
1465        }
1466        (ObjectKind::Array, schema::Element::Array(element)) => {
1467            schema::Expect::Array(Arc::clone(element))
1468        }
1469        (ObjectKind::Array, schema::Element::Object(_)) => schema::Expect::UnmatchedObject,
1470    }
1471}
1472
1473/// The output of the `parse_with_schema` function where the parsed JSON `Element` is returned
1474/// along with a list of fields that the schema did not define.
1475#[derive(Debug)]
1476pub(crate) struct ParseReport<'buf> {
1477    /// The root JSON [`Element`].
1478    pub element: Element<'buf>,
1479
1480    /// A list of fields that were not expected: The schema did not define them.
1481    pub unexpected_fields: UnexpectedFields<'buf>,
1482}