jsonptr/
resolve.rs

1//! # Resolve values based on JSON [`Pointer`]s
2//!
3//! This module provides the [`Resolve`] and [`ResolveMut`] traits which are
4//! implemented by types that can internally resolve a value based on a JSON
5//! Pointer.
6//!
7//! This module is enabled by default with the `"resolve"` feature flag.
8//!
9//! ## Usage
10//! [`Resolve`] and [`ResolveMut`] can be used directly or through the
11//! [`resolve`](Pointer::resolve) and [`resolve_mut`](Pointer::resolve_mut)
12//! methods on [`Pointer`] and [`PointerBuf`](crate::PointerBuf).
13//!
14//! ```rust
15//! use jsonptr::{Pointer, Resolve, ResolveMut};
16//! use serde_json::json;
17//!
18//! let ptr = Pointer::from_static("/foo/1");
19//! let mut data = json!({"foo": ["bar", "baz"]});
20//!
21//! let value = ptr.resolve(&data).unwrap();
22//! assert_eq!(value, &json!("baz"));
23//!
24//! let value = data.resolve_mut(ptr).unwrap();
25//! assert_eq!(value, &json!("baz"));
26//! ```
27//!
28//! ## Provided implementations
29//!
30//! | Lang  |     value type      | feature flag | Default |
31//! | ----- |: ----------------- :|: ---------- :| ------- |
32//! | JSON  | `serde_json::Value` |   `"json"`   |   ✓     |
33//! | TOML  |    `toml::Value`    |   `"toml"`   |         |
34//!
35//!
36use crate::{
37    index::{OutOfBoundsError, ParseIndexError},
38    Pointer, Token,
39};
40
41/*
42░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
43╔══════════════════════════════════════════════════════════════════════════════╗
44║                                                                              ║
45║                                   Resolve                                    ║
46║                                  ¯¯¯¯¯¯¯¯¯                                   ║
47╚══════════════════════════════════════════════════════════════════════════════╝
48░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
49*/
50
51/// A trait implemented by types which can resolve a reference to a value type
52/// from a path represented by a JSON [`Pointer`].
53pub trait Resolve {
54    /// The type of value that this implementation can operate on.
55    type Value;
56
57    /// Error associated with `Resolve`
58    type Error;
59
60    /// Resolve a reference to `Self::Value` based on the path in a [Pointer].
61    ///
62    /// ## Errors
63    /// Returns a [`Self::Error`](Resolve::Error) if the [`Pointer`] can not
64    /// be resolved.
65    fn resolve(&self, ptr: &Pointer) -> Result<&Self::Value, Self::Error>;
66}
67
68/*
69░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
70╔══════════════════════════════════════════════════════════════════════════════╗
71║                                                                              ║
72║                                 ResolveMut                                   ║
73║                                ¯¯¯¯¯¯¯¯¯¯¯¯                                  ║
74╚══════════════════════════════════════════════════════════════════════════════╝
75░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
76*/
77
78/// A trait implemented by types which can resolve a mutable reference to a
79/// value type from a path represented by a JSON [`Pointer`].
80pub trait ResolveMut {
81    /// The type of value that is being resolved.
82    type Value;
83
84    /// Error associated with `ResolveMut`
85    type Error;
86
87    /// Resolve a mutable reference to a `serde_json::Value` based on the path
88    /// in a JSON Pointer.
89    ///
90    /// ## Errors
91    /// Returns a [`Self::Error`](ResolveMut::Error) if the [`Pointer`] can not
92    /// be resolved.
93    fn resolve_mut(&mut self, ptr: &Pointer) -> Result<&mut Self::Value, Self::Error>;
94}
95
96/*
97░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
98╔══════════════════════════════════════════════════════════════════════════════╗
99║                                                                              ║
100║                                 ResolveError                                 ║
101║                                ¯¯¯¯¯¯¯¯¯¯¯¯¯¯                                ║
102╚══════════════════════════════════════════════════════════════════════════════╝
103░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
104*/
105
106/// Indicates that the `Pointer` could not be resolved.
107#[derive(Debug, PartialEq, Eq)]
108pub enum ResolveError {
109    /// `Pointer` could not be resolved because a `Token` for an array index is
110    /// not a valid integer or dash (`"-"`).
111    ///
112    /// ## Example
113    /// ```rust
114    /// # use serde_json::json;
115    /// # use jsonptr::Pointer;
116    /// let data = json!({ "foo": ["bar"] });
117    /// let ptr = Pointer::from_static("/foo/invalid");
118    /// assert!(ptr.resolve(&data).unwrap_err().is_failed_to_parse_index());
119    /// ```
120    FailedToParseIndex {
121        /// Offset of the partial pointer starting with the invalid index.
122        offset: usize,
123        /// The source `ParseIndexError`
124        source: ParseIndexError,
125    },
126
127    /// `Pointer` could not be resolved due to an index being out of bounds
128    /// within an array.
129    ///
130    /// ## Example
131    /// ```rust
132    /// # use serde_json::json;
133    /// # use jsonptr::Pointer;
134    /// let data = json!({ "foo": ["bar"] });
135    /// let ptr = Pointer::from_static("/foo/1");
136    /// assert!(ptr.resolve(&data).unwrap_err().is_out_of_bounds());
137    OutOfBounds {
138        /// Offset of the partial pointer starting with the invalid index.
139        offset: usize,
140        /// The source `OutOfBoundsError`
141        source: OutOfBoundsError,
142    },
143
144    /// `Pointer` could not be resolved as a segment of the path was not found.
145    ///
146    /// ## Example
147    /// ```rust
148    /// # use serde_json::json;
149    /// # use jsonptr::{Pointer};
150    /// let mut data = json!({ "foo": "bar" });
151    /// let ptr = Pointer::from_static("/bar");
152    /// assert!(ptr.resolve(&data).unwrap_err().is_not_found());
153    /// ```
154    NotFound {
155        /// Offset of the pointer starting with the `Token` which was not found.
156        offset: usize,
157    },
158
159    /// `Pointer` could not be resolved as the path contains a scalar value
160    /// before fully exhausting the path.
161    ///
162    /// ## Example
163    /// ```rust
164    /// # use serde_json::json;
165    /// # use jsonptr::Pointer;
166    /// let mut data = json!({ "foo": "bar" });
167    /// let ptr = Pointer::from_static("/foo/unreachable");
168    /// let err = ptr.resolve(&data).unwrap_err();
169    /// assert!(err.is_unreachable());
170    /// ```
171    Unreachable {
172        /// Offset of the pointer which was unreachable.
173        offset: usize,
174    },
175}
176
177impl ResolveError {
178    /// Offset of the partial pointer starting with the token which caused the
179    /// error.
180    pub fn offset(&self) -> usize {
181        match self {
182            Self::FailedToParseIndex { offset, .. }
183            | Self::OutOfBounds { offset, .. }
184            | Self::NotFound { offset, .. }
185            | Self::Unreachable { offset, .. } => *offset,
186        }
187    }
188
189    /// Returns `true` if this error is `FailedToParseIndex`; otherwise returns
190    /// `false`.
191    pub fn is_unreachable(&self) -> bool {
192        matches!(self, Self::Unreachable { .. })
193    }
194
195    /// Returns `true` if this error is `FailedToParseIndex`; otherwise returns
196    /// `false`.
197    pub fn is_not_found(&self) -> bool {
198        matches!(self, Self::NotFound { .. })
199    }
200
201    /// Returns `true` if this error is `FailedToParseIndex`; otherwise returns
202    /// `false`.
203    pub fn is_out_of_bounds(&self) -> bool {
204        matches!(self, Self::OutOfBounds { .. })
205    }
206
207    /// Returns `true` if this error is `FailedToParseIndex`; otherwise returns
208    /// `false`.
209    pub fn is_failed_to_parse_index(&self) -> bool {
210        matches!(self, Self::FailedToParseIndex { .. })
211    }
212}
213
214impl core::fmt::Display for ResolveError {
215    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
216        match self {
217            Self::FailedToParseIndex { offset, .. } => {
218                write!(f, "failed to parse index at offset {offset}")
219            }
220            Self::OutOfBounds { offset, .. } => {
221                write!(f, "index at offset {offset} out of bounds")
222            }
223            Self::NotFound { offset, .. } => {
224                write!(f, "pointer starting at offset {offset} not found")
225            }
226            Self::Unreachable { offset, .. } => {
227                write!(f, "pointer starting at offset {offset} is unreachable")
228            }
229        }
230    }
231}
232
233#[cfg(feature = "std")]
234impl std::error::Error for ResolveError {
235    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
236        match self {
237            Self::FailedToParseIndex { source, .. } => Some(source),
238            Self::OutOfBounds { source, .. } => Some(source),
239            _ => None,
240        }
241    }
242}
243
244/*
245░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
246╔══════════════════════════════════════════════════════════════════════════════╗
247║                                                                              ║
248║                                  json impl                                   ║
249║                                 ¯¯¯¯¯¯¯¯¯¯¯                                  ║
250╚══════════════════════════════════════════════════════════════════════════════╝
251░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
252*/
253
254#[cfg(feature = "json")]
255mod json {
256    use super::{parse_index, Pointer, Resolve, ResolveError, ResolveMut};
257    use serde_json::Value;
258
259    impl Resolve for Value {
260        type Value = Value;
261        type Error = ResolveError;
262
263        fn resolve(&self, mut ptr: &Pointer) -> Result<&Value, Self::Error> {
264            let mut offset = 0;
265            let mut value = self;
266            while let Some((token, rem)) = ptr.split_front() {
267                let tok_len = token.encoded().len();
268                ptr = rem;
269                value = match value {
270                    Value::Array(v) => {
271                        let idx = token
272                            .to_index()
273                            .map_err(|source| ResolveError::FailedToParseIndex { offset, source })?
274                            .for_len(v.len())
275                            .map_err(|source| ResolveError::OutOfBounds { offset, source })?;
276                        Ok(&v[idx])
277                    }
278
279                    Value::Object(v) => v
280                        .get(token.decoded().as_ref())
281                        .ok_or(ResolveError::NotFound { offset }),
282                    // found a leaf node but the pointer hasn't been exhausted
283                    _ => Err(ResolveError::Unreachable { offset }),
284                }?;
285                offset += 1 + tok_len;
286            }
287            Ok(value)
288        }
289    }
290
291    impl ResolveMut for Value {
292        type Value = Value;
293        type Error = ResolveError;
294
295        fn resolve_mut(&mut self, mut ptr: &Pointer) -> Result<&mut Value, ResolveError> {
296            let mut offset = 0;
297            let mut value = self;
298            while let Some((token, rem)) = ptr.split_front() {
299                let tok_len = token.encoded().len();
300                ptr = rem;
301                value = match value {
302                    Value::Array(array) => {
303                        let idx = parse_index(token, array.len(), offset)?;
304                        Ok(&mut array[idx])
305                    }
306                    Value::Object(v) => v
307                        .get_mut(token.decoded().as_ref())
308                        .ok_or(ResolveError::NotFound { offset }),
309                    // found a leaf node but the pointer hasn't been exhausted
310                    _ => Err(ResolveError::Unreachable { offset }),
311                }?;
312                offset += 1 + tok_len;
313            }
314            Ok(value)
315        }
316    }
317}
318fn parse_index(token: Token, array_len: usize, offset: usize) -> Result<usize, ResolveError> {
319    token
320        .to_index()
321        .map_err(|source| ResolveError::FailedToParseIndex { offset, source })?
322        .for_len(array_len)
323        .map_err(|source| ResolveError::OutOfBounds { offset, source })
324}
325
326/*
327░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
328╔══════════════════════════════════════════════════════════════════════════════╗
329║                                                                              ║
330║                                  toml impl                                   ║
331║                                 ¯¯¯¯¯¯¯¯¯¯¯                                  ║
332╚══════════════════════════════════════════════════════════════════════════════╝
333░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
334*/
335
336#[cfg(feature = "toml")]
337mod toml {
338    use super::{Resolve, ResolveError, ResolveMut};
339    use crate::Pointer;
340    use toml::Value;
341
342    impl Resolve for Value {
343        type Value = Value;
344        type Error = ResolveError;
345
346        fn resolve(&self, mut ptr: &Pointer) -> Result<&Value, Self::Error> {
347            let mut offset = 0;
348            let mut value = self;
349            while let Some((token, rem)) = ptr.split_front() {
350                let tok_len = token.encoded().len();
351                ptr = rem;
352                value = match value {
353                    Value::Array(v) => {
354                        let idx = token
355                            .to_index()
356                            .map_err(|source| ResolveError::FailedToParseIndex { offset, source })?
357                            .for_len(v.len())
358                            .map_err(|source| ResolveError::OutOfBounds { offset, source })?;
359                        Ok(&v[idx])
360                    }
361
362                    Value::Table(v) => v
363                        .get(token.decoded().as_ref())
364                        .ok_or(ResolveError::NotFound { offset }),
365                    // found a leaf node but the pointer hasn't been exhausted
366                    _ => Err(ResolveError::Unreachable { offset }),
367                }?;
368                offset += 1 + tok_len;
369            }
370            Ok(value)
371        }
372    }
373
374    impl ResolveMut for Value {
375        type Value = Value;
376        type Error = ResolveError;
377
378        fn resolve_mut(&mut self, mut ptr: &Pointer) -> Result<&mut Value, ResolveError> {
379            let mut offset = 0;
380            let mut value = self;
381            while let Some((token, rem)) = ptr.split_front() {
382                let tok_len = token.encoded().len();
383                ptr = rem;
384                value = match value {
385                    Value::Array(array) => {
386                        let idx = token
387                            .to_index()
388                            .map_err(|source| ResolveError::FailedToParseIndex { offset, source })?
389                            .for_len(array.len())
390                            .map_err(|source| ResolveError::OutOfBounds { offset, source })?;
391                        Ok(&mut array[idx])
392                    }
393                    Value::Table(v) => v
394                        .get_mut(token.decoded().as_ref())
395                        .ok_or(ResolveError::NotFound { offset }),
396                    // found a leaf node but the pointer hasn't been exhausted
397                    _ => Err(ResolveError::Unreachable { offset }),
398                }?;
399                offset += 1 + tok_len;
400            }
401            Ok(value)
402        }
403    }
404}
405
406/*
407░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
408╔══════════════════════════════════════════════════════════════════════════════╗
409║                                                                              ║
410║                                    Tests                                     ║
411║                                   ¯¯¯¯¯¯¯                                    ║
412╚══════════════════════════════════════════════════════════════════════════════╝
413░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
414*/
415
416#[cfg(test)]
417mod tests {
418    use super::{Resolve, ResolveError, ResolveMut};
419    use crate::{
420        index::{OutOfBoundsError, ParseIndexError},
421        Pointer,
422    };
423    use core::fmt;
424
425    #[cfg(feature = "std")]
426    #[test]
427    fn resolve_error_source() {
428        use std::error::Error;
429        let err = ResolveError::FailedToParseIndex {
430            offset: 0,
431            source: ParseIndexError::InvalidInteger("invalid".parse::<usize>().unwrap_err()),
432        };
433        assert!(err.source().is_some());
434
435        let err = ResolveError::OutOfBounds {
436            offset: 0,
437            source: OutOfBoundsError {
438                index: 1,
439                length: 0,
440            },
441        };
442        assert!(err.source().is_some());
443
444        let err = ResolveError::NotFound { offset: 0 };
445        assert!(err.source().is_none());
446
447        let err = ResolveError::Unreachable { offset: 0 };
448        assert!(err.source().is_none());
449    }
450
451    #[test]
452    fn resolve_error_display() {
453        let err = ResolveError::FailedToParseIndex {
454            offset: 0,
455            source: ParseIndexError::InvalidInteger("invalid".parse::<usize>().unwrap_err()),
456        };
457        assert_eq!(format!("{err}"), "failed to parse index at offset 0");
458
459        let err = ResolveError::OutOfBounds {
460            offset: 0,
461            source: OutOfBoundsError {
462                index: 1,
463                length: 0,
464            },
465        };
466        assert_eq!(format!("{err}"), "index at offset 0 out of bounds");
467
468        let err = ResolveError::NotFound { offset: 0 };
469
470        assert_eq!(format!("{err}"), "pointer starting at offset 0 not found");
471
472        let err = ResolveError::Unreachable { offset: 0 };
473        assert_eq!(
474            format!("{err}"),
475            "pointer starting at offset 0 is unreachable"
476        );
477    }
478
479    #[test]
480    fn resolve_error_offset() {
481        let err = ResolveError::FailedToParseIndex {
482            offset: 0,
483            source: ParseIndexError::InvalidInteger("invalid".parse::<usize>().unwrap_err()),
484        };
485        assert_eq!(err.offset(), 0);
486
487        let err = ResolveError::OutOfBounds {
488            offset: 0,
489            source: OutOfBoundsError {
490                index: 1,
491                length: 0,
492            },
493        };
494        assert_eq!(err.offset(), 0);
495
496        let err = ResolveError::NotFound { offset: 0 };
497        assert_eq!(err.offset(), 0);
498
499        let err = ResolveError::Unreachable { offset: 0 };
500        assert_eq!(err.offset(), 0);
501    }
502
503    #[test]
504    fn resolve_error_is_unreachable() {
505        let err = ResolveError::FailedToParseIndex {
506            offset: 0,
507            source: ParseIndexError::InvalidInteger("invalid".parse::<usize>().unwrap_err()),
508        };
509        assert!(!err.is_unreachable());
510
511        let err = ResolveError::OutOfBounds {
512            offset: 0,
513            source: OutOfBoundsError {
514                index: 1,
515                length: 0,
516            },
517        };
518        assert!(!err.is_unreachable());
519
520        let err = ResolveError::NotFound { offset: 0 };
521        assert!(!err.is_unreachable());
522
523        let err = ResolveError::Unreachable { offset: 0 };
524        assert!(err.is_unreachable());
525    }
526
527    #[test]
528    fn resolve_error_is_not_found() {
529        let err = ResolveError::FailedToParseIndex {
530            offset: 0,
531            source: ParseIndexError::InvalidInteger("invalid".parse::<usize>().unwrap_err()),
532        };
533        assert!(!err.is_not_found());
534
535        let err = ResolveError::OutOfBounds {
536            offset: 0,
537            source: OutOfBoundsError {
538                index: 1,
539                length: 0,
540            },
541        };
542        assert!(!err.is_not_found());
543
544        let err = ResolveError::NotFound { offset: 0 };
545        assert!(err.is_not_found());
546
547        let err = ResolveError::Unreachable { offset: 0 };
548        assert!(!err.is_not_found());
549    }
550
551    #[test]
552    fn resolve_error_is_out_of_bounds() {
553        let err = ResolveError::FailedToParseIndex {
554            offset: 0,
555            source: ParseIndexError::InvalidInteger("invalid".parse::<usize>().unwrap_err()),
556        };
557        assert!(!err.is_out_of_bounds());
558
559        let err = ResolveError::OutOfBounds {
560            offset: 0,
561            source: OutOfBoundsError {
562                index: 1,
563                length: 0,
564            },
565        };
566        assert!(err.is_out_of_bounds());
567
568        let err = ResolveError::NotFound { offset: 0 };
569        assert!(!err.is_out_of_bounds());
570
571        let err = ResolveError::Unreachable { offset: 0 };
572        assert!(!err.is_out_of_bounds());
573    }
574
575    #[test]
576    fn resolve_error_is_failed_to_parse_index() {
577        let err = ResolveError::FailedToParseIndex {
578            offset: 0,
579            source: ParseIndexError::InvalidInteger("invalid".parse::<usize>().unwrap_err()),
580        };
581        assert!(err.is_failed_to_parse_index());
582
583        let err = ResolveError::OutOfBounds {
584            offset: 0,
585            source: OutOfBoundsError {
586                index: 1,
587                length: 0,
588            },
589        };
590        assert!(!err.is_failed_to_parse_index());
591
592        let err = ResolveError::NotFound { offset: 0 };
593        assert!(!err.is_failed_to_parse_index());
594
595        let err = ResolveError::Unreachable { offset: 0 };
596        assert!(!err.is_failed_to_parse_index());
597    }
598
599    /*
600    ╔═══════════════════════════════════════════════════╗
601    ║                        json                       ║
602    ╚═══════════════════════════════════════════════════╝
603    */
604
605    #[test]
606    #[cfg(feature = "json")]
607    fn resolve_json() {
608        use serde_json::json;
609
610        let data = &json!({
611            "array": ["bar", "baz"],
612            "object": {
613                "object": {"baz": {"qux": "quux"}},
614                "strings": ["zero", "one", "two"],
615                "nothing": null,
616                "bool": true,
617                "objects": [{"field": "zero"}, {"field": "one"}, {"field": "two"}]
618            },
619            "": 0,
620            "a/b": 1,
621            "c%d": 2,
622            "e^f": 3,
623            "g|h": 4,
624            "i\\j": 5,
625            "k\"l": 6,
626            " ": 7,
627            "m~n": 8
628        });
629        // let data = &data;
630
631        Test::all([
632            // 0
633            Test {
634                ptr: "",
635                data,
636                expected: Ok(data),
637            },
638            // 1
639            Test {
640                ptr: "/array",
641                data,
642                expected: Ok(data.get("array").unwrap()), // ["bar", "baz"]
643            },
644            // 2
645            Test {
646                ptr: "/array/0",
647                data,
648                expected: Ok(data.get("array").unwrap().get(0).unwrap()), // "bar"
649            },
650            // 3
651            Test {
652                ptr: "/a~1b",
653                data,
654                expected: Ok(data.get("a/b").unwrap()), // 1
655            },
656            // 4
657            Test {
658                ptr: "/c%d",
659                data,
660                expected: Ok(data.get("c%d").unwrap()), // 2
661            },
662            // 5
663            Test {
664                ptr: "/e^f",
665                data,
666                expected: Ok(data.get("e^f").unwrap()), // 3
667            },
668            // 6
669            Test {
670                ptr: "/g|h",
671                data,
672                expected: Ok(data.get("g|h").unwrap()), // 4
673            },
674            // 7
675            Test {
676                ptr: "/i\\j",
677                data,
678                expected: Ok(data.get("i\\j").unwrap()), // 5
679            },
680            // 8
681            Test {
682                ptr: "/k\"l",
683                data,
684                expected: Ok(data.get("k\"l").unwrap()), // 6
685            },
686            // 9
687            Test {
688                ptr: "/ ",
689                data,
690                expected: Ok(data.get(" ").unwrap()), // 7
691            },
692            // 10
693            Test {
694                ptr: "/m~0n",
695                data,
696                expected: Ok(data.get("m~n").unwrap()), // 8
697            },
698            // 11
699            Test {
700                ptr: "/object/bool/unresolvable",
701                data,
702                expected: Err(ResolveError::Unreachable { offset: 12 }),
703            },
704            // 12
705            Test {
706                ptr: "/object/not_found",
707                data,
708                expected: Err(ResolveError::NotFound { offset: 7 }),
709            },
710        ]);
711    }
712
713    /*
714    ╔═══════════════════════════════════════════════════╗
715    ║                        toml                       ║
716    ╚═══════════════════════════════════════════════════╝
717    */
718    #[test]
719    #[cfg(feature = "toml")]
720    fn resolve_toml() {
721        use toml::{toml, Value};
722
723        let data = &Value::Table(toml! {
724            "array" = ["bar", "baz"]
725            "object" = {
726                "object" = {"baz" = {"qux" = "quux"}},
727                "strings" = ["zero", "one", "two"],
728                "bool" = true,
729                "objects" = [{"field" = "zero"}, {"field" = "one"}, {"field" = "two"}]
730            }
731            "" = 0
732            "a/b" = 1
733            "c%d" = 2
734            "e^f" = 3
735            "g|h" = 4
736            "i\\j" = 5
737            "k\"l" = 6
738            " " = 7
739            "m~n" = 8
740        });
741        // let data = &data;
742
743        Test::all([
744            Test {
745                ptr: "",
746                data,
747                expected: Ok(data),
748            },
749            Test {
750                ptr: "/array",
751                data,
752                expected: Ok(data.get("array").unwrap()), // ["bar", "baz"]
753            },
754            Test {
755                ptr: "/array/0",
756                data,
757                expected: Ok(data.get("array").unwrap().get(0).unwrap()), // "bar"
758            },
759            Test {
760                ptr: "/a~1b",
761                data,
762                expected: Ok(data.get("a/b").unwrap()), // 1
763            },
764            Test {
765                ptr: "/c%d",
766                data,
767                expected: Ok(data.get("c%d").unwrap()), // 2
768            },
769            Test {
770                ptr: "/e^f",
771                data,
772                expected: Ok(data.get("e^f").unwrap()), // 3
773            },
774            Test {
775                ptr: "/g|h",
776                data,
777                expected: Ok(data.get("g|h").unwrap()), // 4
778            },
779            Test {
780                ptr: "/i\\j",
781                data,
782                expected: Ok(data.get("i\\j").unwrap()), // 5
783            },
784            Test {
785                ptr: "/k\"l",
786                data,
787                expected: Ok(data.get("k\"l").unwrap()), // 6
788            },
789            Test {
790                ptr: "/ ",
791                data,
792                expected: Ok(data.get(" ").unwrap()), // 7
793            },
794            Test {
795                ptr: "/m~0n",
796                data,
797                expected: Ok(data.get("m~n").unwrap()), // 8
798            },
799            Test {
800                ptr: "/object/bool/unresolvable",
801                data,
802                expected: Err(ResolveError::Unreachable { offset: 12 }),
803            },
804            Test {
805                ptr: "/object/not_found",
806                data,
807                expected: Err(ResolveError::NotFound { offset: 7 }),
808            },
809        ]);
810    }
811    struct Test<'v, V> {
812        ptr: &'static str,
813        expected: Result<&'v V, ResolveError>,
814        data: &'v V,
815    }
816
817    impl<'v, V> Test<'v, V>
818    where
819        V: Resolve<Value = V, Error = ResolveError>
820            + ResolveMut<Value = V, Error = ResolveError>
821            + Clone
822            + PartialEq
823            + fmt::Display
824            + fmt::Debug,
825    {
826        fn all(tests: impl IntoIterator<Item = Test<'v, V>>) {
827            tests.into_iter().enumerate().for_each(|(i, t)| t.run(i));
828        }
829
830        fn run(self, _i: usize) {
831            _ = self;
832            let Test {
833                ptr,
834                data,
835                expected,
836            } = self;
837            let ptr = Pointer::from_static(ptr);
838
839            // cloning the data & expected to make comparison easier
840            let mut data = data.clone();
841            let expected = expected.cloned();
842
843            // testing Resolve
844            let res = data.resolve(ptr).cloned();
845            assert_eq!(&res, &expected);
846
847            // testing ResolveMut
848            let res = data.resolve_mut(ptr).cloned();
849            assert_eq!(&res, &expected);
850        }
851    }
852}