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    pub fn to_strings(&self) -> Vec<String> {
506        self.0.iter().map(ToString::to_string).collect()
507    }
508
509    pub fn into_strings(self) -> Vec<String> {
510        self.0.into_iter().map(|path| path.to_string()).collect()
511    }
512
513    pub fn is_empty(&self) -> bool {
514        self.0.is_empty()
515    }
516
517    pub fn len(&self) -> usize {
518        self.0.len()
519    }
520
521    pub fn iter<'a>(&'a self) -> UnexpectedFieldsIter<'a, 'buf> {
522        UnexpectedFieldsIter(self.0.iter())
523    }
524}
525
526impl<'buf> IntoIterator for UnexpectedFields<'buf> {
527    type Item = PathRef<'buf>;
528
529    type IntoIter = UnexpectedFieldsIntoIter<'buf>;
530
531    fn into_iter(self) -> Self::IntoIter {
532        UnexpectedFieldsIntoIter(self.0.into_iter())
533    }
534}
535
536pub struct UnexpectedFieldsIntoIter<'buf>(std::vec::IntoIter<PathNodeRef<'buf>>);
537
538impl<'buf> Iterator for UnexpectedFieldsIntoIter<'buf> {
539    type Item = PathRef<'buf>;
540
541    fn next(&mut self) -> Option<Self::Item> {
542        let path_node = self.0.next()?;
543
544        Some(PathRef(path_node))
545    }
546}
547
548impl<'a, 'buf> IntoIterator for &'a UnexpectedFields<'buf> {
549    type Item = PathRef<'buf>;
550
551    type IntoIter = UnexpectedFieldsIter<'a, 'buf>;
552
553    fn into_iter(self) -> Self::IntoIter {
554        self.iter()
555    }
556}
557
558pub struct UnexpectedFieldsIter<'a, 'buf>(std::slice::Iter<'a, PathNodeRef<'buf>>);
559
560impl<'buf> Iterator for UnexpectedFieldsIter<'_, 'buf> {
561    type Item = PathRef<'buf>;
562
563    fn next(&mut self) -> Option<Self::Item> {
564        let path_node = self.0.next()?;
565
566        Some(PathRef(Rc::clone(path_node)))
567    }
568}
569
570/// A path to a JSON `Element` where the path components are borrowed from the source JSON `&str`.
571///
572/// The Display impl outputs strings like:
573///
574/// - `$` The root is represented by a dollar.
575/// - `$.object_key` Dots separate the path elements.
576/// - `$.object_key.2` Arrays are represented as integers.
577pub struct PathRef<'buf>(PathNodeRef<'buf>);
578
579impl fmt::Debug for PathRef<'_> {
580    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
581        write!(f, "{self}")
582    }
583}
584
585impl<'buf> PathRef<'buf> {
586    /// Return an [`Iterator`] over the components of this path.
587    pub fn components(&self) -> PathComponents<'buf> {
588        PathComponents(PathIter::new(Rc::clone(&self.0)))
589    }
590}
591
592/// An [`Iterator`] over the components of a path.
593pub struct PathComponents<'buf>(PathIter<'buf>);
594
595impl<'buf> Iterator for PathComponents<'buf> {
596    type Item = PathComponent<'buf>;
597
598    fn next(&mut self) -> Option<Self::Item> {
599        let path_node = self.0.next()?;
600        Some(PathComponent(path_node))
601    }
602}
603
604/// The `PathRef` can be compared with other strings just like a `String`.
605impl PartialEq<&str> for PathRef<'_> {
606    fn eq(&self, other: &&str) -> bool {
607        match_path_node(&self.0, other, |_| false)
608    }
609}
610
611/// The `PathRef` can be compared with other strings just like a `String`.
612impl PartialEq<String> for PathRef<'_> {
613    fn eq(&self, other: &String) -> bool {
614        match_path_node(&self.0, other, |_| false)
615    }
616}
617
618impl fmt::Display for PathRef<'_> {
619    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
620        fmt::Display::fmt(&self.0, f)
621    }
622}
623
624#[cfg(test)]
625mod test_path_node_matches_str {
626    use std::rc::Rc;
627
628    use crate::test;
629
630    use super::PathNode;
631
632    #[test]
633    fn should_match_path() {
634        test::setup();
635
636        let root = Rc::new(PathNode::Root);
637        let path_a = Rc::new(PathNode::Array {
638            parent: Rc::clone(&root),
639            index: 1,
640        });
641        let path_b = Rc::new(PathNode::Object {
642            parent: Rc::clone(&path_a),
643            key: r#""name""#.into(),
644        });
645        let path_c = PathNode::Object {
646            parent: Rc::clone(&path_b),
647            key: r#""gene""#.into(),
648        };
649
650        assert_eq!(*root, "$");
651        assert_eq!(*path_a, "$.1");
652        assert_eq!(*path_b, "$.1.name");
653        assert_eq!(path_c, "$.1.name.gene");
654    }
655}
656
657/// The path to a JSON `Element`.
658pub(crate) type PathNodeRef<'buf> = Rc<PathNode<'buf>>;
659
660/// A single node of a complete path.
661///
662/// Path's are structured as a linked list from the leaf of the path back to the root through the parents.
663///
664/// The Display impl of the `Path` outputs strings like:
665///
666/// - `$` The root is represented by a dollar.
667/// - `$.object_key` Dots separate the path elements.
668/// - `$.object_key.2` Arrays are represented as integers.
669#[derive(Clone, Debug, Default, Eq, PartialEq, Ord, PartialOrd)]
670pub(crate) enum PathNode<'buf> {
671    /// The root of the JSON `Element` tree.
672    #[default]
673    Root,
674    /// An `Array` element referenced by index.
675    Array {
676        parent: PathNodeRef<'buf>,
677        index: usize,
678    },
679    /// An `Object` field referenced be key value.
680    Object {
681        parent: PathNodeRef<'buf>,
682        key: RawStr<'buf>,
683    },
684}
685
686/// A light weight enum used to indicate the kind of component being visited when using the
687/// [`PathComponents`] [`Iterator`].
688pub enum PathNodeKind {
689    /// The root of the JSON `Element` tree.
690    Root,
691    /// An `Array` element referenced by index.
692    Array,
693    /// An `Object` field referenced be key value.
694    Object,
695}
696
697/// A path to a JSON `Element` where the path components are heap allocated and so do not require
698/// a lifetime back to the source JSON `&str`.
699///
700/// The Display impl outputs strings like:
701///
702/// - `$` The root is represented by a dollar.
703/// - `$.object_key` Dots separate the path elements.
704/// - `$.object_key.2` Arrays are represented as integers.
705#[derive(Clone, Debug, Eq, PartialEq, Ord, PartialOrd)]
706pub struct Path(Vec<PathPiece>);
707
708impl Path {
709    /// Create an root `Path`.
710    const fn root() -> Self {
711        Self(vec![])
712    }
713
714    /// Create an `Path` by iterating over a [`PathNode`].
715    fn from_node(path: PathNodeRef<'_>) -> Self {
716        let paths: Vec<_> = PathIter::new(path).collect();
717
718        let pieces = paths
719            .into_iter()
720            .rev()
721            .filter_map(|path_node| match *path_node {
722                PathNode::Root => None,
723                PathNode::Array { index, .. } => Some(PathPiece::Array(index)),
724                PathNode::Object { key, .. } => Some(PathPiece::Object(key.to_string())),
725            })
726            .collect();
727
728        Self(pieces)
729    }
730}
731
732/// The `Path` can be compared with other strings just like a `String`.
733impl PartialEq<&str> for Path {
734    fn eq(&self, other: &&str) -> bool {
735        match_path(self, other)
736    }
737}
738
739/// The `Path` can be compared with other strings just like a `String`.
740impl PartialEq<String> for Path {
741    fn eq(&self, other: &String) -> bool {
742        match_path(self, other)
743    }
744}
745
746impl fmt::Display for Path {
747    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
748        let iter = self.0.iter();
749
750        write!(f, "$")?;
751
752        for path in iter {
753            write!(f, ".{path}")?;
754        }
755
756        Ok(())
757    }
758}
759
760/// A piece/component of a [`Path`].
761///
762/// The `PathComponent` name is already taken and this type is private.
763#[derive(Clone, Debug, Eq, PartialEq, Ord, PartialOrd)]
764enum PathPiece {
765    /// An `Array` element referenced by index.
766    Array(usize),
767    /// An `Object` field referenced be key value.
768    Object(String),
769}
770
771impl fmt::Display for PathPiece {
772    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
773        match self {
774            PathPiece::Array(index) => write!(f, "{index}"),
775            PathPiece::Object(key) => write!(f, "{key}"),
776        }
777    }
778}
779
780/// A single component of a [`PathRef`].
781pub struct PathComponent<'buf>(PathNodeRef<'buf>);
782
783impl PathComponent<'_> {
784    /// Return the kind of component this is.
785    pub fn kind(&self) -> PathNodeKind {
786        match *self.0 {
787            PathNode::Root => PathNodeKind::Root,
788            PathNode::Array { .. } => PathNodeKind::Array,
789            PathNode::Object { .. } => PathNodeKind::Object,
790        }
791    }
792}
793
794impl fmt::Display for PathComponent<'_> {
795    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
796        match *self.0 {
797            PathNode::Root => f.write_str(PATH_ROOT),
798            PathNode::Array { index, .. } => write!(f, "{index}"),
799            PathNode::Object { key, .. } => write!(f, "{key}"),
800        }
801    }
802}
803
804impl fmt::Display for PathNode<'_> {
805    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
806        let paths: Vec<_> = PathIter::new(Rc::new(self.clone())).collect();
807        let mut iter = paths.into_iter().rev();
808
809        if f.alternate() {
810            // print out each path element as a debugging tab-stop.
811            for path in iter {
812                match *path {
813                    PathNode::Root => f.write_str("")?,
814                    PathNode::Array { .. } | PathNode::Object { .. } => f.write_str("...|")?,
815                }
816            }
817        } else {
818            if let Some(path) = iter.next() {
819                write!(f, "{}", PathComponent(path))?;
820            }
821
822            for path in iter {
823                write!(f, ".{}", PathComponent(path))?;
824            }
825        }
826        Ok(())
827    }
828}
829
830impl<'buf> PathNode<'buf> {
831    /// Returns true if the `Path` refers to the root.
832    pub(crate) fn is_root(&self) -> bool {
833        matches!(self, PathNode::Root)
834    }
835
836    /// Returns true if the `Path` refers to an `Array`.
837    pub(crate) fn is_array(&self) -> bool {
838        matches!(self, PathNode::Array { .. })
839    }
840
841    /// Return a key as `Some(&str)` if the `Path` refers to an `Object`.
842    pub(crate) fn as_object_key(&self) -> Option<&RawStr<'buf>> {
843        match self {
844            PathNode::Object { key, .. } => Some(key),
845            PathNode::Root | PathNode::Array { .. } => None,
846        }
847    }
848}
849
850/// Return true if the given `PathNode` matches the given `&str`.
851///
852/// If the `skip` function returns true, that path component is skipped.
853/// The `skip` function allows this single function to implement comparisons between `PathNode` and `&str`;
854/// and comparisons between `PathNode` and `PathGlob`.
855fn match_path_node<F>(path: &PathNode<'_>, s: &str, mut skip: F) -> bool
856where
857    F: FnMut(&str) -> bool,
858{
859    let mut parts = s.rsplit(PATH_SEPARATOR);
860    let mut paths_iter = PathIter::new(Rc::new(path.clone()));
861
862    loop {
863        let node_segment = paths_iter.next();
864        let str_segment = parts.next();
865
866        let (node_segment, str_segment) = match (node_segment, str_segment) {
867            // If we have exhausted both iterators then the `&str` is equal to the path.
868            (None, None) => return true,
869            // If either of the iters are a different size, then they don't match.
870            (None, Some(_)) | (Some(_), None) => return false,
871            // If both iters have another item, continue on to try match them.
872            (Some(a), Some(b)) => (a, b),
873        };
874
875        // If the skip function says to skip a path segment, then continue to the next segment.
876        if skip(str_segment) {
877            continue;
878        }
879
880        let yip = match *node_segment {
881            PathNode::Root => str_segment == PATH_ROOT,
882            PathNode::Array { index, .. } => {
883                let Ok(b) = str_segment.parse::<usize>() else {
884                    return false;
885                };
886
887                index == b
888            }
889            PathNode::Object { key, .. } => key.as_raw() == str_segment,
890        };
891
892        // Return false on the first mismatch.
893        if !yip {
894            return false;
895        }
896    }
897}
898
899/// Return true if the given `Path` matches the given `&str`.
900fn match_path(path: &Path, s: &str) -> bool {
901    let mut parts = s.split(PATH_SEPARATOR);
902    let mut paths_iter = path.0.iter();
903
904    let Some(str_segment) = parts.next() else {
905        return false;
906    };
907
908    // The root path segment is not explicitly stored in a `Path` so we just match the first
909    // `str` segment to the expected `$` nomenclature.
910    if str_segment != PATH_ROOT {
911        return false;
912    }
913
914    loop {
915        let node_segment = paths_iter.next();
916        let str_segment = parts.next();
917
918        let (node_segment, str_segment) = match (node_segment, str_segment) {
919            // If we have exhausted both iterators then the `&str` is equal to the path.
920            (None, None) => return true,
921            // If either of the iters are a different size, then they don't match.
922            (None, Some(_)) | (Some(_), None) => return false,
923            // If both iters have another item, continue on to try match them.
924            (Some(a), Some(b)) => (a, b),
925        };
926
927        let yip = match node_segment {
928            PathPiece::Array(index) => {
929                let Ok(b) = str_segment.parse::<usize>() else {
930                    return false;
931                };
932
933                *index == b
934            }
935            PathPiece::Object(key) => key == str_segment,
936        };
937
938        // Return false on the first mismatch.
939        if !yip {
940            return false;
941        }
942    }
943}
944
945impl PartialEq<&str> for PathNode<'_> {
946    fn eq(&self, other: &&str) -> bool {
947        match_path_node(self, other, |_| false)
948    }
949}
950
951impl PartialEq<String> for PathNode<'_> {
952    fn eq(&self, other: &String) -> bool {
953        match_path_node(self, other, |_| false)
954    }
955}
956
957/// Traverse a `Path` from the leaf to the root.
958struct PathIter<'buf> {
959    /// The root has been reached.
960    complete: bool,
961    /// The current path node to introspect when `Iterator::next` is called.
962    path: PathNodeRef<'buf>,
963}
964
965impl<'buf> PathIter<'buf> {
966    /// Create a new `PathIter` from a leaf node.
967    fn new(path: PathNodeRef<'buf>) -> Self {
968        Self {
969            complete: false,
970            path,
971        }
972    }
973}
974
975impl<'buf> Iterator for PathIter<'buf> {
976    type Item = PathNodeRef<'buf>;
977
978    fn next(&mut self) -> Option<Self::Item> {
979        if self.complete {
980            return None;
981        }
982
983        match &*self.path {
984            PathNode::Root => {
985                // The iteration is complete once we've arrived at the root node.
986                self.complete = true;
987                Some(Rc::clone(&self.path))
988            }
989            PathNode::Array { parent, .. } | PathNode::Object { parent, .. } => {
990                let next = Rc::clone(&self.path);
991                self.path = Rc::clone(parent);
992                Some(next)
993            }
994        }
995    }
996}
997
998/// Display the expectation stack for debugging
999struct DisplayExpectStack<'a>(&'a [schema::Expect]);
1000
1001impl fmt::Display for DisplayExpectStack<'_> {
1002    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1003        let mut iter = self.0.iter().rev();
1004        let last = iter.next();
1005
1006        // Use the `~` to represent a schema stack.
1007        f.write_str("~")?;
1008
1009        for _ in iter {
1010            f.write_str("...~")?;
1011        }
1012
1013        if let Some(exp) = last {
1014            match exp {
1015                schema::Expect::Scalar => f.write_str("~")?,
1016                schema::Expect::Array(element) => match &**element {
1017                    schema::Element::Scalar => f.write_str("~")?,
1018                    schema::Element::Array(element) => write!(f, "[{element:?}]")?,
1019                    schema::Element::Object(fields) => {
1020                        write!(f, "[{{{:}}}])", DisplayExpectFields(&**fields))?;
1021                    }
1022                },
1023                schema::Expect::Object(fields) => {
1024                    write!(f, "{{{:}}}", DisplayExpectFields(&**fields))?;
1025                }
1026                schema::Expect::UnmatchedScalar => write!(f, "unmatched(scalar)")?,
1027                schema::Expect::UnmatchedArray => write!(f, "unmatched(array)")?,
1028                schema::Expect::UnmatchedObject => write!(f, "unmatched(object)")?,
1029                schema::Expect::OutOfSchema => write!(f, "no_schema")?,
1030            }
1031        }
1032
1033        Ok(())
1034    }
1035}
1036
1037/// Display the fields of a schema expect stack level.
1038struct DisplayExpectFields<'a, V>(&'a BTreeMap<&'a str, V>);
1039
1040impl<V> fmt::Display for DisplayExpectFields<'_, V> {
1041    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1042        const MAX_FIELDS: usize = 8;
1043
1044        let mut count = 0;
1045        let mut iter = self.0.keys().peekable();
1046
1047        loop {
1048            if count >= MAX_FIELDS {
1049                f.write_str("...")?;
1050                break;
1051            }
1052
1053            let Some(field) = iter.next() else {
1054                break;
1055            };
1056
1057            count += 1;
1058            write!(f, "{field}")?;
1059
1060            let Some(_) = iter.peek() else {
1061                break;
1062            };
1063
1064            f.write_str(", ")?;
1065        }
1066
1067        Ok(())
1068    }
1069}
1070
1071#[derive(Debug)]
1072struct UnbalancedExpectStack;
1073
1074impl fmt::Display for UnbalancedExpectStack {
1075    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1076        f.write_str("unbalanced expectation stack")
1077    }
1078}
1079
1080impl std::error::Error for UnbalancedExpectStack {}
1081
1082/// Parse the JSON into an `Element`.
1083pub(crate) fn parse_with_schema<'buf>(
1084    json: &'buf str,
1085    schema: &schema::Element,
1086) -> Result<Report<'buf>, Error> {
1087    let parser = Parser::new(json);
1088    let mut unexpected_fields = vec![];
1089    // The current node of the schema is the last element of this vec.
1090    let mut expectation_stack = vec![schema.to_expectation()];
1091
1092    for event in parser {
1093        match event? {
1094            parser::Event::Open { kind, parent_path } => {
1095                // Take the schema expectation off the stack.
1096                // This is simpler than taking a `&mut` to the last element.
1097                let Some(expectation) = expectation_stack.pop() else {
1098                    return Err(ErrorKind::Internal(Box::new(UnbalancedExpectStack))
1099                        .into_partial_error_without_token()
1100                        .with_root_path());
1101                };
1102
1103                if tracing::enabled!(Level::DEBUG) {
1104                    match kind {
1105                        ObjectKind::Array => {
1106                            trace!("{parent_path} [ {}", DisplayExpectStack(&expectation_stack));
1107                        }
1108                        ObjectKind::Object => trace!(
1109                            "{parent_path} {{ {}",
1110                            DisplayExpectStack(&expectation_stack)
1111                        ),
1112                    }
1113                }
1114
1115                match expectation {
1116                    schema::Expect::Array(elem) => {
1117                        // If the opening element is at the root we only care if the element
1118                        // is an array or not.
1119                        if parent_path.is_root() {
1120                            let next = match kind {
1121                                ObjectKind::Array => schema::Expect::Array(elem),
1122                                ObjectKind::Object => schema::Expect::UnmatchedArray,
1123                            };
1124
1125                            expectation_stack.push(next);
1126                            trace!("{}", DisplayExpectStack(&expectation_stack));
1127                            continue;
1128                        }
1129
1130                        if !parent_path.is_array() {
1131                            expectation_stack.push(schema::Expect::UnmatchedArray);
1132                            trace!("{}", DisplayExpectStack(&expectation_stack));
1133                            continue;
1134                        }
1135
1136                        expectation_stack.push(schema::Expect::Array(Arc::clone(&elem)));
1137                        // each array element should match this expectation
1138                        expectation_stack.push(elem.to_expectation());
1139                    }
1140                    schema::Expect::Object(fields) => {
1141                        // If the opening element is at the root there is no path to inspect.
1142                        // We only care if the element is an object or not.
1143                        if parent_path.is_root() {
1144                            let next = match kind {
1145                                ObjectKind::Array => schema::Expect::UnmatchedObject,
1146                                ObjectKind::Object => schema::Expect::Object(fields),
1147                            };
1148
1149                            expectation_stack.push(next);
1150                            trace!("{}", DisplayExpectStack(&expectation_stack));
1151                            continue;
1152                        }
1153                        let Some(key) = parent_path.as_object_key() else {
1154                            expectation_stack.push(schema::Expect::UnmatchedObject);
1155                            trace!("{}", DisplayExpectStack(&expectation_stack));
1156                            continue;
1157                        };
1158
1159                        let next = if let Some(elem) = fields.get(key.as_raw()) {
1160                            open_object(kind, elem.as_ref())
1161                        } else {
1162                            unexpected_fields.push(parent_path);
1163                            schema::Expect::OutOfSchema
1164                        };
1165
1166                        expectation_stack.push(schema::Expect::Object(fields));
1167                        expectation_stack.push(next);
1168                    }
1169                    schema::Expect::OutOfSchema => {
1170                        // If we're already outside of the schema we put that back on the stack
1171                        // and add a new one for the object that just opened.
1172                        //
1173                        // We need to keep track of object level even though the schema expectations
1174                        // have been exhausted, as we'll pop these placeholder `OutOfSchema`s
1175                        // off the stack when the object has closed so we land on the correct
1176                        // schema again.
1177                        expectation_stack.push(expectation);
1178                        expectation_stack.push(schema::Expect::OutOfSchema);
1179                    }
1180                    schema::Expect::UnmatchedArray | schema::Expect::UnmatchedObject => {
1181                        expectation_stack.push(expectation);
1182                        expectation_stack.push(schema::Expect::OutOfSchema);
1183                    }
1184                    _ => {
1185                        expectation_stack.push(expectation);
1186                    }
1187                }
1188
1189                trace!("{}", DisplayExpectStack(&expectation_stack));
1190            }
1191            parser::Event::Element { kind, parent_path } => {
1192                // Take the schema expectation off the stack.
1193                // This is simpler than taking a `&mut` to the last element.
1194                let Some(expectation) = expectation_stack.pop() else {
1195                    return Err(ErrorKind::Internal(Box::new(UnbalancedExpectStack))
1196                        .into_partial_error_without_token()
1197                        .with_root_path());
1198                };
1199
1200                // An `Element` of kind `Array` or `Object` means the `Element` is closed
1201                // and has completed construction. The expectation can remain off the stack.
1202                if let ValueKind::Array | ValueKind::Object = kind {
1203                    if tracing::enabled!(Level::DEBUG) {
1204                        match kind {
1205                            ValueKind::Array => {
1206                                trace!(
1207                                    "{parent_path} ] {}",
1208                                    DisplayExpectStack(&expectation_stack)
1209                                );
1210                            }
1211                            ValueKind::Object => trace!(
1212                                "{parent_path} }} {}",
1213                                DisplayExpectStack(&expectation_stack)
1214                            ),
1215                            _ => (),
1216                        }
1217                    }
1218                    continue;
1219                }
1220
1221                match expectation {
1222                    #[expect(
1223                        clippy::unreachable,
1224                        reason = "The parser only emits an `Event::Complete` for a scalar object at the root"
1225                    )]
1226                    schema::Expect::Object(fields) => match &*parent_path {
1227                        PathNode::Root => unreachable!(),
1228                        PathNode::Array { .. } => {
1229                            expectation_stack.push(schema::Expect::UnmatchedObject);
1230                        }
1231                        PathNode::Object { parent, key } => {
1232                            trace!("{parent:#}.{key}");
1233
1234                            if !fields.contains_key(key.as_raw()) {
1235                                unexpected_fields.push(parent_path);
1236                            }
1237
1238                            expectation_stack.push(schema::Expect::Object(fields));
1239                        }
1240                    },
1241                    schema::Expect::OutOfSchema => {
1242                        unexpected_fields.push(parent_path);
1243                        expectation_stack.push(expectation);
1244                    }
1245                    _ => {
1246                        expectation_stack.push(expectation);
1247                    }
1248                }
1249            }
1250            parser::Event::Complete(element) => {
1251                if element.value().is_scalar() {
1252                    unexpected_fields.push(element.path_node());
1253                }
1254
1255                // Parsing the JSON is complete.
1256                // Return the `Element` and the unexpected fields collected during parsing
1257                return Ok(Report {
1258                    element,
1259                    unexpected_fields: UnexpectedFields::from_vec(unexpected_fields),
1260                });
1261            }
1262        }
1263    }
1264
1265    Err(ErrorKind::UnexpectedEOF
1266        .into_partial_error_without_token()
1267        .with_root_path())
1268}
1269
1270fn open_object(kind: ObjectKind, elem: Option<&Arc<schema::Element>>) -> schema::Expect {
1271    let Some(schema) = elem else {
1272        return schema::Expect::OutOfSchema;
1273    };
1274
1275    match (kind, &**schema) {
1276        (ObjectKind::Object | ObjectKind::Array, schema::Element::Scalar) => {
1277            schema::Expect::UnmatchedScalar
1278        }
1279        (ObjectKind::Object, schema::Element::Array(_)) => schema::Expect::UnmatchedArray,
1280        (ObjectKind::Object, schema::Element::Object(fields)) => {
1281            schema::Expect::Object(Arc::clone(fields))
1282        }
1283        (ObjectKind::Array, schema::Element::Array(element)) => {
1284            schema::Expect::Array(Arc::clone(element))
1285        }
1286        (ObjectKind::Array, schema::Element::Object(_)) => schema::Expect::UnmatchedObject,
1287    }
1288}
1289
1290/// The output of the `parse_with_schema` function where the parsed JSON `Element` is returned
1291/// along with a list of fields that the schema did not define.
1292#[derive(Debug)]
1293pub(crate) struct Report<'buf> {
1294    /// The root JSON `Element`.
1295    pub element: Element<'buf>,
1296
1297    /// A list of fields that were not expected.
1298    pub unexpected_fields: UnexpectedFields<'buf>,
1299}
1300
1301#[cfg(test)]
1302pub mod test {
1303    #![allow(clippy::missing_panics_doc, reason = "tests are allowed to panic")]
1304    #![allow(clippy::panic, reason = "tests are allowed panic")]
1305
1306    use std::borrow::Cow;
1307
1308    use crate::json::match_path_node;
1309
1310    use super::{
1311        parser::Span, walk::DepthFirst, ElemId, Element, Field, FieldsAsExt as _, PathNode,
1312        PathNodeRef, PathRef, RawStr, UnexpectedFields, Value,
1313    };
1314
1315    impl<'buf> Element<'buf> {
1316        /// Return the `Span` of the `Element`'s `&str` is the source JSON.
1317        pub fn span(&self) -> Span {
1318            self.span
1319        }
1320
1321        /// Consume the `Element` and return only the `Value`.
1322        pub(crate) fn into_value(self) -> Value<'buf> {
1323            self.value
1324        }
1325
1326        /// Consume the `Element` and return the `Path`, `Span` and `Value` as a tuple.
1327        pub(crate) fn into_parts(self) -> (ElemId, PathNodeRef<'buf>, Span, Value<'buf>) {
1328            let Self {
1329                id,
1330                path_node: path,
1331                span,
1332                value,
1333            } = self;
1334            (id, path, span, value)
1335        }
1336
1337        pub(crate) fn find_field(&self, key: &str) -> Option<&Field<'buf>> {
1338            self.as_object_fields()
1339                .and_then(|fields| fields.find_field(key))
1340        }
1341    }
1342
1343    impl<'buf> Value<'buf> {
1344        /// Return true if the `Value` is an `Array`.
1345        pub(crate) fn is_array(&self) -> bool {
1346            matches!(self, Value::Array(_))
1347        }
1348
1349        /// Return true if the `Value` is an `Object`.
1350        pub(crate) fn is_object(&self) -> bool {
1351            matches!(self, Value::Object(_))
1352        }
1353
1354        pub(crate) fn as_string(&self) -> Option<&RawStr<'buf>> {
1355            match self {
1356                Value::String(s) => Some(s),
1357                _ => None,
1358            }
1359        }
1360    }
1361
1362    impl<'buf> Field<'buf> {
1363        pub fn id(&self) -> ElemId {
1364            self.0.id()
1365        }
1366
1367        pub fn into_parts(self) -> (ElemId, PathNodeRef<'buf>, Span, Value<'buf>) {
1368            self.0.into_parts()
1369        }
1370    }
1371
1372    impl<'buf> UnexpectedFields<'buf> {
1373        /// The tests need to assert against the contents.
1374        pub(crate) fn into_inner(self) -> Vec<PathNodeRef<'buf>> {
1375            self.0
1376        }
1377
1378        /// Filter off the fields that match the glob.
1379        pub(crate) fn filter_matches(&mut self, glob: &PathGlob<'_>) {
1380            self.0.retain(|path| !glob.matches(path));
1381        }
1382    }
1383
1384    /// A string based `Path` that can contain glob `*` patterns in place of a literal path element.
1385    /// The glob means that the path section can be any valid section.
1386    #[derive(Debug)]
1387    pub(crate) struct PathGlob<'a>(Cow<'a, str>);
1388
1389    impl PathGlob<'_> {
1390        /// Return true if this `PathGlob` matches the given `PathNode`.
1391        pub(crate) fn matches(&self, path: &PathNode<'_>) -> bool {
1392            const WILDCARD: &str = "*";
1393
1394            match_path_node(path, &self.0, |s| {
1395                // if the `PathGlob` segment is a glob, then continue to the next segment.
1396                s == WILDCARD
1397            })
1398        }
1399    }
1400
1401    /// The tests need to assert against literal `ElemId`s.
1402    impl From<usize> for ElemId {
1403        fn from(value: usize) -> Self {
1404            Self(value)
1405        }
1406    }
1407
1408    impl<'a> From<&'a str> for PathGlob<'a> {
1409        fn from(s: &'a str) -> Self {
1410            Self(s.into())
1411        }
1412    }
1413
1414    impl From<String> for PathGlob<'_> {
1415        fn from(s: String) -> Self {
1416            Self(s.into())
1417        }
1418    }
1419
1420    impl<'de, 'buf> serde::Deserialize<'de> for PathGlob<'buf> {
1421        fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
1422        where
1423            D: ::serde::Deserializer<'de>,
1424        {
1425            let s = <Cow<'buf, str> as ::serde::Deserialize>::deserialize(deserializer)?;
1426            Ok(Self(s))
1427        }
1428    }
1429
1430    /// A map of `Element`s referenced by their unique Id.
1431    pub struct ElementMap<'a, 'bin>(Vec<&'a Element<'bin>>);
1432
1433    impl<'a, 'bin> ElementMap<'a, 'bin> {
1434        /// Create a new `ElementMap` by traversing the `Element` tree from the given node.
1435        pub fn for_elem(root: &'a Element<'bin>) -> Self {
1436            // The walker will emit `Element`s ordered by their Id.
1437            let walker = DepthFirst::new(root);
1438            Self(walker.collect())
1439        }
1440
1441        /// Return the `Element` with the given id.
1442        pub fn get(&self, id: ElemId) -> &Element<'bin> {
1443            self.0.get(id.0).map(|e| &**e).unwrap()
1444        }
1445
1446        /// Return the `Path` of the `Element` with the given id.
1447        pub fn path(&self, id: ElemId) -> PathRef<'bin> {
1448            self.0.get(id.0).map(|elem| elem.path()).unwrap()
1449        }
1450    }
1451
1452    #[cfg(test)]
1453    mod test_path_matches_glob {
1454        use std::rc::Rc;
1455
1456        use crate::test;
1457
1458        use super::{PathGlob, PathNode};
1459
1460        #[test]
1461        fn should_match_path() {
1462            test::setup();
1463
1464            let root = Rc::new(PathNode::Root);
1465            let path_a = Rc::new(PathNode::Array {
1466                parent: Rc::clone(&root),
1467                index: 1,
1468            });
1469            let path_b = Rc::new(PathNode::Object {
1470                parent: Rc::clone(&path_a),
1471                key: r#""name""#.into(),
1472            });
1473            let path_c = PathNode::Object {
1474                parent: Rc::clone(&path_b),
1475                key: r#""gene""#.into(),
1476            };
1477
1478            assert!(PathGlob::from("$").matches(&root));
1479            assert!(PathGlob::from("*").matches(&root));
1480
1481            assert!(!PathGlob::from("*").matches(&path_a));
1482            assert!(PathGlob::from("*.*").matches(&path_a));
1483            assert!(PathGlob::from("$.*").matches(&path_a));
1484            assert!(PathGlob::from("$.1").matches(&path_a));
1485
1486            assert!(!PathGlob::from("*").matches(&path_b));
1487            assert!(!PathGlob::from("*.*").matches(&path_b));
1488            assert!(PathGlob::from("*.*.*").matches(&path_b));
1489            assert!(PathGlob::from("$.*.*").matches(&path_b));
1490            assert!(PathGlob::from("$.1.*").matches(&path_b));
1491            assert!(PathGlob::from("$.*.name").matches(&path_b));
1492            assert!(PathGlob::from("$.1.name").matches(&path_b));
1493
1494            assert!(PathGlob::from("$.1.name.gene").matches(&path_c));
1495        }
1496    }
1497}
1498
1499#[cfg(test)]
1500mod test_path {
1501    use super::{Path, PathPiece};
1502
1503    #[test]
1504    fn path_should_cmp_with_str() {
1505        assert_ne!(Path::root(), "");
1506        assert_eq!(Path::root(), "$");
1507        assert_eq!(Path(vec![PathPiece::Object("field_a".into())]), "$.field_a");
1508        assert_eq!(Path(vec![PathPiece::Array(1)]), "$.1");
1509        assert_eq!(
1510            Path(vec![
1511                PathPiece::Object("field_a".into()),
1512                PathPiece::Array(1)
1513            ]),
1514            "$.field_a.1"
1515        );
1516    }
1517
1518    #[test]
1519    fn path_should_display() {
1520        assert_eq!(Path::root().to_string(), "$");
1521        assert_eq!(
1522            Path(vec![PathPiece::Object("field_a".into())]).to_string(),
1523            "$.field_a"
1524        );
1525        assert_eq!(Path(vec![PathPiece::Array(1)]).to_string(), "$.1");
1526        assert_eq!(
1527            Path(vec![
1528                PathPiece::Object("field_a".into()),
1529                PathPiece::Array(1)
1530            ])
1531            .to_string(),
1532            "$.field_a.1"
1533        );
1534    }
1535}
1536
1537#[cfg(test)]
1538mod test_parse_with_schema {
1539    use crate::{json_schema, test};
1540
1541    use super::{parse_with_schema, Report};
1542
1543    #[test]
1544    fn should_report_unexpected_fields_for_root_element() {
1545        const JSON: &str = "null";
1546
1547        test::setup();
1548
1549        let schema = json_schema!({
1550            "id",
1551            "currency",
1552        });
1553
1554        let report = parse_with_schema(JSON, &schema).unwrap();
1555        let Report {
1556            element: _,
1557            unexpected_fields,
1558        } = report;
1559
1560        {
1561            let [field_a] = unexpected_fields.into_inner().try_into().unwrap();
1562            assert_eq!(*field_a, "$");
1563        }
1564    }
1565
1566    #[test]
1567    fn should_report_unexpected_fields_in_flat_object() {
1568        const JSON: &str = r#"{
1569    "id": "tariff_id",
1570    "currency": "EUR",
1571    "name": "Barry",
1572    "address": "Barrystown"
1573}"#;
1574
1575        test::setup();
1576
1577        let schema = json_schema!({
1578            "id",
1579            "currency",
1580        });
1581
1582        let report = parse_with_schema(JSON, &schema).unwrap();
1583        let Report {
1584            element: _,
1585            unexpected_fields,
1586        } = report;
1587
1588        {
1589            let [field_a, field_b] = unexpected_fields.into_inner().try_into().unwrap();
1590            assert_eq!(*field_a, "$.name");
1591            assert_eq!(*field_b, "$.address");
1592        }
1593    }
1594
1595    #[test]
1596    fn should_report_unexpected_fields_in_nested_object() {
1597        const JSON: &str = r#"{
1598    "id": "tariff_id",
1599    "currency": "EUR",
1600    "owner": {
1601        "id": "456856",
1602        "subscription_id": "tedi4568",
1603        "name": "Barry",
1604        "address": "Barrystown"
1605    }
1606}"#;
1607
1608        test::setup();
1609
1610        let schema = json_schema!({
1611            "id",
1612            "currency",
1613            "owner": {
1614                "id",
1615                "subscription_id"
1616            }
1617        });
1618
1619        let report = parse_with_schema(JSON, &schema).unwrap();
1620        let Report {
1621            element: _,
1622            unexpected_fields,
1623        } = report;
1624
1625        {
1626            let [field_a, field_b] = unexpected_fields.into_inner().try_into().unwrap();
1627            assert_eq!(*field_a, "$.owner.name");
1628            assert_eq!(*field_b, "$.owner.address");
1629        }
1630    }
1631
1632    #[test]
1633    fn should_parse_nested_object_out_of_schema() {
1634        const JSON: &str = r#"{
1635    "id": "tariff_id",
1636    "owner": {
1637        "id": "456856",
1638        "subscription_id": "tedi4568",
1639        "name": "Barry",
1640        "address": {
1641            "city": "Barrystown",
1642            "street": "Barrysstreet"
1643        }
1644    },
1645    "currency": "EUR",
1646    "country": "NL"
1647}"#;
1648
1649        test::setup();
1650
1651        let schema = json_schema!({
1652            "id",
1653            "currency",
1654            "owner"
1655        });
1656
1657        let report = parse_with_schema(JSON, &schema).unwrap();
1658        let Report {
1659            element: _,
1660            unexpected_fields,
1661        } = report;
1662
1663        {
1664            let [field_a, field_b, field_c, field_d, field_e, field_f] =
1665                unexpected_fields.into_inner().try_into().unwrap();
1666            assert_eq!(*field_a, "$.owner.id");
1667            assert_eq!(*field_b, "$.owner.subscription_id");
1668            assert_eq!(*field_c, "$.owner.name");
1669            assert_eq!(*field_d, "$.owner.address.city");
1670            assert_eq!(*field_e, "$.owner.address.street");
1671            assert_eq!(*field_f, "$.country");
1672        }
1673    }
1674
1675    #[test]
1676    fn should_report_unexpected_fields_in_array_with_nested_object() {
1677        const JSON: &str = r#"{
1678    "id": "tariff_id",
1679    "currency": "EUR",
1680    "elements": [{
1681        "id": "456856",
1682        "subscription_id": "tedi4568",
1683        "name": "Barry",
1684        "address": "Barrystown"
1685    }]
1686}"#;
1687
1688        test::setup();
1689
1690        let schema = json_schema!({
1691            "id",
1692            "currency",
1693            "elements": [{
1694                "id",
1695                "subscription_id"
1696            }]
1697        });
1698
1699        let report = parse_with_schema(JSON, &schema).unwrap();
1700        let Report {
1701            element: _,
1702            unexpected_fields,
1703        } = report;
1704
1705        {
1706            let [field_a, field_b] = unexpected_fields.into_inner().try_into().unwrap();
1707            assert_eq!(*field_a, "$.elements.0.name");
1708            assert_eq!(*field_b, "$.elements.0.address");
1709        }
1710    }
1711
1712    #[test]
1713    fn should_report_unexpected_fields_in_array_of_nested_objects() {
1714        const JSON: &str = r#"{
1715    "id": "tariff_id",
1716    "currency": "EUR",
1717    "elements": [
1718        {
1719            "id": "456856",
1720            "subscription_id": "tedi4568",
1721            "name": "Barry",
1722            "address": "Barrystown"
1723        },
1724        {
1725            "id": "8746we",
1726            "subscription_id": "dfr345",
1727            "name": "Gerry",
1728            "address": "Gerrystown"
1729        }
1730    ]
1731}"#;
1732
1733        test::setup();
1734
1735        let schema = json_schema!({
1736            "id",
1737            "currency",
1738            "elements": [{
1739                "id",
1740                "subscription_id"
1741            }]
1742        });
1743
1744        let report = parse_with_schema(JSON, &schema).unwrap();
1745        let Report {
1746            element: _,
1747            unexpected_fields,
1748        } = report;
1749
1750        {
1751            let [field_a, field_b, field_c, field_d] =
1752                unexpected_fields.into_inner().try_into().unwrap();
1753            assert_eq!(*field_a, "$.elements.0.name");
1754            assert_eq!(*field_b, "$.elements.0.address");
1755            assert_eq!(*field_c, "$.elements.1.name");
1756            assert_eq!(*field_d, "$.elements.1.address");
1757        }
1758    }
1759
1760    #[test]
1761    fn should_report_unexpected_fields_in_array_of_objects() {
1762        const JSON: &str = r#"[
1763    {
1764        "id": "456856",
1765        "subscription_id": "tedi4568",
1766        "name": "Barry",
1767        "address": "Barrystown"
1768    },
1769    {
1770        "id": "8746we",
1771        "subscription_id": "dfr345",
1772        "name": "Gerry",
1773        "address": "Gerrystown"
1774    }
1775]"#;
1776
1777        test::setup();
1778
1779        let schema = json_schema!([
1780            {
1781                "id",
1782                "subscription_id"
1783            }
1784        ]);
1785
1786        let report = parse_with_schema(JSON, &schema).unwrap();
1787        let Report {
1788            element: _,
1789            unexpected_fields,
1790        } = report;
1791
1792        {
1793            let [field_a, field_b, field_c, field_d] =
1794                unexpected_fields.into_inner().try_into().unwrap();
1795            assert_eq!(*field_a, "$.0.name");
1796            assert_eq!(*field_b, "$.0.address");
1797            assert_eq!(*field_c, "$.1.name");
1798            assert_eq!(*field_d, "$.1.address");
1799        }
1800    }
1801}
1802
1803#[cfg(test)]
1804mod test_source_json {
1805    use super::{parse, walk};
1806
1807    #[test]
1808    fn should_resolve_to_source_json() {
1809        const JSON: &str = r#"{
1810    "name": "David Byrne",
1811    "hobbies": ["song writing", "thinking about society"]
1812}"#;
1813
1814        let element = parse(JSON).unwrap();
1815
1816        let mut walk = walk::DepthFirst::new(&element);
1817
1818        let root = walk.next().unwrap();
1819        assert_eq!(root.source_json(JSON), JSON);
1820
1821        let field_name = walk.next().unwrap();
1822        assert_eq!(field_name.source_json(JSON), r#""name": "David Byrne""#);
1823        assert_eq!(field_name.source_json_value(JSON), r#""David Byrne""#);
1824
1825        let field_hobbies = walk.next().unwrap();
1826        assert_eq!(
1827            field_hobbies.source_json(JSON),
1828            r#""hobbies": ["song writing", "thinking about society"]"#
1829        );
1830        assert_eq!(
1831            field_hobbies.source_json_value(JSON),
1832            r#"["song writing", "thinking about society"]"#
1833        );
1834
1835        let hobbies_one = walk.next().unwrap();
1836        assert_eq!(hobbies_one.source_json(JSON), r#""song writing""#);
1837        assert_eq!(hobbies_one.source_json_value(JSON), r#""song writing""#);
1838
1839        let hobbies_two = walk.next().unwrap();
1840        assert_eq!(hobbies_two.source_json(JSON), r#""thinking about society""#);
1841        assert_eq!(
1842            hobbies_two.source_json_value(JSON),
1843            r#""thinking about society""#
1844        );
1845    }
1846}
1847
1848#[cfg(test)]
1849mod test_path_node {
1850    use std::rc::Rc;
1851
1852    use super::{
1853        parser::{RawStr, Token, TokenType},
1854        PathNode, Span,
1855    };
1856
1857    #[test]
1858    fn should_display_path() {
1859        let root = Rc::new(PathNode::Root);
1860        let path_a = Rc::new(PathNode::Array {
1861            parent: Rc::clone(&root),
1862            index: 1,
1863        });
1864        let path_b = Rc::new(PathNode::Object {
1865            parent: Rc::clone(&path_a),
1866            key: r#""name""#.into(),
1867        });
1868        let path_c = Rc::new(PathNode::Object {
1869            parent: Rc::clone(&path_b),
1870            key: r#""gene""#.into(),
1871        });
1872
1873        assert_eq!(*root, "$");
1874        assert_eq!(*path_a, "$.1");
1875        assert_eq!(*path_b, "$.1.name");
1876        assert_eq!(*path_c, "$.1.name.gene");
1877    }
1878
1879    impl<'buf> From<&'buf str> for RawStr<'buf> {
1880        #[track_caller]
1881        fn from(s: &'buf str) -> Self {
1882            RawStr::from_quoted_str(
1883                s,
1884                Token {
1885                    kind: TokenType::String,
1886                    span: Span::default(),
1887                },
1888            )
1889            .unwrap()
1890        }
1891    }
1892}
1893
1894#[cfg(test)]
1895mod test_raw_json {
1896    use std::{borrow::Cow, rc::Rc};
1897
1898    use serde::{de::IntoDeserializer, Deserialize};
1899
1900    use super::{ElemId, Element, PathNode, RawValue, Span, Value, ValueKind};
1901    use crate::json::decode::unescape_str;
1902
1903    const TITLE: &str = "همّا مين واحنا مين (Who Are They and Who Are We?)";
1904
1905    /// Extends a `RawValue` with methods that:
1906    ///
1907    /// - Convert a `RawValue` into a `Value`.
1908    /// - Convert a `RawValue` into a `RawObject`.
1909    /// - Identifies the type of the JSON value in the `RawValue`.
1910    pub(crate) trait RawValueExt {
1911        fn kind(&self) -> ValueKind;
1912
1913        fn is_string(&self) -> bool;
1914
1915        /// Return Some(&str) if the value is a JSON string.
1916        ///
1917        /// The surrounding quotes will be trimmed from the JSON string.
1918        fn as_str(&self) -> Option<Cow<'_, str>>;
1919    }
1920
1921    impl RawValueExt for RawValue {
1922        fn kind(&self) -> ValueKind {
1923            let s = self.get();
1924            let first = s
1925                .as_bytes()
1926                .first()
1927                .expect("A RawValue can`t be an empty string, it has to contain a JSON value");
1928
1929            // If whitespace has been removed from a JSON value and we know `serde` has already
1930            // validated the value. Then the only possible set of chars that can come next `[0-9]` or `[-nt"[{]`.
1931            //
1932            // * See: <https://www.json.org/json-en.html>
1933            //
1934            // `RawValue` has whitespace stripped so we know the first char is non-whitespace.
1935            // See: `test_raw_json::should_fail_to_parse_whitespace_only_string_as_json` and
1936            // `test_raw_json::should_identify_whitespace_surrounded_value_as_array`.
1937            match *first {
1938                b'n' => ValueKind::Null,
1939                b't' | b'f' => ValueKind::Bool,
1940                b'"' => ValueKind::String,
1941                b'[' => ValueKind::Array,
1942                b'{' => ValueKind::Object,
1943                // A `RawValue` is already known to be valid, the only other possibility for valid JSON
1944                // is that this is a number
1945                _ => ValueKind::Number,
1946            }
1947        }
1948
1949        fn is_string(&self) -> bool {
1950            matches!(self.kind(), ValueKind::String)
1951        }
1952
1953        fn as_str(&self) -> Option<Cow<'_, str>> {
1954            if !self.is_string() {
1955                return None;
1956            }
1957
1958            let s = self.get().trim_matches('"');
1959            // This is a dummy element used to satisfy the `Warning` system used by the `decode` mod.
1960            // This hack will not be needed when the pricer uses the new parser.
1961            let elem = Element {
1962                id: ElemId(0),
1963                path_node: Rc::new(PathNode::Root),
1964                span: Span::default(),
1965                value: Value::Null,
1966            };
1967            let (s, _warnings) = unescape_str(s, &elem).into_parts();
1968            Some(s)
1969        }
1970    }
1971
1972    #[test]
1973    fn should_fail_to_parse_whitespace_only_string_as_json() {
1974        const JSON: &str = "  ";
1975        let err = serde_json::from_str::<&RawValue>(JSON).unwrap_err();
1976
1977        assert_eq!(
1978            err.classify(),
1979            serde_json::error::Category::Eof,
1980            "A JSON string can't be empty"
1981        );
1982
1983        let err = RawValue::from_string(JSON.to_string()).unwrap_err();
1984
1985        assert_eq!(
1986            err.classify(),
1987            serde_json::error::Category::Eof,
1988            "A JSON string can't be empty"
1989        );
1990    }
1991
1992    #[test]
1993    fn should_validate_json_without_allocating_for_each_token() {
1994        #[derive(Deserialize)]
1995        struct Song {
1996            title: String,
1997        }
1998
1999        let json = format!(r#"{{ "title": "{TITLE}" }}"#);
2000
2001        // If you need to simply validate json then you can deserialize to `&RawValue` or
2002        // `Box<RawValue>`. The given `String` will be parsed as JSON and the bytes returned
2003        // wrapped in a `RawValue`.
2004        //
2005        // `RawValue` asserts that the bytes are valid JSON encoded as UTF8. It is a wrapper
2006        // around `str` and is therefore unsized.
2007        //
2008        // Use a `Box<RawValue>` to store an owned `RawValue`.
2009        // This will copy/allocate the source bytes to the heap.
2010        let json: Box<RawValue> = serde_json::from_str(&json).unwrap();
2011
2012        // If you want to parse the `RawValue` into a Rust data type the `str` must be extracted
2013        // and the bytes parsed anew. This is the cost of not annotating the source `String`
2014        // with any structural markers. But parsing JSON is a quick operation compared to
2015        // recursive allocation.
2016        let song = Song::deserialize(json.into_deserializer()).unwrap();
2017
2018        assert_eq!(song.title, TITLE);
2019    }
2020
2021    #[test]
2022    fn should_compare_raw_title_correctly() {
2023        #[derive(Deserialize)]
2024        struct Song<'a> {
2025            #[serde(borrow)]
2026            title: &'a RawValue,
2027        }
2028
2029        let json = format!(r#"{{ "title": "{TITLE}" }}"#);
2030        let song: Song<'_> = serde_json::from_str(&json).unwrap();
2031
2032        assert_ne!(
2033            song.title.get(),
2034            TITLE,
2035            "The raw `title` field contains the delimiting '\"' and so is technically not directly equal to the `TITLE` const"
2036        );
2037
2038        let title = song.title.as_str().unwrap();
2039
2040        assert_eq!(
2041            title, TITLE,
2042            "When the quotes are removed the `title` field is the same as the `TITLE` const"
2043        );
2044    }
2045
2046    #[test]
2047    fn should_fail_to_parse_invalid_json() {
2048        const JSON: &str = r#"{ "title": }"#;
2049
2050        let err = serde_json::from_str::<Box<RawValue>>(JSON).unwrap_err();
2051
2052        assert_eq!(
2053            err.classify(),
2054            serde_json::error::Category::Syntax,
2055            "The bytes contained within `RawValue` are valid JSON"
2056        );
2057    }
2058
2059    #[test]
2060    fn should_parse_raw_json_to_rust_struct() {
2061        /// A Song where the `title` field is copied onto the heap.
2062        #[derive(Deserialize)]
2063        struct Song {
2064            title: String,
2065        }
2066
2067        /// A Song with the original JSON stored alongside on the heap.
2068        struct SongMessage {
2069            song: Song,
2070            original: Box<RawValue>,
2071        }
2072
2073        // This is the first heap allocation in this test.
2074        let json = format!(r#"{{ "title": "{TITLE}" }}"#);
2075
2076        // This is the second heap allocation in this test.
2077        let raw_json: Box<RawValue> = serde_json::from_str(&json)
2078            .expect("Typically we want to parse some JSON from an endpoint first");
2079        // This (`title: String`) is the third heap allocation in this test.
2080        let song = Song::deserialize(raw_json.into_deserializer()).expect("And then introspect it");
2081
2082        let message = SongMessage {
2083            song,
2084            original: raw_json,
2085        };
2086
2087        assert_eq!(
2088            message.song.title, TITLE,
2089            "The title is a normal `String` and so can be directly compared"
2090        );
2091        assert_eq!(
2092            message.original.get(),
2093            &json,
2094            "The original has not been modified in any way"
2095        );
2096    }
2097
2098    #[test]
2099    fn should_parse_borrowed_raw_json_to_rust_struct() {
2100        /// A Song where the `title` field is borrowed from the original JSON String.
2101        #[derive(Deserialize)]
2102        struct Song<'a> {
2103            title: &'a str,
2104        }
2105
2106        /// A Song with the original JSON stored alongside.
2107        ///
2108        /// Where all fields are borrowed.
2109        struct SongMessage<'a> {
2110            song: Song<'a>,
2111            original: &'a RawValue,
2112        }
2113
2114        // This is the only heap allocation in this test.
2115        let json = format!(r#"{{ "title": "{TITLE}" }}"#);
2116
2117        // The JSON bytes contained in the original String are borrowed to the `RawValue(str)`.
2118        let raw_json: &RawValue = serde_json::from_str(&json)
2119            .expect("Typically we want to parse some JSON from an endpoint first");
2120        // The bytes borrowed to the `RawValue` are in turn, borrowed to `Song::title`.
2121        let song =
2122            Song::<'_>::deserialize(raw_json.into_deserializer()).expect("And then introspect it");
2123        // The original JSON bytes are borrowed to the `SongMessage::original` field.
2124        let message = SongMessage {
2125            song,
2126            original: raw_json,
2127        };
2128
2129        assert_eq!(
2130            message.song.title, TITLE,
2131            "The title is a normal `&str` and so can be directly compared"
2132        );
2133        assert_eq!(
2134            message.original.get(),
2135            &json,
2136            "The original has not been modified in any way"
2137        );
2138    }
2139
2140    #[test]
2141    fn should_deser_number_as_i64() {
2142        const JSON: &str = "123";
2143        let json: &RawValue = serde_json::from_str(JSON).unwrap();
2144
2145        let n = i64::deserialize(json.into_deserializer()).unwrap();
2146
2147        assert_eq!(n, 123);
2148    }
2149
2150    #[test]
2151    fn should_convert_json_string_to_str() {
2152        /// A Song where the `title` field is borrowed from the original JSON String.
2153        #[derive(Deserialize)]
2154        struct Song<'a> {
2155            title: &'a str,
2156        }
2157
2158        /// A Song with the original JSON stored alongside.
2159        ///
2160        /// Where all fields are borrowed.
2161        struct SongMessage<'a> {
2162            song: Song<'a>,
2163            original: &'a RawValue,
2164        }
2165
2166        // This is the only heap allocation in this test.
2167        let json = format!(r#"{{ "title": "{TITLE}" }}"#);
2168
2169        // The JSON bytes contained in the original String are borrowed to the `RawValue(str)`.
2170        let raw_json: &RawValue = serde_json::from_str(&json)
2171            .expect("Typically we want to parse some JSON from an endpoint first");
2172        // The bytes borrowed to the `RawValue` are in turn, borrowed to `Song::title`.
2173        let song =
2174            Song::<'_>::deserialize(raw_json.into_deserializer()).expect("And then introspect it");
2175        // The original JSON bytes are borrowed to the `SongMessage::original` field.
2176        let message = SongMessage {
2177            song,
2178            original: raw_json,
2179        };
2180
2181        assert_eq!(
2182            message.song.title, TITLE,
2183            "The title is a normal `&str` and so can be directly compared"
2184        );
2185        assert_eq!(
2186            message.original.get(),
2187            &json,
2188            "The original has not been modified in any way"
2189        );
2190    }
2191}