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}