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