ocpi_tariffs/
json.rs

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