ocpi_tariffs/
json.rs

1//! Types and functions for parsing JSON in a flexible and pedantic manner.
2pub mod decode;
3pub mod parser;
4pub(crate) mod schema;
5pub(crate) mod walk;
6pub mod write;
7
8#[cfg(test)]
9mod test_parser;
10
11use std::{
12    collections::BTreeMap,
13    fmt::{self, Write as _},
14    rc::Rc,
15    sync::Arc,
16};
17
18use serde::Serialize;
19use tracing::{trace, Level};
20
21use crate::{warning, Verdict};
22use parser::ErrorKind;
23use parser::{Parser, Span};
24
25#[doc(inline)]
26pub use parser::{line_col, Error, ErrorReport, LineCol};
27pub(crate) use parser::{parse, RawStr};
28
29const PATH_SEPARATOR: char = '.';
30const PATH_ROOT: &str = "$";
31
32/// A trait for converting `Element`s to Rust types.
33pub(crate) trait FromJson<'elem, 'buf>: Sized {
34    type WarningKind: warning::Kind;
35
36    /// Convert the given `Element` to `Self`.
37    fn from_json(elem: &'elem Element<'buf>) -> Verdict<Self, Self::WarningKind>;
38}
39
40/// A JSON [`Element`] composed of a `Path` and it's [`Value`].
41///
42/// The `Span` is included so that the [`Element`]'s  source `&str` can be acquired from the source JSON if needed.
43#[derive(Debug, Eq, PartialEq)]
44pub struct Element<'buf> {
45    /// Used to reference the Element from `Warning`s.
46    id: ElemId,
47
48    /// The `Path` to this [`Element`].
49    path_node: PathNodeRef<'buf>,
50
51    /// The `Span` of this [`Element`].
52    ///
53    /// The `Span` defines the range of bytes that delimits this JSON [`Element`].
54    span: Span,
55
56    /// The `Value` of this [`Element`].
57    value: Value<'buf>,
58}
59
60/// A simple integer index used to ID the given [`Element`] within a JSON file.
61///
62/// The Id is unique until `usize::MAX` [`Element`]s are parsed.
63#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq, Ord, PartialOrd)]
64pub struct ElemId(usize);
65
66impl fmt::Display for ElemId {
67    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
68        fmt::Display::fmt(&self.0, f)
69    }
70}
71
72impl<'buf> Element<'buf> {
73    /// Create a new `Element`.
74    fn new(id: ElemId, path: PathNodeRef<'buf>, span: Span, value: Value<'buf>) -> Element<'buf> {
75        Element {
76            id,
77            path_node: path,
78            span,
79            value,
80        }
81    }
82
83    /// Return the unique Id for this `Element`.
84    pub(crate) const fn id(&self) -> ElemId {
85        self.id
86    }
87
88    /// Return the `Path` to this `Element`.
89    pub fn path(&self) -> PathRef<'buf> {
90        PathRef(self.path_node())
91    }
92
93    /// Return the `PathNode` to this `Element`.
94    pub(crate) fn path_node(&self) -> PathNodeRef<'buf> {
95        Rc::clone(&self.path_node)
96    }
97
98    /// Return the source JSON `&str` of the entire Object field if the `Element` is an Object.
99    /// Otherwise return the span of the [`Value`].
100    ///
101    /// In the case of an array like `["one", "two"]`, calling this method on the second `Element`
102    /// will return `"two"`.
103    ///
104    /// In the case of an object like `{"one": 1, "two": 2}`, calling this method on the second
105    /// `Element` will return `"\"two\": 2"`.
106    ///
107    /// # Panics
108    ///
109    /// If a source JSON is used that this `Element` didn't not originate from there is a chance
110    /// that this function will panic.
111    pub fn source_json(&self, source_json: &'buf str) -> SourceStr<'buf> {
112        if let PathNode::Object { key, .. } = *self.path_node {
113            // The span of an objects field starts from the start of the key...
114            let span = Span {
115                start: key.span().start,
116                // ... and ends at the end of the value.
117                end: self.span.end,
118            };
119            let field_str = &source_json
120                .get(span.start..span.end)
121                .expect("The disconnection between the source JSON and the `Element` will be fixed in a future PR");
122            let field = RawStr::from_str(field_str, span);
123            let (key, value) = field_str
124                .split_once(':')
125                .expect("An objects field always contains a delimiting `:`");
126
127            SourceStr::Field { field, key, value }
128        } else {
129            let span = self.span;
130            let s = source_json
131                .get(span.start..span.end)
132                .expect("The disconnection between the source JSON and the `Element` will be fixed in a future PR");
133            SourceStr::Value(RawStr::from_str(s, span))
134        }
135    }
136
137    /// Return the source JSON `&str` for the [`Value`].
138    ///
139    /// In the case of an array like `["one", "two"]`, calling this method on the second `Element`
140    /// will return `"two"`.
141    ///
142    /// In the case of an object like `{"one": 1, "two": 2}`, calling this method on the second
143    /// `Element` will return `"2"`.
144    ///
145    /// # Panics
146    ///
147    /// If a source JSON is used that this `Element` didn't not originate from there is a chance
148    /// that this function will panic.
149    pub fn source_json_value(&self, source_json: &'buf str) -> &'buf str {
150        source_json
151            .get(self.span.start..self.span.end)
152            .expect("The disconnection between the source JSON and the `Element` will be fixed in a future PR")
153    }
154
155    /// Return the `Value` of the `Element`.
156    pub(crate) fn value(&self) -> &Value<'buf> {
157        &self.value
158    }
159
160    /// Return the `&Value`.
161    pub(crate) fn as_value(&self) -> &Value<'buf> {
162        &self.value
163    }
164
165    /// Return `Some(&str)` if the `Value` is a `String`.
166    pub(crate) fn as_raw_str(&self) -> Option<&RawStr<'buf>> {
167        self.value.as_raw_str()
168    }
169
170    /// Return `Some(&[Field])` if the `Value` is a `Object`.
171    pub(crate) fn as_object_fields(&self) -> Option<&[Field<'buf>]> {
172        self.value.as_object_fields()
173    }
174
175    pub(crate) fn as_array(&self) -> Option<&[Element<'buf>]> {
176        self.value.as_array()
177    }
178
179    pub fn as_number_str(&self) -> Option<&str> {
180        self.value.as_number()
181    }
182}
183
184#[derive(Debug)]
185pub enum SourceStr<'buf> {
186    /// The source `&str` of the given [`Value`].
187    Value(RawStr<'buf>),
188
189    /// The key-value pair of the given [`Element`] where the [`PathNode`] is an referring to an object.
190    Field {
191        /// The entire field as a `&str`. This is the `&str` from the beginning of the key to the end of the value.
192        field: RawStr<'buf>,
193
194        /// The key excluding the separating `:`.
195        key: &'buf str,
196
197        /// The [`Value`] as `&str`.
198        value: &'buf str,
199    },
200}
201
202impl fmt::Display for SourceStr<'_> {
203    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
204        match self {
205            SourceStr::Value(s) => f.write_str(s.as_raw()),
206            SourceStr::Field { field, .. } => f.write_str(field.as_raw()),
207        }
208    }
209}
210
211/// The `SourceStr` can be compared with other strings just like a `String`.
212impl PartialEq<&str> for SourceStr<'_> {
213    fn eq(&self, other: &&str) -> bool {
214        match self {
215            SourceStr::Value(s) => s.as_raw() == *other,
216            SourceStr::Field { field, .. } => field.as_raw() == *other,
217        }
218    }
219}
220
221/// The `SourceStr` can be compared with other strings just like a `String`.
222impl PartialEq<String> for SourceStr<'_> {
223    fn eq(&self, other: &String) -> bool {
224        self.eq(&&**other)
225    }
226}
227
228impl PartialOrd for Element<'_> {
229    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
230        Some(self.cmp(other))
231    }
232}
233
234impl Ord for Element<'_> {
235    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
236        self.path_node.cmp(&other.path_node)
237    }
238}
239
240impl fmt::Display for Element<'_> {
241    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
242        write!(f, "{} = {}", self.path_node, self.value)
243    }
244}
245
246/// A JSON `Object`'s field that upholds the invariant that the `Element`'s `Path` is as `Object`.
247#[derive(Debug, Eq, PartialEq)]
248pub(crate) struct Field<'buf>(Element<'buf>);
249
250impl<'buf> Field<'buf> {
251    #[expect(
252        clippy::unreachable,
253        reason = "A Field is created by the parser when the type is an Object."
254    )]
255    pub(crate) fn key(&self) -> RawStr<'buf> {
256        let PathNode::Object { key, .. } = *self.0.path_node else {
257            unreachable!();
258        };
259
260        key
261    }
262
263    /// Consume the `Field` and return the inner `Element`.
264    #[expect(dead_code, reason = "pending use in `tariff::lint`")]
265    pub(crate) fn into_element(self) -> Element<'buf> {
266        self.0
267    }
268
269    /// Consume the `Field` and return the inner `Element`.
270    pub(crate) fn element(&self) -> &Element<'buf> {
271        &self.0
272    }
273}
274
275/// A JSON `Value` that borrows it's content from the source JSON `&str`.
276#[derive(Debug, Eq, PartialEq)]
277pub(crate) enum Value<'buf> {
278    /// A `"null"` value.
279    Null,
280
281    /// A `"true"` value.
282    True,
283
284    /// A `"false"` value.
285    False,
286
287    /// The value of the `String` has the quotes trimmed.
288    String(RawStr<'buf>),
289
290    /// A JSON `Number` in string format.
291    ///
292    /// The string is not guaranteed to be a valid number. Only that it's not a `null`, `bool` or `string` value.
293    /// Convert the string into the number format you want.
294    Number(&'buf str),
295
296    /// A JSON `Array` parsed into a `Vec` of `Elements`.
297    ///
298    /// The inner `Element`'s path also encodes the index.
299    /// E.g. `$.elements.2`: This path refers to third OCPI tariff element.
300    Array(Vec<Element<'buf>>),
301
302    /// A JSON `Object` where each of the fields are parsed into a `Vec` of `Elements`.
303    ///
304    /// The inner `Element`'s path encodes the fields key.
305    /// E.g. `$.elements.2.restrictions` This path referf to the `restrictions` `Object`
306    /// of the third OCPI tariff element.
307    Object(Vec<Field<'buf>>),
308}
309
310impl<'buf> Value<'buf> {
311    pub(crate) fn kind(&self) -> ValueKind {
312        match self {
313            Value::Null => ValueKind::Null,
314            Value::True | Value::False => ValueKind::Bool,
315            Value::String(_) => ValueKind::String,
316            Value::Number(_) => ValueKind::Number,
317            Value::Array(_) => ValueKind::Array,
318            Value::Object(_) => ValueKind::Object,
319        }
320    }
321
322    /// Return true if the `Value` can't contain child elements.
323    pub(crate) fn is_scalar(&self) -> bool {
324        matches!(
325            self,
326            Value::Null | Value::True | Value::False | Value::String(_) | Value::Number(_)
327        )
328    }
329
330    pub(crate) fn as_array(&self) -> Option<&[Element<'buf>]> {
331        match self {
332            Value::Array(elems) => Some(elems),
333            _ => None,
334        }
335    }
336
337    pub(crate) fn as_number(&self) -> Option<&str> {
338        match self {
339            Value::Number(s) => Some(s),
340            _ => None,
341        }
342    }
343
344    /// Return `Some(&str)` if the `Value` is a `String`.
345    pub(crate) fn as_raw_str(&self) -> Option<&RawStr<'buf>> {
346        match self {
347            Value::String(s) => Some(s),
348            _ => None,
349        }
350    }
351
352    /// Return `Some(&[Field])` if the `Value` is a `Object`.
353    pub(crate) fn as_object_fields(&self) -> Option<&[Field<'buf>]> {
354        match self {
355            Value::Object(fields) => Some(fields),
356            _ => None,
357        }
358    }
359}
360
361impl fmt::Display for Value<'_> {
362    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
363        match self {
364            Self::Null => write!(f, "null"),
365            Self::True => write!(f, "true"),
366            Self::False => write!(f, "false"),
367            Self::String(s) => write!(f, "{s}"),
368            Self::Number(s) => write!(f, "{s}"),
369            Self::Array(..) => f.write_str("[...]"),
370            Self::Object(..) => f.write_str("{...}"),
371        }
372    }
373}
374
375/// A light-weight type identity for a JSON `Value`'s content.
376#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Serialize)]
377pub enum ValueKind {
378    Null,
379    Bool,
380    Number,
381    String,
382    Array,
383    Object,
384}
385
386impl fmt::Display for ValueKind {
387    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
388        match self {
389            ValueKind::Null => write!(f, "null"),
390            ValueKind::Bool => write!(f, "bool"),
391            ValueKind::Number => write!(f, "number"),
392            ValueKind::String => write!(f, "string"),
393            ValueKind::Array => write!(f, "array"),
394            ValueKind::Object => write!(f, "object"),
395        }
396    }
397}
398
399/// Used to distinguish the type of compound object.
400///
401/// This is used to track which type of object an `Element` is in when parsing.
402#[derive(Copy, Clone, Debug, Eq, PartialEq)]
403pub(crate) enum ObjectKind {
404    Object,
405    Array,
406}
407
408type RawMap<'buf> = BTreeMap<RawStr<'buf>, Element<'buf>>;
409type RawRefMap<'a, 'buf> = BTreeMap<RawStr<'buf>, &'a Element<'buf>>;
410
411#[expect(dead_code, reason = "pending use in `tariff::lint`")]
412pub(crate) trait FieldsIntoExt<'buf> {
413    fn into_map(self) -> RawMap<'buf>;
414}
415
416pub(crate) trait FieldsAsExt<'buf> {
417    fn as_raw_map(&self) -> RawRefMap<'_, 'buf>;
418    fn find_field(&self, key: &str) -> Option<&Field<'buf>>;
419}
420
421impl<'buf> FieldsIntoExt<'buf> for Vec<Field<'buf>> {
422    fn into_map(self) -> RawMap<'buf> {
423        self.into_iter()
424            .map(|field| (field.key(), field.into_element()))
425            .collect()
426    }
427}
428
429impl<'buf> FieldsAsExt<'buf> for Vec<Field<'buf>> {
430    fn as_raw_map(&self) -> RawRefMap<'_, 'buf> {
431        self.iter()
432            .map(|field| (field.key(), field.element()))
433            .collect()
434    }
435
436    fn find_field(&self, key: &str) -> Option<&Field<'buf>> {
437        self.iter().find(|field| field.key().as_raw() == key)
438    }
439}
440
441impl<'buf> FieldsAsExt<'buf> for [Field<'buf>] {
442    fn as_raw_map(&self) -> RawRefMap<'_, 'buf> {
443        self.iter()
444            .map(|field| (field.key(), field.element()))
445            .collect()
446    }
447
448    fn find_field(&self, key: &str) -> Option<&Field<'buf>> {
449        self.iter().find(|field| field.key().as_raw() == key)
450    }
451}
452
453/// Reference to a range of bytes encompassing a single valid JSON value in the
454/// input data.
455///
456/// Use `RawValue` to store JSON for general transport around the code, as it does not
457/// allocate recursively like `Value`.
458///
459/// A `RawValue` can be used to defer parsing parts of a payload until later,
460/// or to avoid parsing it at all in the case that part of the payload just
461/// needs to be transferred verbatim into a different output object.
462///
463/// When serializing, a value of this type will retain its original formatting
464/// and will not be minified or pretty-printed.
465pub(crate) type RawValue = serde_json::value::RawValue;
466
467/// A collection of paths that were unexpected according to the schema used while parsing the JSON
468/// for an OCPI object.
469#[derive(Clone, Debug)]
470pub struct UnexpectedFields<'buf>(Vec<PathNodeRef<'buf>>);
471
472impl fmt::Display for UnexpectedFields<'_> {
473    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
474        if f.alternate() {
475            // Print each path on a newline.
476            f.write_str("[\n")?;
477            for entry in &self.0 {
478                writeln!(f, "\t\"{entry}\",")?;
479            }
480            f.write_str("]\n")?;
481        } else {
482            // Print all paths on a single line.
483            f.write_char('[')?;
484            for entry in &self.0 {
485                write!(f, "{entry},")?;
486            }
487            f.write_char(']')?;
488        }
489
490        Ok(())
491    }
492}
493
494impl<'buf> UnexpectedFields<'buf> {
495    /// Create an empty `UnexpectedFields` collection.
496    pub(crate) fn empty() -> Self {
497        Self(vec![])
498    }
499
500    /// Create an collection of `UnexpectedFields` from a `Vec`
501    pub(crate) fn from_vec(v: Vec<PathNodeRef<'buf>>) -> Self {
502        Self(v)
503    }
504
505    /// Return the field paths as a `Vec` of `String`s.
506    pub fn to_strings(&self) -> Vec<String> {
507        self.0.iter().map(ToString::to_string).collect()
508    }
509
510    /// Return the field paths as a `Vec` of `String`s.
511    pub fn into_strings(self) -> Vec<String> {
512        self.0.into_iter().map(|path| path.to_string()).collect()
513    }
514
515    /// Return true if the list of unexpected fields is empty.
516    pub fn is_empty(&self) -> bool {
517        self.0.is_empty()
518    }
519
520    /// Return the number of unexpected fields.
521    pub fn len(&self) -> usize {
522        self.0.len()
523    }
524
525    /// Return an Iterator over the unexpected fields.
526    pub fn iter<'a>(&'a self) -> UnexpectedFieldsIter<'a, 'buf> {
527        UnexpectedFieldsIter(self.0.iter())
528    }
529}
530
531impl<'buf> IntoIterator for UnexpectedFields<'buf> {
532    type Item = PathRef<'buf>;
533
534    type IntoIter = UnexpectedFieldsIntoIter<'buf>;
535
536    fn into_iter(self) -> Self::IntoIter {
537        UnexpectedFieldsIntoIter(self.0.into_iter())
538    }
539}
540
541pub struct UnexpectedFieldsIntoIter<'buf>(std::vec::IntoIter<PathNodeRef<'buf>>);
542
543impl<'buf> Iterator for UnexpectedFieldsIntoIter<'buf> {
544    type Item = PathRef<'buf>;
545
546    fn next(&mut self) -> Option<Self::Item> {
547        let path_node = self.0.next()?;
548
549        Some(PathRef(path_node))
550    }
551}
552
553impl<'a, 'buf> IntoIterator for &'a UnexpectedFields<'buf> {
554    type Item = PathRef<'buf>;
555
556    type IntoIter = UnexpectedFieldsIter<'a, 'buf>;
557
558    fn into_iter(self) -> Self::IntoIter {
559        self.iter()
560    }
561}
562
563/// An `Iterator` over each unexpected field as a `PathRef`.
564pub struct UnexpectedFieldsIter<'a, 'buf>(std::slice::Iter<'a, PathNodeRef<'buf>>);
565
566impl<'buf> Iterator for UnexpectedFieldsIter<'_, 'buf> {
567    type Item = PathRef<'buf>;
568
569    fn next(&mut self) -> Option<Self::Item> {
570        let path_node = self.0.next()?;
571
572        Some(PathRef(Rc::clone(path_node)))
573    }
574}
575
576/// A path to a JSON `Element` where the path components are borrowed from the source JSON `&str`.
577///
578/// The Display impl outputs strings like:
579///
580/// - `$` The root is represented by a dollar.
581/// - `$.object_key` Dots separate the path elements.
582/// - `$.object_key.2` Arrays are represented as integers.
583pub struct PathRef<'buf>(PathNodeRef<'buf>);
584
585impl fmt::Debug for PathRef<'_> {
586    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
587        write!(f, "{self}")
588    }
589}
590
591impl<'buf> PathRef<'buf> {
592    /// Return an [`Iterator`] over the components of this path.
593    pub fn components(&self) -> PathComponents<'buf> {
594        PathComponents(PathIter::new(Rc::clone(&self.0)))
595    }
596}
597
598/// An [`Iterator`] over the components of a path.
599pub struct PathComponents<'buf>(PathIter<'buf>);
600
601impl<'buf> Iterator for PathComponents<'buf> {
602    type Item = PathComponent<'buf>;
603
604    fn next(&mut self) -> Option<Self::Item> {
605        let path_node = self.0.next()?;
606        Some(PathComponent(path_node))
607    }
608}
609
610/// The `PathRef` can be compared with other strings just like a `String`.
611impl PartialEq<&str> for PathRef<'_> {
612    fn eq(&self, other: &&str) -> bool {
613        match_path_node(&self.0, other, |_| false)
614    }
615}
616
617/// The `PathRef` can be compared with other strings just like a `String`.
618impl PartialEq<String> for PathRef<'_> {
619    fn eq(&self, other: &String) -> bool {
620        match_path_node(&self.0, other, |_| false)
621    }
622}
623
624impl fmt::Display for PathRef<'_> {
625    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
626        fmt::Display::fmt(&self.0, f)
627    }
628}
629
630#[cfg(test)]
631mod test_path_node_matches_str {
632    use std::rc::Rc;
633
634    use crate::test;
635
636    use super::PathNode;
637
638    #[test]
639    fn should_match_path() {
640        test::setup();
641
642        let root = Rc::new(PathNode::Root);
643        let path_a = Rc::new(PathNode::Array {
644            parent: Rc::clone(&root),
645            index: 1,
646        });
647        let path_b = Rc::new(PathNode::Object {
648            parent: Rc::clone(&path_a),
649            key: r#""name""#.into(),
650        });
651        let path_c = PathNode::Object {
652            parent: Rc::clone(&path_b),
653            key: r#""gene""#.into(),
654        };
655
656        assert_eq!(*root, "$");
657        assert_eq!(*path_a, "$.1");
658        assert_eq!(*path_b, "$.1.name");
659        assert_eq!(path_c, "$.1.name.gene");
660    }
661}
662
663/// The path to a JSON `Element`.
664pub(crate) type PathNodeRef<'buf> = Rc<PathNode<'buf>>;
665
666/// A single node of a complete path.
667///
668/// Path's are structured as a linked list from the leaf of the path back to the root through the parents.
669///
670/// The Display impl of the `Path` outputs strings like:
671///
672/// - `$` The root is represented by a dollar.
673/// - `$.object_key` Dots separate the path elements.
674/// - `$.object_key.2` Arrays are represented as integers.
675#[derive(Clone, Debug, Default, Eq, PartialEq, Ord, PartialOrd)]
676pub(crate) enum PathNode<'buf> {
677    /// The root of the JSON `Element` tree.
678    #[default]
679    Root,
680    /// An `Array` element referenced by index.
681    Array {
682        parent: PathNodeRef<'buf>,
683        index: usize,
684    },
685    /// An `Object` field referenced be key value.
686    Object {
687        parent: PathNodeRef<'buf>,
688        key: RawStr<'buf>,
689    },
690}
691
692/// A light weight enum used to indicate the kind of component being visited when using the
693/// [`PathComponents`] [`Iterator`].
694pub enum PathNodeKind {
695    /// The root of the JSON `Element` tree.
696    Root,
697    /// An `Array` element referenced by index.
698    Array,
699    /// An `Object` field referenced be key value.
700    Object,
701}
702
703/// A path to a JSON `Element` where the path components are heap allocated and so do not require
704/// a lifetime back to the source JSON `&str`.
705///
706/// The Display impl outputs strings like:
707///
708/// - `$` The root is represented by a dollar.
709/// - `$.object_key` Dots separate the path elements.
710/// - `$.object_key.2` Arrays are represented as integers.
711#[derive(Clone, Debug, Eq, PartialEq, Ord, PartialOrd)]
712pub struct Path(Vec<PathPiece>);
713
714impl Path {
715    /// Create an root `Path`.
716    const fn root() -> Self {
717        Self(vec![])
718    }
719
720    /// Create an `Path` by iterating over a [`PathNode`].
721    fn from_node(path: PathNodeRef<'_>) -> Self {
722        let paths: Vec<_> = PathIter::new(path).collect();
723
724        let pieces = paths
725            .into_iter()
726            .rev()
727            .filter_map(|path_node| match *path_node {
728                PathNode::Root => None,
729                PathNode::Array { index, .. } => Some(PathPiece::Array(index)),
730                PathNode::Object { key, .. } => Some(PathPiece::Object(key.to_string())),
731            })
732            .collect();
733
734        Self(pieces)
735    }
736}
737
738/// The `Path` can be compared with other strings just like a `String`.
739impl PartialEq<&str> for Path {
740    fn eq(&self, other: &&str) -> bool {
741        match_path(self, other)
742    }
743}
744
745/// The `Path` can be compared with other strings just like a `String`.
746impl PartialEq<String> for Path {
747    fn eq(&self, other: &String) -> bool {
748        match_path(self, other)
749    }
750}
751
752impl fmt::Display for Path {
753    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
754        let iter = self.0.iter();
755
756        write!(f, "$")?;
757
758        for path in iter {
759            write!(f, ".{path}")?;
760        }
761
762        Ok(())
763    }
764}
765
766/// A piece/component of a [`Path`].
767///
768/// The `PathComponent` name is already taken and this type is private.
769#[derive(Clone, Debug, Eq, PartialEq, Ord, PartialOrd)]
770enum PathPiece {
771    /// An `Array` element referenced by index.
772    Array(usize),
773    /// An `Object` field referenced be key value.
774    Object(String),
775}
776
777impl fmt::Display for PathPiece {
778    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
779        match self {
780            PathPiece::Array(index) => write!(f, "{index}"),
781            PathPiece::Object(key) => write!(f, "{key}"),
782        }
783    }
784}
785
786/// A single component of a [`PathRef`].
787pub struct PathComponent<'buf>(PathNodeRef<'buf>);
788
789impl PathComponent<'_> {
790    /// Return the kind of component this is.
791    pub fn kind(&self) -> PathNodeKind {
792        match *self.0 {
793            PathNode::Root => PathNodeKind::Root,
794            PathNode::Array { .. } => PathNodeKind::Array,
795            PathNode::Object { .. } => PathNodeKind::Object,
796        }
797    }
798}
799
800impl fmt::Display for PathComponent<'_> {
801    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
802        match *self.0 {
803            PathNode::Root => f.write_str(PATH_ROOT),
804            PathNode::Array { index, .. } => write!(f, "{index}"),
805            PathNode::Object { key, .. } => write!(f, "{key}"),
806        }
807    }
808}
809
810impl fmt::Display for PathNode<'_> {
811    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
812        let paths: Vec<_> = PathIter::new(Rc::new(self.clone())).collect();
813        let mut iter = paths.into_iter().rev();
814
815        if f.alternate() {
816            // print out each path element as a debugging tab-stop.
817            for path in iter {
818                match *path {
819                    PathNode::Root => f.write_str("")?,
820                    PathNode::Array { .. } | PathNode::Object { .. } => f.write_str("...|")?,
821                }
822            }
823        } else {
824            if let Some(path) = iter.next() {
825                write!(f, "{}", PathComponent(path))?;
826            }
827
828            for path in iter {
829                write!(f, ".{}", PathComponent(path))?;
830            }
831        }
832        Ok(())
833    }
834}
835
836impl<'buf> PathNode<'buf> {
837    /// Returns true if the `Path` refers to the root.
838    pub(crate) fn is_root(&self) -> bool {
839        matches!(self, PathNode::Root)
840    }
841
842    /// Returns true if the `Path` refers to an `Array`.
843    pub(crate) fn is_array(&self) -> bool {
844        matches!(self, PathNode::Array { .. })
845    }
846
847    /// Return a key as `Some(&str)` if the `Path` refers to an `Object`.
848    pub(crate) fn as_object_key(&self) -> Option<&RawStr<'buf>> {
849        match self {
850            PathNode::Object { key, .. } => Some(key),
851            PathNode::Root | PathNode::Array { .. } => None,
852        }
853    }
854}
855
856/// Return true if the given `PathNode` matches the given `&str`.
857///
858/// If the `skip` function returns true, that path component is skipped.
859/// The `skip` function allows this single function to implement comparisons between `PathNode` and `&str`;
860/// and comparisons between `PathNode` and `PathGlob`.
861fn match_path_node<F>(path: &PathNode<'_>, s: &str, mut skip: F) -> bool
862where
863    F: FnMut(&str) -> bool,
864{
865    let mut parts = s.rsplit(PATH_SEPARATOR);
866    let mut paths_iter = PathIter::new(Rc::new(path.clone()));
867
868    loop {
869        let node_segment = paths_iter.next();
870        let str_segment = parts.next();
871
872        let (node_segment, str_segment) = match (node_segment, str_segment) {
873            // If we have exhausted both iterators then the `&str` is equal to the path.
874            (None, None) => return true,
875            // If either of the iters are a different size, then they don't match.
876            (None, Some(_)) | (Some(_), None) => return false,
877            // If both iters have another item, continue on to try match them.
878            (Some(a), Some(b)) => (a, b),
879        };
880
881        // If the skip function says to skip a path segment, then continue to the next segment.
882        if skip(str_segment) {
883            continue;
884        }
885
886        let yip = match *node_segment {
887            PathNode::Root => str_segment == PATH_ROOT,
888            PathNode::Array { index, .. } => {
889                let Ok(b) = str_segment.parse::<usize>() else {
890                    return false;
891                };
892
893                index == b
894            }
895            PathNode::Object { key, .. } => key.as_raw() == str_segment,
896        };
897
898        // Return false on the first mismatch.
899        if !yip {
900            return false;
901        }
902    }
903}
904
905/// Return true if the given `Path` matches the given `&str`.
906fn match_path(path: &Path, s: &str) -> bool {
907    let mut parts = s.split(PATH_SEPARATOR);
908    let mut paths_iter = path.0.iter();
909
910    let Some(str_segment) = parts.next() else {
911        return false;
912    };
913
914    // The root path segment is not explicitly stored in a `Path` so we just match the first
915    // `str` segment to the expected `$` nomenclature.
916    if str_segment != PATH_ROOT {
917        return false;
918    }
919
920    loop {
921        let node_segment = paths_iter.next();
922        let str_segment = parts.next();
923
924        let (node_segment, str_segment) = match (node_segment, str_segment) {
925            // If we have exhausted both iterators then the `&str` is equal to the path.
926            (None, None) => return true,
927            // If either of the iters are a different size, then they don't match.
928            (None, Some(_)) | (Some(_), None) => return false,
929            // If both iters have another item, continue on to try match them.
930            (Some(a), Some(b)) => (a, b),
931        };
932
933        let yip = match node_segment {
934            PathPiece::Array(index) => {
935                let Ok(b) = str_segment.parse::<usize>() else {
936                    return false;
937                };
938
939                *index == b
940            }
941            PathPiece::Object(key) => key == str_segment,
942        };
943
944        // Return false on the first mismatch.
945        if !yip {
946            return false;
947        }
948    }
949}
950
951impl PartialEq<&str> for PathNode<'_> {
952    fn eq(&self, other: &&str) -> bool {
953        match_path_node(self, other, |_| false)
954    }
955}
956
957impl PartialEq<String> for PathNode<'_> {
958    fn eq(&self, other: &String) -> bool {
959        match_path_node(self, other, |_| false)
960    }
961}
962
963/// Traverse a `Path` from the leaf to the root.
964struct PathIter<'buf> {
965    /// The root has been reached.
966    complete: bool,
967    /// The current path node to introspect when `Iterator::next` is called.
968    path: PathNodeRef<'buf>,
969}
970
971impl<'buf> PathIter<'buf> {
972    /// Create a new `PathIter` from a leaf node.
973    fn new(path: PathNodeRef<'buf>) -> Self {
974        Self {
975            complete: false,
976            path,
977        }
978    }
979}
980
981impl<'buf> Iterator for PathIter<'buf> {
982    type Item = PathNodeRef<'buf>;
983
984    fn next(&mut self) -> Option<Self::Item> {
985        if self.complete {
986            return None;
987        }
988
989        match &*self.path {
990            PathNode::Root => {
991                // The iteration is complete once we've arrived at the root node.
992                self.complete = true;
993                Some(Rc::clone(&self.path))
994            }
995            PathNode::Array { parent, .. } | PathNode::Object { parent, .. } => {
996                let next = Rc::clone(&self.path);
997                self.path = Rc::clone(parent);
998                Some(next)
999            }
1000        }
1001    }
1002}
1003
1004/// Display the expectation stack for debugging
1005struct DisplayExpectStack<'a>(&'a [schema::Expect]);
1006
1007impl fmt::Display for DisplayExpectStack<'_> {
1008    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1009        let mut iter = self.0.iter().rev();
1010        let last = iter.next();
1011
1012        // Use the `~` to represent a schema stack.
1013        f.write_str("~")?;
1014
1015        for _ in iter {
1016            f.write_str("...~")?;
1017        }
1018
1019        if let Some(exp) = last {
1020            match exp {
1021                schema::Expect::Scalar => f.write_str("~")?,
1022                schema::Expect::Array(element) => match &**element {
1023                    schema::Element::Scalar => f.write_str("~")?,
1024                    schema::Element::Array(element) => write!(f, "[{element:?}]")?,
1025                    schema::Element::Object(fields) => {
1026                        write!(f, "[{{{:}}}])", DisplayExpectFields(&**fields))?;
1027                    }
1028                },
1029                schema::Expect::Object(fields) => {
1030                    write!(f, "{{{:}}}", DisplayExpectFields(&**fields))?;
1031                }
1032                schema::Expect::UnmatchedScalar => write!(f, "unmatched(scalar)")?,
1033                schema::Expect::UnmatchedArray => write!(f, "unmatched(array)")?,
1034                schema::Expect::UnmatchedObject => write!(f, "unmatched(object)")?,
1035                schema::Expect::OutOfSchema => write!(f, "no_schema")?,
1036            }
1037        }
1038
1039        Ok(())
1040    }
1041}
1042
1043/// Display the fields of a schema expect stack level.
1044struct DisplayExpectFields<'a, V>(&'a BTreeMap<&'a str, V>);
1045
1046impl<V> fmt::Display for DisplayExpectFields<'_, V> {
1047    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1048        const MAX_FIELDS: usize = 8;
1049
1050        let mut count = 0;
1051        let mut iter = self.0.keys().peekable();
1052
1053        loop {
1054            if count >= MAX_FIELDS {
1055                f.write_str("...")?;
1056                break;
1057            }
1058
1059            let Some(field) = iter.next() else {
1060                break;
1061            };
1062
1063            count += 1;
1064            write!(f, "{field}")?;
1065
1066            let Some(_) = iter.peek() else {
1067                break;
1068            };
1069
1070            f.write_str(", ")?;
1071        }
1072
1073        Ok(())
1074    }
1075}
1076
1077#[derive(Debug)]
1078struct UnbalancedExpectStack;
1079
1080impl fmt::Display for UnbalancedExpectStack {
1081    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1082        f.write_str("unbalanced expectation stack")
1083    }
1084}
1085
1086impl std::error::Error for UnbalancedExpectStack {}
1087
1088/// Parse the JSON into a [`ParseReport`] checking the parsed [`Element`]s names against the given
1089/// [`schema`] and reporting fields that are unexpected in the [`ParseReport::unexpected_fields`].
1090pub(crate) fn parse_with_schema<'buf>(
1091    json: &'buf str,
1092    schema: &schema::Element,
1093) -> Result<ParseReport<'buf>, Error> {
1094    let parser = Parser::new(json);
1095    let mut unexpected_fields = vec![];
1096    // The current node of the schema is the last element of this vec.
1097    let mut expectation_stack = vec![schema.to_expectation()];
1098
1099    for event in parser {
1100        match event? {
1101            parser::Event::Open { kind, parent_path } => {
1102                // Take the schema expectation off the stack.
1103                // This is simpler than taking a `&mut` to the last element.
1104                let Some(expectation) = expectation_stack.pop() else {
1105                    return Err(ErrorKind::Internal(Box::new(UnbalancedExpectStack))
1106                        .into_partial_error_without_token()
1107                        .with_root_path());
1108                };
1109
1110                if tracing::enabled!(Level::DEBUG) {
1111                    match kind {
1112                        ObjectKind::Array => {
1113                            trace!("{parent_path} [ {}", DisplayExpectStack(&expectation_stack));
1114                        }
1115                        ObjectKind::Object => trace!(
1116                            "{parent_path} {{ {}",
1117                            DisplayExpectStack(&expectation_stack)
1118                        ),
1119                    }
1120                }
1121
1122                match expectation {
1123                    schema::Expect::Array(elem) => {
1124                        // If the opening element is at the root we only care if the element
1125                        // is an array or not.
1126                        if parent_path.is_root() {
1127                            let next = match kind {
1128                                ObjectKind::Array => schema::Expect::Array(elem),
1129                                ObjectKind::Object => schema::Expect::UnmatchedArray,
1130                            };
1131
1132                            expectation_stack.push(next);
1133                            trace!("{}", DisplayExpectStack(&expectation_stack));
1134                            continue;
1135                        }
1136
1137                        if !parent_path.is_array() {
1138                            expectation_stack.push(schema::Expect::UnmatchedArray);
1139                            trace!("{}", DisplayExpectStack(&expectation_stack));
1140                            continue;
1141                        }
1142
1143                        expectation_stack.push(schema::Expect::Array(Arc::clone(&elem)));
1144                        // each array element should match this expectation
1145                        expectation_stack.push(elem.to_expectation());
1146                    }
1147                    schema::Expect::Object(fields) => {
1148                        // If the opening element is at the root there is no path to inspect.
1149                        // We only care if the element is an object or not.
1150                        if parent_path.is_root() {
1151                            let next = match kind {
1152                                ObjectKind::Array => schema::Expect::UnmatchedObject,
1153                                ObjectKind::Object => schema::Expect::Object(fields),
1154                            };
1155
1156                            expectation_stack.push(next);
1157                            trace!("{}", DisplayExpectStack(&expectation_stack));
1158                            continue;
1159                        }
1160                        let Some(key) = parent_path.as_object_key() else {
1161                            expectation_stack.push(schema::Expect::UnmatchedObject);
1162                            trace!("{}", DisplayExpectStack(&expectation_stack));
1163                            continue;
1164                        };
1165
1166                        let next = if let Some(elem) = fields.get(key.as_raw()) {
1167                            open_object(kind, elem.as_ref())
1168                        } else {
1169                            unexpected_fields.push(parent_path);
1170                            schema::Expect::OutOfSchema
1171                        };
1172
1173                        expectation_stack.push(schema::Expect::Object(fields));
1174                        expectation_stack.push(next);
1175                    }
1176                    schema::Expect::OutOfSchema => {
1177                        // If we're already outside of the schema we put that back on the stack
1178                        // and add a new one for the object that just opened.
1179                        //
1180                        // We need to keep track of object level even though the schema expectations
1181                        // have been exhausted, as we'll pop these placeholder `OutOfSchema`s
1182                        // off the stack when the object has closed so we land on the correct
1183                        // schema again.
1184                        expectation_stack.push(expectation);
1185                        expectation_stack.push(schema::Expect::OutOfSchema);
1186                    }
1187                    schema::Expect::UnmatchedArray | schema::Expect::UnmatchedObject => {
1188                        expectation_stack.push(expectation);
1189                        expectation_stack.push(schema::Expect::OutOfSchema);
1190                    }
1191                    _ => {
1192                        expectation_stack.push(expectation);
1193                    }
1194                }
1195
1196                trace!("{}", DisplayExpectStack(&expectation_stack));
1197            }
1198            parser::Event::Element { kind, parent_path } => {
1199                // Take the schema expectation off the stack.
1200                // This is simpler than taking a `&mut` to the last element.
1201                let Some(expectation) = expectation_stack.pop() else {
1202                    return Err(ErrorKind::Internal(Box::new(UnbalancedExpectStack))
1203                        .into_partial_error_without_token()
1204                        .with_root_path());
1205                };
1206
1207                // An `Element` of kind `Array` or `Object` means the `Element` is closed
1208                // and has completed construction. The expectation can remain off the stack.
1209                if let ValueKind::Array | ValueKind::Object = kind {
1210                    if tracing::enabled!(Level::DEBUG) {
1211                        match kind {
1212                            ValueKind::Array => {
1213                                trace!(
1214                                    "{parent_path} ] {}",
1215                                    DisplayExpectStack(&expectation_stack)
1216                                );
1217                            }
1218                            ValueKind::Object => trace!(
1219                                "{parent_path} }} {}",
1220                                DisplayExpectStack(&expectation_stack)
1221                            ),
1222                            _ => (),
1223                        }
1224                    }
1225                    continue;
1226                }
1227
1228                match expectation {
1229                    #[expect(
1230                        clippy::unreachable,
1231                        reason = "The parser only emits an `Event::Complete` for a scalar object at the root"
1232                    )]
1233                    schema::Expect::Object(fields) => match &*parent_path {
1234                        PathNode::Root => unreachable!(),
1235                        PathNode::Array { .. } => {
1236                            expectation_stack.push(schema::Expect::UnmatchedObject);
1237                        }
1238                        PathNode::Object { parent, key } => {
1239                            trace!("{parent:#}.{key}");
1240
1241                            if !fields.contains_key(key.as_raw()) {
1242                                unexpected_fields.push(parent_path);
1243                            }
1244
1245                            expectation_stack.push(schema::Expect::Object(fields));
1246                        }
1247                    },
1248                    schema::Expect::OutOfSchema => {
1249                        unexpected_fields.push(parent_path);
1250                        expectation_stack.push(expectation);
1251                    }
1252                    _ => {
1253                        expectation_stack.push(expectation);
1254                    }
1255                }
1256            }
1257            parser::Event::Complete(element) => {
1258                if element.value().is_scalar() {
1259                    unexpected_fields.push(element.path_node());
1260                }
1261
1262                // Parsing the JSON is complete.
1263                // Return the `Element` and the unexpected fields collected during parsing
1264                return Ok(ParseReport {
1265                    element,
1266                    unexpected_fields: UnexpectedFields::from_vec(unexpected_fields),
1267                });
1268            }
1269        }
1270    }
1271
1272    Err(ErrorKind::UnexpectedEOF
1273        .into_partial_error_without_token()
1274        .with_root_path())
1275}
1276
1277fn open_object(kind: ObjectKind, elem: Option<&Arc<schema::Element>>) -> schema::Expect {
1278    let Some(schema) = elem else {
1279        return schema::Expect::OutOfSchema;
1280    };
1281
1282    match (kind, &**schema) {
1283        (ObjectKind::Object | ObjectKind::Array, schema::Element::Scalar) => {
1284            schema::Expect::UnmatchedScalar
1285        }
1286        (ObjectKind::Object, schema::Element::Array(_)) => schema::Expect::UnmatchedArray,
1287        (ObjectKind::Object, schema::Element::Object(fields)) => {
1288            schema::Expect::Object(Arc::clone(fields))
1289        }
1290        (ObjectKind::Array, schema::Element::Array(element)) => {
1291            schema::Expect::Array(Arc::clone(element))
1292        }
1293        (ObjectKind::Array, schema::Element::Object(_)) => schema::Expect::UnmatchedObject,
1294    }
1295}
1296
1297/// The output of the `parse_with_schema` function where the parsed JSON `Element` is returned
1298/// along with a list of fields that the schema did not define.
1299#[derive(Debug)]
1300pub(crate) struct ParseReport<'buf> {
1301    /// The root JSON [`Element`].
1302    pub element: Element<'buf>,
1303
1304    /// A list of fields that were not expected: The schema did not define them.
1305    pub unexpected_fields: UnexpectedFields<'buf>,
1306}
1307
1308#[cfg(test)]
1309pub mod test {
1310    #![allow(clippy::missing_panics_doc, reason = "tests are allowed to panic")]
1311    #![allow(clippy::panic, reason = "tests are allowed panic")]
1312
1313    use std::borrow::Cow;
1314
1315    use crate::json::match_path_node;
1316
1317    use super::{
1318        parser::Span, walk::DepthFirst, ElemId, Element, Field, FieldsAsExt as _, PathNode,
1319        PathNodeRef, PathRef, RawStr, UnexpectedFields, Value,
1320    };
1321
1322    impl<'buf> Element<'buf> {
1323        /// Return the `Span` of the `Element`'s `&str` is the source JSON.
1324        pub fn span(&self) -> Span {
1325            self.span
1326        }
1327
1328        /// Consume the `Element` and return only the `Value`.
1329        pub(crate) fn into_value(self) -> Value<'buf> {
1330            self.value
1331        }
1332
1333        /// Consume the `Element` and return the `Path`, `Span` and `Value` as a tuple.
1334        pub(crate) fn into_parts(self) -> (ElemId, PathNodeRef<'buf>, Span, Value<'buf>) {
1335            let Self {
1336                id,
1337                path_node: path,
1338                span,
1339                value,
1340            } = self;
1341            (id, path, span, value)
1342        }
1343
1344        pub(crate) fn find_field(&self, key: &str) -> Option<&Field<'buf>> {
1345            self.as_object_fields()
1346                .and_then(|fields| fields.find_field(key))
1347        }
1348    }
1349
1350    impl<'buf> Value<'buf> {
1351        /// Return true if the `Value` is an `Array`.
1352        pub(crate) fn is_array(&self) -> bool {
1353            matches!(self, Value::Array(_))
1354        }
1355
1356        /// Return true if the `Value` is an `Object`.
1357        pub(crate) fn is_object(&self) -> bool {
1358            matches!(self, Value::Object(_))
1359        }
1360
1361        pub(crate) fn as_string(&self) -> Option<&RawStr<'buf>> {
1362            match self {
1363                Value::String(s) => Some(s),
1364                _ => None,
1365            }
1366        }
1367    }
1368
1369    impl<'buf> Field<'buf> {
1370        pub fn id(&self) -> ElemId {
1371            self.0.id()
1372        }
1373
1374        pub fn into_parts(self) -> (ElemId, PathNodeRef<'buf>, Span, Value<'buf>) {
1375            self.0.into_parts()
1376        }
1377    }
1378
1379    impl<'buf> UnexpectedFields<'buf> {
1380        /// The tests need to assert against the contents.
1381        pub(crate) fn into_inner(self) -> Vec<PathNodeRef<'buf>> {
1382            self.0
1383        }
1384
1385        /// Filter off the fields that match the glob.
1386        pub(crate) fn filter_matches(&mut self, glob: &PathGlob<'_>) {
1387            self.0.retain(|path| !glob.matches(path));
1388        }
1389    }
1390
1391    /// A string based `Path` that can contain glob `*` patterns in place of a literal path element.
1392    /// The glob means that the path section can be any valid section.
1393    #[derive(Debug)]
1394    pub(crate) struct PathGlob<'a>(Cow<'a, str>);
1395
1396    impl PathGlob<'_> {
1397        /// Return true if this `PathGlob` matches the given `PathNode`.
1398        pub(crate) fn matches(&self, path: &PathNode<'_>) -> bool {
1399            const WILDCARD: &str = "*";
1400
1401            match_path_node(path, &self.0, |s| {
1402                // if the `PathGlob` segment is a glob, then continue to the next segment.
1403                s == WILDCARD
1404            })
1405        }
1406    }
1407
1408    /// The tests need to assert against literal `ElemId`s.
1409    impl From<usize> for ElemId {
1410        fn from(value: usize) -> Self {
1411            Self(value)
1412        }
1413    }
1414
1415    impl<'a> From<&'a str> for PathGlob<'a> {
1416        fn from(s: &'a str) -> Self {
1417            Self(s.into())
1418        }
1419    }
1420
1421    impl From<String> for PathGlob<'_> {
1422        fn from(s: String) -> Self {
1423            Self(s.into())
1424        }
1425    }
1426
1427    impl<'de, 'buf> serde::Deserialize<'de> for PathGlob<'buf> {
1428        fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
1429        where
1430            D: ::serde::Deserializer<'de>,
1431        {
1432            let s = <Cow<'buf, str> as ::serde::Deserialize>::deserialize(deserializer)?;
1433            Ok(Self(s))
1434        }
1435    }
1436
1437    /// A map of `Element`s referenced by their unique Id.
1438    pub struct ElementMap<'a, 'bin>(Vec<&'a Element<'bin>>);
1439
1440    impl<'a, 'bin> ElementMap<'a, 'bin> {
1441        /// Create a new `ElementMap` by traversing the `Element` tree from the given node.
1442        pub fn for_elem(root: &'a Element<'bin>) -> Self {
1443            // The walker will emit `Element`s ordered by their Id.
1444            let walker = DepthFirst::new(root);
1445            Self(walker.collect())
1446        }
1447
1448        /// Return the `Element` with the given id.
1449        pub fn get(&self, id: ElemId) -> &Element<'bin> {
1450            self.0.get(id.0).map(|e| &**e).unwrap()
1451        }
1452
1453        /// Return the `Path` of the `Element` with the given id.
1454        pub fn path(&self, id: ElemId) -> PathRef<'bin> {
1455            self.0.get(id.0).map(|elem| elem.path()).unwrap()
1456        }
1457    }
1458
1459    #[cfg(test)]
1460    mod test_path_matches_glob {
1461        use std::rc::Rc;
1462
1463        use crate::test;
1464
1465        use super::{PathGlob, PathNode};
1466
1467        #[test]
1468        fn should_match_path() {
1469            test::setup();
1470
1471            let root = Rc::new(PathNode::Root);
1472            let path_a = Rc::new(PathNode::Array {
1473                parent: Rc::clone(&root),
1474                index: 1,
1475            });
1476            let path_b = Rc::new(PathNode::Object {
1477                parent: Rc::clone(&path_a),
1478                key: r#""name""#.into(),
1479            });
1480            let path_c = PathNode::Object {
1481                parent: Rc::clone(&path_b),
1482                key: r#""gene""#.into(),
1483            };
1484
1485            assert!(PathGlob::from("$").matches(&root));
1486            assert!(PathGlob::from("*").matches(&root));
1487
1488            assert!(!PathGlob::from("*").matches(&path_a));
1489            assert!(PathGlob::from("*.*").matches(&path_a));
1490            assert!(PathGlob::from("$.*").matches(&path_a));
1491            assert!(PathGlob::from("$.1").matches(&path_a));
1492
1493            assert!(!PathGlob::from("*").matches(&path_b));
1494            assert!(!PathGlob::from("*.*").matches(&path_b));
1495            assert!(PathGlob::from("*.*.*").matches(&path_b));
1496            assert!(PathGlob::from("$.*.*").matches(&path_b));
1497            assert!(PathGlob::from("$.1.*").matches(&path_b));
1498            assert!(PathGlob::from("$.*.name").matches(&path_b));
1499            assert!(PathGlob::from("$.1.name").matches(&path_b));
1500
1501            assert!(PathGlob::from("$.1.name.gene").matches(&path_c));
1502        }
1503    }
1504}
1505
1506#[cfg(test)]
1507mod test_path {
1508    use super::{Path, PathPiece};
1509
1510    #[test]
1511    fn path_should_cmp_with_str() {
1512        assert_ne!(Path::root(), "");
1513        assert_eq!(Path::root(), "$");
1514        assert_eq!(Path(vec![PathPiece::Object("field_a".into())]), "$.field_a");
1515        assert_eq!(Path(vec![PathPiece::Array(1)]), "$.1");
1516        assert_eq!(
1517            Path(vec![
1518                PathPiece::Object("field_a".into()),
1519                PathPiece::Array(1)
1520            ]),
1521            "$.field_a.1"
1522        );
1523    }
1524
1525    #[test]
1526    fn path_should_display() {
1527        assert_eq!(Path::root().to_string(), "$");
1528        assert_eq!(
1529            Path(vec![PathPiece::Object("field_a".into())]).to_string(),
1530            "$.field_a"
1531        );
1532        assert_eq!(Path(vec![PathPiece::Array(1)]).to_string(), "$.1");
1533        assert_eq!(
1534            Path(vec![
1535                PathPiece::Object("field_a".into()),
1536                PathPiece::Array(1)
1537            ])
1538            .to_string(),
1539            "$.field_a.1"
1540        );
1541    }
1542}
1543
1544#[cfg(test)]
1545mod test_parse_with_schema {
1546    use crate::{json_schema, test};
1547
1548    use super::{parse_with_schema, ParseReport};
1549
1550    #[test]
1551    fn should_report_unexpected_fields_for_root_element() {
1552        const JSON: &str = "null";
1553
1554        test::setup();
1555
1556        let schema = json_schema!({
1557            "id",
1558            "currency",
1559        });
1560
1561        let report = parse_with_schema(JSON, &schema).unwrap();
1562        let ParseReport {
1563            element: _,
1564            unexpected_fields,
1565        } = report;
1566
1567        {
1568            let [field_a] = unexpected_fields.into_inner().try_into().unwrap();
1569            assert_eq!(*field_a, "$");
1570        }
1571    }
1572
1573    #[test]
1574    fn should_report_unexpected_fields_in_flat_object() {
1575        const JSON: &str = r#"{
1576    "id": "tariff_id",
1577    "currency": "EUR",
1578    "name": "Barry",
1579    "address": "Barrystown"
1580}"#;
1581
1582        test::setup();
1583
1584        let schema = json_schema!({
1585            "id",
1586            "currency",
1587        });
1588
1589        let report = parse_with_schema(JSON, &schema).unwrap();
1590        let ParseReport {
1591            element: _,
1592            unexpected_fields,
1593        } = report;
1594
1595        {
1596            let [field_a, field_b] = unexpected_fields.into_inner().try_into().unwrap();
1597            assert_eq!(*field_a, "$.name");
1598            assert_eq!(*field_b, "$.address");
1599        }
1600    }
1601
1602    #[test]
1603    fn should_report_unexpected_fields_in_nested_object() {
1604        const JSON: &str = r#"{
1605    "id": "tariff_id",
1606    "currency": "EUR",
1607    "owner": {
1608        "id": "456856",
1609        "subscription_id": "tedi4568",
1610        "name": "Barry",
1611        "address": "Barrystown"
1612    }
1613}"#;
1614
1615        test::setup();
1616
1617        let schema = json_schema!({
1618            "id",
1619            "currency",
1620            "owner": {
1621                "id",
1622                "subscription_id"
1623            }
1624        });
1625
1626        let report = parse_with_schema(JSON, &schema).unwrap();
1627        let ParseReport {
1628            element: _,
1629            unexpected_fields,
1630        } = report;
1631
1632        {
1633            let [field_a, field_b] = unexpected_fields.into_inner().try_into().unwrap();
1634            assert_eq!(*field_a, "$.owner.name");
1635            assert_eq!(*field_b, "$.owner.address");
1636        }
1637    }
1638
1639    #[test]
1640    fn should_parse_nested_object_out_of_schema() {
1641        const JSON: &str = r#"{
1642    "id": "tariff_id",
1643    "owner": {
1644        "id": "456856",
1645        "subscription_id": "tedi4568",
1646        "name": "Barry",
1647        "address": {
1648            "city": "Barrystown",
1649            "street": "Barrysstreet"
1650        }
1651    },
1652    "currency": "EUR",
1653    "country": "NL"
1654}"#;
1655
1656        test::setup();
1657
1658        let schema = json_schema!({
1659            "id",
1660            "currency",
1661            "owner"
1662        });
1663
1664        let report = parse_with_schema(JSON, &schema).unwrap();
1665        let ParseReport {
1666            element: _,
1667            unexpected_fields,
1668        } = report;
1669
1670        {
1671            let [field_a, field_b, field_c, field_d, field_e, field_f] =
1672                unexpected_fields.into_inner().try_into().unwrap();
1673            assert_eq!(*field_a, "$.owner.id");
1674            assert_eq!(*field_b, "$.owner.subscription_id");
1675            assert_eq!(*field_c, "$.owner.name");
1676            assert_eq!(*field_d, "$.owner.address.city");
1677            assert_eq!(*field_e, "$.owner.address.street");
1678            assert_eq!(*field_f, "$.country");
1679        }
1680    }
1681
1682    #[test]
1683    fn should_report_unexpected_fields_in_array_with_nested_object() {
1684        const JSON: &str = r#"{
1685    "id": "tariff_id",
1686    "currency": "EUR",
1687    "elements": [{
1688        "id": "456856",
1689        "subscription_id": "tedi4568",
1690        "name": "Barry",
1691        "address": "Barrystown"
1692    }]
1693}"#;
1694
1695        test::setup();
1696
1697        let schema = json_schema!({
1698            "id",
1699            "currency",
1700            "elements": [{
1701                "id",
1702                "subscription_id"
1703            }]
1704        });
1705
1706        let report = parse_with_schema(JSON, &schema).unwrap();
1707        let ParseReport {
1708            element: _,
1709            unexpected_fields,
1710        } = report;
1711
1712        {
1713            let [field_a, field_b] = unexpected_fields.into_inner().try_into().unwrap();
1714            assert_eq!(*field_a, "$.elements.0.name");
1715            assert_eq!(*field_b, "$.elements.0.address");
1716        }
1717    }
1718
1719    #[test]
1720    fn should_report_unexpected_fields_in_array_of_nested_objects() {
1721        const JSON: &str = r#"{
1722    "id": "tariff_id",
1723    "currency": "EUR",
1724    "elements": [
1725        {
1726            "id": "456856",
1727            "subscription_id": "tedi4568",
1728            "name": "Barry",
1729            "address": "Barrystown"
1730        },
1731        {
1732            "id": "8746we",
1733            "subscription_id": "dfr345",
1734            "name": "Gerry",
1735            "address": "Gerrystown"
1736        }
1737    ]
1738}"#;
1739
1740        test::setup();
1741
1742        let schema = json_schema!({
1743            "id",
1744            "currency",
1745            "elements": [{
1746                "id",
1747                "subscription_id"
1748            }]
1749        });
1750
1751        let report = parse_with_schema(JSON, &schema).unwrap();
1752        let ParseReport {
1753            element: _,
1754            unexpected_fields,
1755        } = report;
1756
1757        {
1758            let [field_a, field_b, field_c, field_d] =
1759                unexpected_fields.into_inner().try_into().unwrap();
1760            assert_eq!(*field_a, "$.elements.0.name");
1761            assert_eq!(*field_b, "$.elements.0.address");
1762            assert_eq!(*field_c, "$.elements.1.name");
1763            assert_eq!(*field_d, "$.elements.1.address");
1764        }
1765    }
1766
1767    #[test]
1768    fn should_report_unexpected_fields_in_array_of_objects() {
1769        const JSON: &str = r#"[
1770    {
1771        "id": "456856",
1772        "subscription_id": "tedi4568",
1773        "name": "Barry",
1774        "address": "Barrystown"
1775    },
1776    {
1777        "id": "8746we",
1778        "subscription_id": "dfr345",
1779        "name": "Gerry",
1780        "address": "Gerrystown"
1781    }
1782]"#;
1783
1784        test::setup();
1785
1786        let schema = json_schema!([
1787            {
1788                "id",
1789                "subscription_id"
1790            }
1791        ]);
1792
1793        let report = parse_with_schema(JSON, &schema).unwrap();
1794        let ParseReport {
1795            element: _,
1796            unexpected_fields,
1797        } = report;
1798
1799        {
1800            let [field_a, field_b, field_c, field_d] =
1801                unexpected_fields.into_inner().try_into().unwrap();
1802            assert_eq!(*field_a, "$.0.name");
1803            assert_eq!(*field_b, "$.0.address");
1804            assert_eq!(*field_c, "$.1.name");
1805            assert_eq!(*field_d, "$.1.address");
1806        }
1807    }
1808}
1809
1810#[cfg(test)]
1811mod test_source_json {
1812    use super::{parse, walk};
1813
1814    #[test]
1815    fn should_resolve_to_source_json() {
1816        const JSON: &str = r#"{
1817    "name": "David Byrne",
1818    "hobbies": ["song writing", "thinking about society"]
1819}"#;
1820
1821        let element = parse(JSON).unwrap();
1822
1823        let mut walk = walk::DepthFirst::new(&element);
1824
1825        let root = walk.next().unwrap();
1826        assert_eq!(root.source_json(JSON), JSON);
1827
1828        let field_name = walk.next().unwrap();
1829        assert_eq!(field_name.source_json(JSON), r#""name": "David Byrne""#);
1830        assert_eq!(field_name.source_json_value(JSON), r#""David Byrne""#);
1831
1832        let field_hobbies = walk.next().unwrap();
1833        assert_eq!(
1834            field_hobbies.source_json(JSON),
1835            r#""hobbies": ["song writing", "thinking about society"]"#
1836        );
1837        assert_eq!(
1838            field_hobbies.source_json_value(JSON),
1839            r#"["song writing", "thinking about society"]"#
1840        );
1841
1842        let hobbies_one = walk.next().unwrap();
1843        assert_eq!(hobbies_one.source_json(JSON), r#""song writing""#);
1844        assert_eq!(hobbies_one.source_json_value(JSON), r#""song writing""#);
1845
1846        let hobbies_two = walk.next().unwrap();
1847        assert_eq!(hobbies_two.source_json(JSON), r#""thinking about society""#);
1848        assert_eq!(
1849            hobbies_two.source_json_value(JSON),
1850            r#""thinking about society""#
1851        );
1852    }
1853}
1854
1855#[cfg(test)]
1856mod test_path_node {
1857    use std::rc::Rc;
1858
1859    use super::{
1860        parser::{RawStr, Token, TokenType},
1861        PathNode, Span,
1862    };
1863
1864    #[test]
1865    fn should_display_path() {
1866        let root = Rc::new(PathNode::Root);
1867        let path_a = Rc::new(PathNode::Array {
1868            parent: Rc::clone(&root),
1869            index: 1,
1870        });
1871        let path_b = Rc::new(PathNode::Object {
1872            parent: Rc::clone(&path_a),
1873            key: r#""name""#.into(),
1874        });
1875        let path_c = Rc::new(PathNode::Object {
1876            parent: Rc::clone(&path_b),
1877            key: r#""gene""#.into(),
1878        });
1879
1880        assert_eq!(*root, "$");
1881        assert_eq!(*path_a, "$.1");
1882        assert_eq!(*path_b, "$.1.name");
1883        assert_eq!(*path_c, "$.1.name.gene");
1884    }
1885
1886    impl<'buf> From<&'buf str> for RawStr<'buf> {
1887        #[track_caller]
1888        fn from(s: &'buf str) -> Self {
1889            RawStr::from_quoted_str(
1890                s,
1891                Token {
1892                    kind: TokenType::String,
1893                    span: Span::default(),
1894                },
1895            )
1896            .unwrap()
1897        }
1898    }
1899}
1900
1901#[cfg(test)]
1902mod test_raw_json {
1903    use std::{borrow::Cow, rc::Rc};
1904
1905    use serde::{de::IntoDeserializer, Deserialize};
1906
1907    use super::{ElemId, Element, PathNode, RawValue, Span, Value, ValueKind};
1908    use crate::json::decode::unescape_str;
1909
1910    const TITLE: &str = "همّا مين واحنا مين (Who Are They and Who Are We?)";
1911
1912    /// Extends a `RawValue` with methods that:
1913    ///
1914    /// - Convert a `RawValue` into a `Value`.
1915    /// - Convert a `RawValue` into a `RawObject`.
1916    /// - Identifies the type of the JSON value in the `RawValue`.
1917    pub(crate) trait RawValueExt {
1918        fn kind(&self) -> ValueKind;
1919
1920        fn is_string(&self) -> bool;
1921
1922        /// Return Some(&str) if the value is a JSON string.
1923        ///
1924        /// The surrounding quotes will be trimmed from the JSON string.
1925        fn as_str(&self) -> Option<Cow<'_, str>>;
1926    }
1927
1928    impl RawValueExt for RawValue {
1929        fn kind(&self) -> ValueKind {
1930            let s = self.get();
1931            let first = s
1932                .as_bytes()
1933                .first()
1934                .expect("A RawValue can`t be an empty string, it has to contain a JSON value");
1935
1936            // If whitespace has been removed from a JSON value and we know `serde` has already
1937            // validated the value. Then the only possible set of chars that can come next `[0-9]` or `[-nt"[{]`.
1938            //
1939            // * See: <https://www.json.org/json-en.html>
1940            //
1941            // `RawValue` has whitespace stripped so we know the first char is non-whitespace.
1942            // See: `test_raw_json::should_fail_to_parse_whitespace_only_string_as_json` and
1943            // `test_raw_json::should_identify_whitespace_surrounded_value_as_array`.
1944            match *first {
1945                b'n' => ValueKind::Null,
1946                b't' | b'f' => ValueKind::Bool,
1947                b'"' => ValueKind::String,
1948                b'[' => ValueKind::Array,
1949                b'{' => ValueKind::Object,
1950                // A `RawValue` is already known to be valid, the only other possibility for valid JSON
1951                // is that this is a number
1952                _ => ValueKind::Number,
1953            }
1954        }
1955
1956        fn is_string(&self) -> bool {
1957            matches!(self.kind(), ValueKind::String)
1958        }
1959
1960        fn as_str(&self) -> Option<Cow<'_, str>> {
1961            if !self.is_string() {
1962                return None;
1963            }
1964
1965            let s = self.get().trim_matches('"');
1966            // This is a dummy element used to satisfy the `Warning` system used by the `decode` mod.
1967            // This hack will not be needed when the pricer uses the new parser.
1968            let elem = Element {
1969                id: ElemId(0),
1970                path_node: Rc::new(PathNode::Root),
1971                span: Span::default(),
1972                value: Value::Null,
1973            };
1974            let (s, _warnings) = unescape_str(s, &elem).into_parts();
1975            Some(s)
1976        }
1977    }
1978
1979    #[test]
1980    fn should_fail_to_parse_whitespace_only_string_as_json() {
1981        const JSON: &str = "  ";
1982        let err = serde_json::from_str::<&RawValue>(JSON).unwrap_err();
1983
1984        assert_eq!(
1985            err.classify(),
1986            serde_json::error::Category::Eof,
1987            "A JSON string can't be empty"
1988        );
1989
1990        let err = RawValue::from_string(JSON.to_string()).unwrap_err();
1991
1992        assert_eq!(
1993            err.classify(),
1994            serde_json::error::Category::Eof,
1995            "A JSON string can't be empty"
1996        );
1997    }
1998
1999    #[test]
2000    fn should_validate_json_without_allocating_for_each_token() {
2001        #[derive(Deserialize)]
2002        struct Song {
2003            title: String,
2004        }
2005
2006        let json = format!(r#"{{ "title": "{TITLE}" }}"#);
2007
2008        // If you need to simply validate json then you can deserialize to `&RawValue` or
2009        // `Box<RawValue>`. The given `String` will be parsed as JSON and the bytes returned
2010        // wrapped in a `RawValue`.
2011        //
2012        // `RawValue` asserts that the bytes are valid JSON encoded as UTF8. It is a wrapper
2013        // around `str` and is therefore unsized.
2014        //
2015        // Use a `Box<RawValue>` to store an owned `RawValue`.
2016        // This will copy/allocate the source bytes to the heap.
2017        let json: Box<RawValue> = serde_json::from_str(&json).unwrap();
2018
2019        // If you want to parse the `RawValue` into a Rust data type the `str` must be extracted
2020        // and the bytes parsed anew. This is the cost of not annotating the source `String`
2021        // with any structural markers. But parsing JSON is a quick operation compared to
2022        // recursive allocation.
2023        let song = Song::deserialize(json.into_deserializer()).unwrap();
2024
2025        assert_eq!(song.title, TITLE);
2026    }
2027
2028    #[test]
2029    fn should_compare_raw_title_correctly() {
2030        #[derive(Deserialize)]
2031        struct Song<'a> {
2032            #[serde(borrow)]
2033            title: &'a RawValue,
2034        }
2035
2036        let json = format!(r#"{{ "title": "{TITLE}" }}"#);
2037        let song: Song<'_> = serde_json::from_str(&json).unwrap();
2038
2039        assert_ne!(
2040            song.title.get(),
2041            TITLE,
2042            "The raw `title` field contains the delimiting '\"' and so is technically not directly equal to the `TITLE` const"
2043        );
2044
2045        let title = song.title.as_str().unwrap();
2046
2047        assert_eq!(
2048            title, TITLE,
2049            "When the quotes are removed the `title` field is the same as the `TITLE` const"
2050        );
2051    }
2052
2053    #[test]
2054    fn should_fail_to_parse_invalid_json() {
2055        const JSON: &str = r#"{ "title": }"#;
2056
2057        let err = serde_json::from_str::<Box<RawValue>>(JSON).unwrap_err();
2058
2059        assert_eq!(
2060            err.classify(),
2061            serde_json::error::Category::Syntax,
2062            "The bytes contained within `RawValue` are valid JSON"
2063        );
2064    }
2065
2066    #[test]
2067    fn should_parse_raw_json_to_rust_struct() {
2068        /// A Song where the `title` field is copied onto the heap.
2069        #[derive(Deserialize)]
2070        struct Song {
2071            title: String,
2072        }
2073
2074        /// A Song with the original JSON stored alongside on the heap.
2075        struct SongMessage {
2076            song: Song,
2077            original: Box<RawValue>,
2078        }
2079
2080        // This is the first heap allocation in this test.
2081        let json = format!(r#"{{ "title": "{TITLE}" }}"#);
2082
2083        // This is the second heap allocation in this test.
2084        let raw_json: Box<RawValue> = serde_json::from_str(&json)
2085            .expect("Typically we want to parse some JSON from an endpoint first");
2086        // This (`title: String`) is the third heap allocation in this test.
2087        let song = Song::deserialize(raw_json.into_deserializer()).expect("And then introspect it");
2088
2089        let message = SongMessage {
2090            song,
2091            original: raw_json,
2092        };
2093
2094        assert_eq!(
2095            message.song.title, TITLE,
2096            "The title is a normal `String` and so can be directly compared"
2097        );
2098        assert_eq!(
2099            message.original.get(),
2100            &json,
2101            "The original has not been modified in any way"
2102        );
2103    }
2104
2105    #[test]
2106    fn should_parse_borrowed_raw_json_to_rust_struct() {
2107        /// A Song where the `title` field is borrowed from the original JSON String.
2108        #[derive(Deserialize)]
2109        struct Song<'a> {
2110            title: &'a str,
2111        }
2112
2113        /// A Song with the original JSON stored alongside.
2114        ///
2115        /// Where all fields are borrowed.
2116        struct SongMessage<'a> {
2117            song: Song<'a>,
2118            original: &'a RawValue,
2119        }
2120
2121        // This is the only heap allocation in this test.
2122        let json = format!(r#"{{ "title": "{TITLE}" }}"#);
2123
2124        // The JSON bytes contained in the original String are borrowed to the `RawValue(str)`.
2125        let raw_json: &RawValue = serde_json::from_str(&json)
2126            .expect("Typically we want to parse some JSON from an endpoint first");
2127        // The bytes borrowed to the `RawValue` are in turn, borrowed to `Song::title`.
2128        let song =
2129            Song::<'_>::deserialize(raw_json.into_deserializer()).expect("And then introspect it");
2130        // The original JSON bytes are borrowed to the `SongMessage::original` field.
2131        let message = SongMessage {
2132            song,
2133            original: raw_json,
2134        };
2135
2136        assert_eq!(
2137            message.song.title, TITLE,
2138            "The title is a normal `&str` and so can be directly compared"
2139        );
2140        assert_eq!(
2141            message.original.get(),
2142            &json,
2143            "The original has not been modified in any way"
2144        );
2145    }
2146
2147    #[test]
2148    fn should_deser_number_as_i64() {
2149        const JSON: &str = "123";
2150        let json: &RawValue = serde_json::from_str(JSON).unwrap();
2151
2152        let n = i64::deserialize(json.into_deserializer()).unwrap();
2153
2154        assert_eq!(n, 123);
2155    }
2156
2157    #[test]
2158    fn should_convert_json_string_to_str() {
2159        /// A Song where the `title` field is borrowed from the original JSON String.
2160        #[derive(Deserialize)]
2161        struct Song<'a> {
2162            title: &'a str,
2163        }
2164
2165        /// A Song with the original JSON stored alongside.
2166        ///
2167        /// Where all fields are borrowed.
2168        struct SongMessage<'a> {
2169            song: Song<'a>,
2170            original: &'a RawValue,
2171        }
2172
2173        // This is the only heap allocation in this test.
2174        let json = format!(r#"{{ "title": "{TITLE}" }}"#);
2175
2176        // The JSON bytes contained in the original String are borrowed to the `RawValue(str)`.
2177        let raw_json: &RawValue = serde_json::from_str(&json)
2178            .expect("Typically we want to parse some JSON from an endpoint first");
2179        // The bytes borrowed to the `RawValue` are in turn, borrowed to `Song::title`.
2180        let song =
2181            Song::<'_>::deserialize(raw_json.into_deserializer()).expect("And then introspect it");
2182        // The original JSON bytes are borrowed to the `SongMessage::original` field.
2183        let message = SongMessage {
2184            song,
2185            original: raw_json,
2186        };
2187
2188        assert_eq!(
2189            message.song.title, TITLE,
2190            "The title is a normal `&str` and so can be directly compared"
2191        );
2192        assert_eq!(
2193            message.original.get(),
2194            &json,
2195            "The original has not been modified in any way"
2196        );
2197    }
2198}