1use crate::{
37 diagnostic::{diagnostic_url, Diagnostic, Label},
38 index::{OutOfBoundsError, ParseIndexError},
39 Pointer, PointerBuf, Token,
40};
41use alloc::{boxed::Box, string::ToString};
42use core::iter::once;
43
44pub trait Resolve {
47 type Value;
49
50 type Error;
52
53 fn resolve(&self, ptr: &Pointer) -> Result<&Self::Value, Self::Error>;
59}
60
61pub trait ResolveMut {
64 type Value;
66
67 type Error;
69
70 fn resolve_mut(&mut self, ptr: &Pointer) -> Result<&mut Self::Value, Self::Error>;
77}
78
79pub type ResolveError = Error;
82
83#[derive(Debug, PartialEq, Eq)]
85pub enum Error {
86 FailedToParseIndex {
98 position: usize,
100 offset: usize,
102 source: ParseIndexError,
104 },
105
106 OutOfBounds {
117 position: usize,
119 offset: usize,
121 source: OutOfBoundsError,
123 },
124
125 NotFound {
136 position: usize,
138 offset: usize,
140 },
141
142 Unreachable {
155 position: usize,
157 offset: usize,
159 },
160}
161
162impl Error {
163 pub fn offset(&self) -> usize {
166 match self {
167 Self::FailedToParseIndex { offset, .. }
168 | Self::OutOfBounds { offset, .. }
169 | Self::NotFound { offset, .. }
170 | Self::Unreachable { offset, .. } => *offset,
171 }
172 }
173
174 pub fn position(&self) -> usize {
176 match self {
177 Self::FailedToParseIndex { position, .. }
178 | Self::OutOfBounds { position, .. }
179 | Self::NotFound { position, .. }
180 | Self::Unreachable { position, .. } => *position,
181 }
182 }
183
184 pub fn is_unreachable(&self) -> bool {
187 matches!(self, Self::Unreachable { .. })
188 }
189
190 pub fn is_not_found(&self) -> bool {
193 matches!(self, Self::NotFound { .. })
194 }
195
196 pub fn is_out_of_bounds(&self) -> bool {
199 matches!(self, Self::OutOfBounds { .. })
200 }
201
202 pub fn is_failed_to_parse_index(&self) -> bool {
205 matches!(self, Self::FailedToParseIndex { .. })
206 }
207}
208
209impl Diagnostic for Error {
210 type Subject = PointerBuf;
211
212 fn url() -> &'static str {
213 diagnostic_url!(enum assign::Error)
214 }
215
216 fn labels(&self, origin: &Self::Subject) -> Option<Box<dyn Iterator<Item = Label>>> {
217 let position = self.position();
218 let token = origin.get(position)?;
219 let offset = if self.offset() + 1 < origin.as_str().len() {
220 self.offset() + 1
221 } else {
222 self.offset()
223 };
224 let len = token.encoded().len();
225 let text = match self {
226 Error::FailedToParseIndex { .. } => "not an array index".to_string(),
227 Error::OutOfBounds { source, .. } => source.to_string(),
228 Error::NotFound { .. } => "not found in value".to_string(),
229 Error::Unreachable { .. } => "unreachable".to_string(),
230 };
231 Some(Box::new(once(Label::new(text, offset, len))))
232 }
233}
234
235impl core::fmt::Display for Error {
236 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
237 match self {
238 Self::FailedToParseIndex { offset, .. } => {
239 write!(f, "resolve failed: json pointer token at offset {offset} failed to parse as an index")
240 }
241 Self::OutOfBounds { offset, .. } => {
242 write!(
243 f,
244 "resolve failed: json pointer token at offset {offset} is out of bounds"
245 )
246 }
247 Self::NotFound { offset, .. } => {
248 write!(
249 f,
250 "resolve failed: json pointer token at {offset} was not found in value"
251 )
252 }
253 Self::Unreachable { offset, .. } => {
254 write!(f, "resolve failed: json pointer token at {offset} is unreachable (previous token resolved to a scalar or null value)")
255 }
256 }
257 }
258}
259
260#[cfg(feature = "std")]
261impl std::error::Error for Error {
262 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
263 match self {
264 Self::FailedToParseIndex { source, .. } => Some(source),
265 Self::OutOfBounds { source, .. } => Some(source),
266 _ => None,
267 }
268 }
269}
270
271#[cfg(feature = "json")]
272mod json {
273 use super::{parse_index, Error, Pointer, Resolve, ResolveMut};
274 use serde_json::Value;
275
276 impl Resolve for Value {
277 type Value = Value;
278 type Error = Error;
279
280 fn resolve(&self, mut ptr: &Pointer) -> Result<&Value, Self::Error> {
281 let mut offset = 0;
282 let mut position = 0;
283 let mut value = self;
284 while let Some((token, rem)) = ptr.split_front() {
285 let tok_len = token.encoded().len();
286 ptr = rem;
287 value = match value {
288 Value::Array(v) => {
289 let idx = token
290 .to_index()
291 .map_err(|source| Error::FailedToParseIndex {
292 position,
293 offset,
294 source,
295 })?
296 .for_len(v.len())
297 .map_err(|source| Error::OutOfBounds {
298 position,
299 offset,
300 source,
301 })?;
302 Ok(&v[idx])
303 }
304
305 Value::Object(v) => v
306 .get(token.decoded().as_ref())
307 .ok_or(Error::NotFound { position, offset }),
308 _ => Err(Error::Unreachable { position, offset }),
310 }?;
311 offset += 1 + tok_len;
312 position += 1;
313 }
314 Ok(value)
315 }
316 }
317
318 impl ResolveMut for Value {
319 type Value = Value;
320 type Error = Error;
321
322 fn resolve_mut(&mut self, mut ptr: &Pointer) -> Result<&mut Value, Error> {
323 let mut offset = 0;
324 let mut position = 0;
325 let mut value = self;
326 while let Some((token, rem)) = ptr.split_front() {
327 let tok_len = token.encoded().len();
328 ptr = rem;
329 value = match value {
330 Value::Array(array) => {
331 let idx = parse_index(token, array.len(), position, offset)?;
332 Ok(&mut array[idx])
333 }
334 Value::Object(v) => v
335 .get_mut(token.decoded().as_ref())
336 .ok_or(Error::NotFound { position, offset }),
337 _ => Err(Error::Unreachable { position, offset }),
339 }?;
340 offset += 1 + tok_len;
341 position += 1;
342 }
343 Ok(value)
344 }
345 }
346}
347fn parse_index(
348 token: Token,
349 array_len: usize,
350 position: usize,
351 offset: usize,
352) -> Result<usize, Error> {
353 token
354 .to_index()
355 .map_err(|source| Error::FailedToParseIndex {
356 position,
357 offset,
358 source,
359 })?
360 .for_len(array_len)
361 .map_err(|source| Error::OutOfBounds {
362 position,
363 offset,
364 source,
365 })
366}
367
368#[cfg(feature = "toml")]
369mod toml {
370 use super::{Error, Resolve, ResolveMut};
371 use crate::Pointer;
372 use toml::Value;
373
374 impl Resolve for Value {
375 type Value = Value;
376 type Error = Error;
377
378 fn resolve(&self, mut ptr: &Pointer) -> Result<&Value, Self::Error> {
379 let mut offset = 0;
380 let mut position = 0;
381 let mut value = self;
382 while let Some((token, rem)) = ptr.split_front() {
383 let tok_len = token.encoded().len();
384 ptr = rem;
385 value = match value {
386 Value::Array(v) => {
387 let idx = token
388 .to_index()
389 .map_err(|source| Error::FailedToParseIndex {
390 position,
391 offset,
392 source,
393 })?
394 .for_len(v.len())
395 .map_err(|source| Error::OutOfBounds {
396 position,
397 offset,
398 source,
399 })?;
400 Ok(&v[idx])
401 }
402
403 Value::Table(v) => v
404 .get(token.decoded().as_ref())
405 .ok_or(Error::NotFound { position, offset }),
406 _ => Err(Error::Unreachable { position, offset }),
408 }?;
409 offset += 1 + tok_len;
410 position += 1;
411 }
412 Ok(value)
413 }
414 }
415
416 impl ResolveMut for Value {
417 type Value = Value;
418 type Error = Error;
419
420 fn resolve_mut(&mut self, mut ptr: &Pointer) -> Result<&mut Value, Error> {
421 let mut offset = 0;
422 let mut position = 0;
423
424 let mut value = self;
425 while let Some((token, rem)) = ptr.split_front() {
426 let tok_len = token.encoded().len();
427 ptr = rem;
428 value = match value {
429 Value::Array(array) => {
430 let idx = token
431 .to_index()
432 .map_err(|source| Error::FailedToParseIndex {
433 position,
434 offset,
435 source,
436 })?
437 .for_len(array.len())
438 .map_err(|source| Error::OutOfBounds {
439 position,
440 offset,
441 source,
442 })?;
443 Ok(&mut array[idx])
444 }
445 Value::Table(v) => v
446 .get_mut(token.decoded().as_ref())
447 .ok_or(Error::NotFound { position, offset }),
448 _ => Err(Error::Unreachable { position, offset }),
450 }?;
451 offset += 1 + tok_len;
452 position += 1;
453 }
454 Ok(value)
455 }
456 }
457}
458
459#[cfg(test)]
460mod tests {
461 use super::{Error, Resolve, ResolveMut};
462 use crate::{
463 index::{OutOfBoundsError, ParseIndexError},
464 Pointer,
465 };
466 use core::fmt;
467
468 #[test]
469 fn resolve_error_is_unreachable() {
470 let err = Error::FailedToParseIndex {
471 position: 0,
472 offset: 0,
473 source: ParseIndexError::InvalidInteger("invalid".parse::<usize>().unwrap_err()),
474 };
475 assert!(!err.is_unreachable());
476
477 let err = Error::OutOfBounds {
478 position: 0,
479 offset: 0,
480 source: OutOfBoundsError {
481 index: 1,
482 length: 0,
483 },
484 };
485 assert!(!err.is_unreachable());
486
487 let err = Error::NotFound {
488 position: 0,
489 offset: 0,
490 };
491 assert!(!err.is_unreachable());
492
493 let err = Error::Unreachable {
494 position: 0,
495 offset: 0,
496 };
497 assert!(err.is_unreachable());
498 }
499
500 #[test]
501 fn resolve_error_is_not_found() {
502 let err = Error::FailedToParseIndex {
503 position: 0,
504 offset: 0,
505 source: ParseIndexError::InvalidInteger("invalid".parse::<usize>().unwrap_err()),
506 };
507 assert!(!err.is_not_found());
508
509 let err = Error::OutOfBounds {
510 position: 0,
511 offset: 0,
512 source: OutOfBoundsError {
513 index: 1,
514 length: 0,
515 },
516 };
517 assert!(!err.is_not_found());
518
519 let err = Error::NotFound {
520 position: 0,
521 offset: 0,
522 };
523 assert!(err.is_not_found());
524
525 let err = Error::Unreachable {
526 position: 0,
527 offset: 0,
528 };
529 assert!(!err.is_not_found());
530 }
531
532 #[test]
533 fn resolve_error_is_out_of_bounds() {
534 let err = Error::FailedToParseIndex {
535 position: 0,
536 offset: 0,
537 source: ParseIndexError::InvalidInteger("invalid".parse::<usize>().unwrap_err()),
538 };
539 assert!(!err.is_out_of_bounds());
540
541 let err = Error::OutOfBounds {
542 position: 0,
543 offset: 0,
544 source: OutOfBoundsError {
545 index: 1,
546 length: 0,
547 },
548 };
549 assert!(err.is_out_of_bounds());
550
551 let err = Error::NotFound {
552 position: 0,
553 offset: 0,
554 };
555 assert!(!err.is_out_of_bounds());
556
557 let err = Error::Unreachable {
558 position: 0,
559 offset: 0,
560 };
561 assert!(!err.is_out_of_bounds());
562 }
563
564 #[test]
565 fn resolve_error_is_failed_to_parse_index() {
566 let err = Error::FailedToParseIndex {
567 position: 0,
568 offset: 0,
569 source: ParseIndexError::InvalidInteger("invalid".parse::<usize>().unwrap_err()),
570 };
571 assert!(err.is_failed_to_parse_index());
572
573 let err = Error::OutOfBounds {
574 position: 0,
575 offset: 0,
576 source: OutOfBoundsError {
577 index: 1,
578 length: 0,
579 },
580 };
581 assert!(!err.is_failed_to_parse_index());
582
583 let err = Error::NotFound {
584 position: 0,
585 offset: 0,
586 };
587 assert!(!err.is_failed_to_parse_index());
588
589 let err = Error::Unreachable {
590 position: 0,
591 offset: 0,
592 };
593 assert!(!err.is_failed_to_parse_index());
594 }
595
596 #[test]
603 #[cfg(feature = "json")]
604 fn resolve_json() {
605 use serde_json::json;
606
607 let data = &json!({
608 "array": ["bar", "baz"],
609 "object": {
610 "object": {"baz": {"qux": "quux"}},
611 "strings": ["zero", "one", "two"],
612 "nothing": null,
613 "bool": true,
614 "objects": [{"field": "zero"}, {"field": "one"}, {"field": "two"}]
615 },
616 "": 0,
617 "a/b": 1,
618 "c%d": 2,
619 "e^f": 3,
620 "g|h": 4,
621 "i\\j": 5,
622 "k\"l": 6,
623 " ": 7,
624 "m~n": 8
625 });
626 Test::all([
629 Test {
631 ptr: "",
632 data,
633 expected: Ok(data),
634 },
635 Test {
637 ptr: "/array",
638 data,
639 expected: Ok(data.get("array").unwrap()), },
641 Test {
643 ptr: "/array/0",
644 data,
645 expected: Ok(data.get("array").unwrap().get(0).unwrap()), },
647 Test {
649 ptr: "/a~1b",
650 data,
651 expected: Ok(data.get("a/b").unwrap()), },
653 Test {
655 ptr: "/c%d",
656 data,
657 expected: Ok(data.get("c%d").unwrap()), },
659 Test {
661 ptr: "/e^f",
662 data,
663 expected: Ok(data.get("e^f").unwrap()), },
665 Test {
667 ptr: "/g|h",
668 data,
669 expected: Ok(data.get("g|h").unwrap()), },
671 Test {
673 ptr: "/i\\j",
674 data,
675 expected: Ok(data.get("i\\j").unwrap()), },
677 Test {
679 ptr: "/k\"l",
680 data,
681 expected: Ok(data.get("k\"l").unwrap()), },
683 Test {
685 ptr: "/ ",
686 data,
687 expected: Ok(data.get(" ").unwrap()), },
689 Test {
691 ptr: "/m~0n",
692 data,
693 expected: Ok(data.get("m~n").unwrap()), },
695 Test {
697 ptr: "/object/bool/unresolvable",
698 data,
699 expected: Err(Error::Unreachable {
700 position: 2,
701 offset: 12,
702 }),
703 },
704 Test {
706 ptr: "/object/not_found",
707 data,
708 expected: Err(Error::NotFound {
709 position: 1,
710 offset: 7,
711 }),
712 },
713 ]);
714 }
715
716 #[test]
722 #[cfg(feature = "toml")]
723 fn resolve_toml() {
724 use toml::{toml, Value};
725
726 let data = &Value::Table(toml! {
727 "array" = ["bar", "baz"]
728 "object" = {
729 "object" = {"baz" = {"qux" = "quux"}},
730 "strings" = ["zero", "one", "two"],
731 "bool" = true,
732 "objects" = [{"field" = "zero"}, {"field" = "one"}, {"field" = "two"}]
733 }
734 "" = 0
735 "a/b" = 1
736 "c%d" = 2
737 "e^f" = 3
738 "g|h" = 4
739 "i\\j" = 5
740 "k\"l" = 6
741 " " = 7
742 "m~n" = 8
743 });
744 Test::all([
747 Test {
748 ptr: "",
749 data,
750 expected: Ok(data),
751 },
752 Test {
753 ptr: "/array",
754 data,
755 expected: Ok(data.get("array").unwrap()), },
757 Test {
758 ptr: "/array/0",
759 data,
760 expected: Ok(data.get("array").unwrap().get(0).unwrap()), },
762 Test {
763 ptr: "/a~1b",
764 data,
765 expected: Ok(data.get("a/b").unwrap()), },
767 Test {
768 ptr: "/c%d",
769 data,
770 expected: Ok(data.get("c%d").unwrap()), },
772 Test {
773 ptr: "/e^f",
774 data,
775 expected: Ok(data.get("e^f").unwrap()), },
777 Test {
778 ptr: "/g|h",
779 data,
780 expected: Ok(data.get("g|h").unwrap()), },
782 Test {
783 ptr: "/i\\j",
784 data,
785 expected: Ok(data.get("i\\j").unwrap()), },
787 Test {
788 ptr: "/k\"l",
789 data,
790 expected: Ok(data.get("k\"l").unwrap()), },
792 Test {
793 ptr: "/ ",
794 data,
795 expected: Ok(data.get(" ").unwrap()), },
797 Test {
798 ptr: "/m~0n",
799 data,
800 expected: Ok(data.get("m~n").unwrap()), },
802 Test {
803 ptr: "/object/bool/unresolvable",
804 data,
805 expected: Err(Error::Unreachable {
806 position: 2,
807 offset: 12,
808 }),
809 },
810 Test {
811 ptr: "/object/not_found",
812 data,
813 expected: Err(Error::NotFound {
814 position: 1,
815 offset: 7,
816 }),
817 },
818 ]);
819 }
820 struct Test<'v, V> {
821 ptr: &'static str,
822 expected: Result<&'v V, Error>,
823 data: &'v V,
824 }
825
826 impl<'v, V> Test<'v, V>
827 where
828 V: Resolve<Value = V, Error = Error>
829 + ResolveMut<Value = V, Error = Error>
830 + Clone
831 + PartialEq
832 + fmt::Display
833 + fmt::Debug,
834 {
835 fn all(tests: impl IntoIterator<Item = Test<'v, V>>) {
836 tests.into_iter().enumerate().for_each(|(i, t)| t.run(i));
837 }
838
839 fn run(self, _i: usize) {
840 _ = self;
841 let Test {
842 ptr,
843 data,
844 expected,
845 } = self;
846 let ptr = Pointer::from_static(ptr);
847
848 let mut data = data.clone();
850 let expected = expected.cloned();
851
852 let res = data.resolve(ptr).cloned();
854 assert_eq!(&res, &expected);
855
856 let res = data.resolve_mut(ptr).cloned();
858 assert_eq!(&res, &expected);
859 }
860 }
861}