Skip to main content

ocpi_tariffs/
json.rs

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