1use crate::{
2 diagnostic::{diagnostic_url, Diagnostic, Label, Report},
3 token::EncodingError,
4 Components, InvalidEncoding, Token, Tokens,
5};
6use alloc::{
7 borrow::{Cow, ToOwned},
8 boxed::Box,
9 fmt,
10 string::{String, ToString},
11 vec::Vec,
12};
13use core::{borrow::Borrow, cmp::Ordering, iter::once, ops::Deref, str::FromStr};
14use slice::PointerIndex;
15
16mod slice;
17
18#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
35#[cfg_attr(not(doc), repr(transparent))]
37pub struct Pointer(str);
38
39impl Default for &'static Pointer {
40 fn default() -> Self {
41 Pointer::root()
42 }
43}
44impl core::fmt::Display for Pointer {
45 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
46 self.0.fmt(f)
47 }
48}
49impl Pointer {
50 pub unsafe fn new_unchecked<S: AsRef<str> + ?Sized>(s: &S) -> &Self {
64 &*(core::ptr::from_ref::<str>(s.as_ref()) as *const Self)
65 }
66
67 pub const fn root() -> &'static Self {
69 #[allow(clippy::ref_as_ptr)]
71 unsafe {
72 &*("" as *const str as *const Self)
73 }
74 }
75
76 pub fn parse<S: AsRef<str> + ?Sized>(s: &S) -> Result<&Self, ParseError> {
83 validate(s.as_ref()).map(|s| unsafe { Self::new_unchecked(s) })
85 }
86
87 pub const fn from_static(s: &'static str) -> &'static Self {
105 assert!(validate(s).is_ok(), "invalid json pointer");
106 unsafe { &*(core::ptr::from_ref::<str>(s) as *const Self) }
107 }
108
109 pub fn as_str(&self) -> &str {
111 &self.0
112 }
113
114 pub fn to_buf(&self) -> PointerBuf {
116 PointerBuf(self.0.to_string())
117 }
118
119 pub fn tokens(&self) -> Tokens {
121 let mut s = self.0.split('/');
122 s.next();
124 Tokens::new(s)
125 }
126
127 pub fn count(&self) -> usize {
129 self.tokens().count()
130 }
131
132 pub fn is_root(&self) -> bool {
134 self.0.is_empty()
135 }
136
137 #[cfg(feature = "json")]
139 pub fn to_json_value(&self) -> serde_json::Value {
140 serde_json::Value::String(self.0.to_string())
141 }
142
143 pub fn back(&self) -> Option<Token> {
145 self.0
146 .rsplit_once('/')
147 .map(|(_, back)| unsafe { Token::from_encoded_unchecked(back) })
149 }
150
151 pub fn last(&self) -> Option<Token> {
155 self.back()
156 }
157
158 pub fn front(&self) -> Option<Token> {
160 if self.is_root() {
161 return None;
162 }
163 self.0[1..]
164 .split_once('/')
165 .map_or_else(
167 || unsafe { Token::from_encoded_unchecked(&self.0[1..]) },
168 |(front, _)| unsafe { Token::from_encoded_unchecked(front) },
169 )
170 .into()
171 }
172
173 pub fn first(&self) -> Option<Token> {
177 self.front()
178 }
179
180 pub fn split_front(&self) -> Option<(Token, &Self)> {
182 if self.is_root() {
183 return None;
184 }
185 self.0[1..]
186 .find('/')
187 .map_or_else(
188 || {
189 (
190 unsafe { Token::from_encoded_unchecked(&self.0[1..]) },
192 Self::root(),
193 )
194 },
195 |idx| {
196 let (front, back) = self.0[1..].split_at(idx);
197 (
198 unsafe { Token::from_encoded_unchecked(front) },
200 unsafe { Self::new_unchecked(back) },
203 )
204 },
205 )
206 .into()
207 }
208
209 pub fn split_at(&self, offset: usize) -> Option<(&Self, &Self)> {
233 if self.0.as_bytes().get(offset).copied() != Some(b'/') {
234 return None;
235 }
236 let (head, tail) = self.0.split_at(offset);
237 unsafe { Some((Self::new_unchecked(head), Self::new_unchecked(tail))) }
239 }
240
241 pub fn split_back(&self) -> Option<(&Self, Token)> {
243 self.0.rsplit_once('/').map(|(front, back)| {
244 (
245 unsafe { Self::new_unchecked(front) },
247 unsafe { Token::from_encoded_unchecked(back) },
249 )
250 })
251 }
252
253 pub fn parent(&self) -> Option<&Self> {
255 self.0
257 .rsplit_once('/')
258 .map(|(front, _)| unsafe { Self::new_unchecked(front) })
259 }
260
261 pub fn strip_suffix<'a>(&'a self, suffix: &Self) -> Option<&'a Self> {
263 self.0
264 .strip_suffix(&suffix.0)
265 .map(|s| unsafe { Self::new_unchecked(s) })
268 }
269
270 pub fn strip_prefix<'a>(&'a self, prefix: &Self) -> Option<&'a Self> {
272 self.0
273 .strip_prefix(&prefix.0)
274 .map(|s| unsafe { Self::new_unchecked(s) })
277 }
278
279 pub fn ends_with(&self, other: &Self) -> bool {
283 (self.is_root() && other.is_root())
284 || (!other.is_root() && self.as_str().ends_with(&other.0))
285 }
286
287 pub fn starts_with(&self, other: &Self) -> bool {
292 self.as_str().starts_with(&other.0)
293 && (other.len() == self.len() || self.0.as_bytes()[other.len()] == b'/')
295 }
296
297 pub fn get<'p, I>(&'p self, index: I) -> Option<I::Output>
318 where
319 I: PointerIndex<'p>,
320 {
321 index.get(self)
322 }
323
324 #[cfg(feature = "resolve")]
345 pub fn resolve<'v, R: crate::Resolve>(&self, value: &'v R) -> Result<&'v R::Value, R::Error> {
346 value.resolve(self)
347 }
348
349 #[cfg(feature = "resolve")]
373 pub fn resolve_mut<'v, R: crate::ResolveMut>(
374 &self,
375 value: &'v mut R,
376 ) -> Result<&'v mut R::Value, R::Error> {
377 value.resolve_mut(self)
378 }
379
380 pub fn intersection<'a>(&'a self, other: &Self) -> &'a Self {
382 if self.is_root() || other.is_root() {
383 return Self::root();
384 }
385 let mut idx = 0;
386 for (a, b) in self.tokens().zip(other.tokens()) {
387 if a != b {
388 break;
389 }
390 idx += a.encoded().len() + 1;
391 }
392 self.split_at(idx).map_or(self, |(head, _)| head)
393 }
394
395 #[cfg(feature = "delete")]
442 pub fn delete<D: crate::Delete>(&self, value: &mut D) -> Option<D::Value> {
443 value.delete(self)
444 }
445
446 #[cfg(feature = "assign")]
469 pub fn assign<D, V>(&self, dest: &mut D, src: V) -> Result<Option<D::Value>, D::Error>
470 where
471 D: crate::Assign,
472 V: Into<D::Value>,
473 {
474 dest.assign(self, src)
475 }
476
477 pub fn components(&self) -> Components {
492 self.into()
493 }
494
495 pub fn with_trailing_token<'t>(&self, token: impl Into<Token<'t>>) -> PointerBuf {
510 let mut buf = self.to_buf();
511 buf.push_back(token.into());
512 buf
513 }
514
515 pub fn with_leading_token<'t>(&self, token: impl Into<Token<'t>>) -> PointerBuf {
530 let mut buf = self.to_buf();
531 buf.push_front(token);
532 buf
533 }
534
535 pub fn concat(&self, other: &Pointer) -> PointerBuf {
551 let mut buf = self.to_buf();
552 buf.append(other);
553 buf
554 }
555
556 pub fn len(&self) -> usize {
571 self.0.len()
572 }
573
574 pub fn is_empty(&self) -> bool {
585 self.0.is_empty()
586 }
587
588 pub fn into_buf(self: Box<Pointer>) -> PointerBuf {
590 let inner = Box::into_raw(self);
591 let inner = unsafe { Box::<str>::from_raw(inner as *mut str) };
593 PointerBuf(inner.into_string())
594 }
595}
596
597#[cfg(feature = "serde")]
598impl serde::Serialize for Pointer {
599 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
600 where
601 S: serde::Serializer,
602 {
603 <str>::serialize(&self.0, serializer)
604 }
605}
606
607#[cfg(feature = "serde")]
608impl<'de: 'p, 'p> serde::Deserialize<'de> for &'p Pointer {
609 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
610 where
611 D: serde::Deserializer<'de>,
612 {
613 use serde::de::{Error, Visitor};
614
615 struct PointerVisitor;
616
617 impl<'a> Visitor<'a> for PointerVisitor {
618 type Value = &'a Pointer;
619
620 fn expecting(&self, formatter: &mut core::fmt::Formatter) -> core::fmt::Result {
621 formatter.write_str("a borrowed Pointer")
622 }
623
624 fn visit_borrowed_str<E>(self, v: &'a str) -> Result<Self::Value, E>
625 where
626 E: Error,
627 {
628 Pointer::parse(v).map_err(|err| {
629 Error::custom(format!("failed to parse json pointer\n\ncaused by:\n{err}"))
630 })
631 }
632 }
633
634 deserializer.deserialize_str(PointerVisitor)
635 }
636}
637
638macro_rules! impl_source_code {
639 ($($ty:ty),+) => {
640 $(
641 #[cfg(feature = "miette")]
642 impl miette::SourceCode for $ty {
643 fn read_span<'a>(
644 &'a self,
645 span: &miette::SourceSpan,
646 context_lines_before: usize,
647 context_lines_after: usize,
648 ) -> Result<Box<dyn miette::SpanContents<'a> + 'a>, miette::MietteError> {
649 miette::SourceCode::read_span(
650 self.0.as_bytes(),
651 span,
652 context_lines_before,
653 context_lines_after,
654 )
655 }
656 }
657 )*
658 };
659}
660
661impl_source_code!(Pointer, &Pointer, PointerBuf);
662
663impl<'p> From<&'p Pointer> for Cow<'p, Pointer> {
664 fn from(value: &'p Pointer) -> Self {
665 Cow::Borrowed(value)
666 }
667}
668
669impl ToOwned for Pointer {
670 type Owned = PointerBuf;
671
672 fn to_owned(&self) -> Self::Owned {
673 self.to_buf()
674 }
675}
676
677impl PartialEq<&str> for Pointer {
678 fn eq(&self, other: &&str) -> bool {
679 &&self.0 == other
680 }
681}
682impl<'p> PartialEq<String> for &'p Pointer {
683 fn eq(&self, other: &String) -> bool {
684 self.0.eq(other)
685 }
686}
687impl PartialEq<str> for Pointer {
688 fn eq(&self, other: &str) -> bool {
689 &self.0 == other
690 }
691}
692
693impl PartialEq<Pointer> for &str {
694 fn eq(&self, other: &Pointer) -> bool {
695 *self == (&other.0)
696 }
697}
698
699impl PartialEq<Pointer> for String {
700 fn eq(&self, other: &Pointer) -> bool {
701 self == &other.0
702 }
703}
704
705impl PartialEq<Pointer> for str {
706 fn eq(&self, other: &Pointer) -> bool {
707 self == &other.0
708 }
709}
710
711impl PartialEq<String> for Pointer {
712 fn eq(&self, other: &String) -> bool {
713 &self.0 == other
714 }
715}
716
717impl PartialEq<PointerBuf> for Pointer {
718 fn eq(&self, other: &PointerBuf) -> bool {
719 self.0 == other.0
720 }
721}
722
723impl PartialEq<Pointer> for PointerBuf {
724 fn eq(&self, other: &Pointer) -> bool {
725 self.0 == other.0
726 }
727}
728impl PartialEq<PointerBuf> for String {
729 fn eq(&self, other: &PointerBuf) -> bool {
730 self == &other.0
731 }
732}
733impl PartialEq<String> for PointerBuf {
734 fn eq(&self, other: &String) -> bool {
735 &self.0 == other
736 }
737}
738
739impl PartialEq<PointerBuf> for str {
740 fn eq(&self, other: &PointerBuf) -> bool {
741 self == other.0
742 }
743}
744impl PartialEq<PointerBuf> for &str {
745 fn eq(&self, other: &PointerBuf) -> bool {
746 *self == other.0
747 }
748}
749
750impl AsRef<Pointer> for Pointer {
751 fn as_ref(&self) -> &Pointer {
752 self
753 }
754}
755impl AsRef<Pointer> for PointerBuf {
756 fn as_ref(&self) -> &Pointer {
757 self
758 }
759}
760
761impl PartialEq<PointerBuf> for &Pointer {
762 fn eq(&self, other: &PointerBuf) -> bool {
763 self.0 == other.0
764 }
765}
766
767impl PartialEq<&Pointer> for PointerBuf {
768 fn eq(&self, other: &&Pointer) -> bool {
769 self.0 == other.0
770 }
771}
772
773#[cfg(feature = "json")]
774impl From<&Pointer> for serde_json::Value {
775 fn from(ptr: &Pointer) -> Self {
776 ptr.to_json_value()
777 }
778}
779
780impl AsRef<str> for Pointer {
781 fn as_ref(&self) -> &str {
782 &self.0
783 }
784}
785
786impl Borrow<str> for Pointer {
787 fn borrow(&self) -> &str {
788 &self.0
789 }
790}
791
792impl AsRef<[u8]> for Pointer {
793 fn as_ref(&self) -> &[u8] {
794 self.0.as_bytes()
795 }
796}
797
798impl PartialOrd<PointerBuf> for Pointer {
799 fn partial_cmp(&self, other: &PointerBuf) -> Option<Ordering> {
800 self.0.partial_cmp(other.0.as_str())
801 }
802}
803
804impl PartialOrd<Pointer> for PointerBuf {
805 fn partial_cmp(&self, other: &Pointer) -> Option<Ordering> {
806 self.0.as_str().partial_cmp(&other.0)
807 }
808}
809impl PartialOrd<&Pointer> for PointerBuf {
810 fn partial_cmp(&self, other: &&Pointer) -> Option<Ordering> {
811 self.0.as_str().partial_cmp(&other.0)
812 }
813}
814
815impl PartialOrd<Pointer> for String {
816 fn partial_cmp(&self, other: &Pointer) -> Option<Ordering> {
817 self.as_str().partial_cmp(&other.0)
818 }
819}
820impl PartialOrd<String> for &Pointer {
821 fn partial_cmp(&self, other: &String) -> Option<Ordering> {
822 self.0.partial_cmp(other.as_str())
823 }
824}
825
826impl PartialOrd<PointerBuf> for String {
827 fn partial_cmp(&self, other: &PointerBuf) -> Option<Ordering> {
828 self.as_str().partial_cmp(other.0.as_str())
829 }
830}
831
832impl PartialOrd<Pointer> for str {
833 fn partial_cmp(&self, other: &Pointer) -> Option<Ordering> {
834 self.partial_cmp(&other.0)
835 }
836}
837
838impl PartialOrd<PointerBuf> for str {
839 fn partial_cmp(&self, other: &PointerBuf) -> Option<Ordering> {
840 self.partial_cmp(other.0.as_str())
841 }
842}
843impl PartialOrd<PointerBuf> for &str {
844 fn partial_cmp(&self, other: &PointerBuf) -> Option<Ordering> {
845 (*self).partial_cmp(other.0.as_str())
846 }
847}
848impl PartialOrd<Pointer> for &str {
849 fn partial_cmp(&self, other: &Pointer) -> Option<Ordering> {
850 (*self).partial_cmp(&other.0)
851 }
852}
853
854impl PartialOrd<&str> for &Pointer {
855 fn partial_cmp(&self, other: &&str) -> Option<Ordering> {
856 PartialOrd::partial_cmp(&self.0[..], &other[..])
857 }
858}
859
860impl PartialOrd<String> for Pointer {
861 fn partial_cmp(&self, other: &String) -> Option<Ordering> {
862 self.0.partial_cmp(other.as_str())
863 }
864}
865
866impl PartialOrd<&str> for PointerBuf {
867 fn partial_cmp(&self, other: &&str) -> Option<Ordering> {
868 PartialOrd::partial_cmp(&self.0[..], &other[..])
869 }
870}
871
872impl<'p> PartialOrd<PointerBuf> for &'p Pointer {
873 fn partial_cmp(&self, other: &PointerBuf) -> Option<Ordering> {
874 self.0.partial_cmp(other.0.as_str())
875 }
876}
877
878impl PartialOrd<String> for PointerBuf {
879 fn partial_cmp(&self, other: &String) -> Option<Ordering> {
880 self.0.partial_cmp(other)
881 }
882}
883
884impl<'a> IntoIterator for &'a Pointer {
885 type Item = Token<'a>;
886 type IntoIter = Tokens<'a>;
887 fn into_iter(self) -> Self::IntoIter {
888 self.tokens()
889 }
890}
891
892#[derive(Clone, Default, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
899pub struct PointerBuf(String);
900
901impl PointerBuf {
902 pub fn root() -> Self {
906 Self::new()
907 }
908
909 pub fn new() -> Self {
911 Self(String::new())
912 }
913
914 pub unsafe fn new_unchecked(s: impl Into<String>) -> Self {
919 Self(s.into())
920 }
921
922 pub fn parse(s: impl Into<String>) -> Result<Self, RichParseError> {
927 let s = s.into();
928 match validate(&s) {
929 Ok(_) => Ok(Self(s)),
930 Err(err) => Err(err.into_report(s)),
931 }
932 }
933
934 pub fn from_tokens<'t>(tokens: impl IntoIterator<Item: Into<Token<'t>>>) -> Self {
936 let mut inner = String::new();
937 for t in tokens.into_iter().map(Into::into) {
938 inner.push('/');
939 inner.push_str(t.encoded());
940 }
941 PointerBuf(inner)
942 }
943
944 pub fn as_ptr(&self) -> &Pointer {
946 self
947 }
948
949 pub fn push_front<'t>(&mut self, token: impl Into<Token<'t>>) {
951 self.0.insert(0, '/');
952 self.0.insert_str(1, token.into().encoded());
953 }
954
955 pub fn push_back<'t>(&mut self, token: impl Into<Token<'t>>) {
957 self.0.push('/');
958 self.0.push_str(token.into().encoded());
959 }
960
961 pub fn pop_back(&mut self) -> Option<Token<'static>> {
963 if let Some(idx) = self.0.rfind('/') {
964 let back = unsafe { Token::from_encoded_unchecked(self.0.split_off(idx + 1)) };
966 self.0.pop(); Some(back)
968 } else {
969 None
970 }
971 }
972
973 pub fn pop_front(&mut self) -> Option<Token<'static>> {
975 (!self.is_root()).then(|| {
976 let mut token = if let Some(idx) = self.0[1..].find('/') {
978 let token = self.0.split_off(idx + 1);
979 core::mem::replace(&mut self.0, token)
980 } else {
981 core::mem::take(&mut self.0)
982 };
983 token.remove(0);
985 unsafe { Token::from_encoded_unchecked(token) }
987 })
988 }
989
990 pub fn append<P: AsRef<Pointer>>(&mut self, other: P) -> &PointerBuf {
992 let other = other.as_ref();
993 if self.is_root() {
994 self.0 = other.0.to_string();
995 } else if !other.is_root() {
996 self.0.push_str(&other.0);
997 }
998 self
999 }
1000
1001 pub fn replace<'t>(
1007 &mut self,
1008 index: usize,
1009 token: impl Into<Token<'t>>,
1010 ) -> Result<Option<Token>, ReplaceError> {
1011 if self.is_root() {
1012 return Err(ReplaceError {
1013 count: self.count(),
1014 index,
1015 });
1016 }
1017 let mut tokens = self.tokens().collect::<Vec<_>>();
1018 if index >= tokens.len() {
1019 return Err(ReplaceError {
1020 count: tokens.len(),
1021 index,
1022 });
1023 }
1024 let old = tokens.get(index).map(super::token::Token::to_owned);
1025 tokens[index] = token.into();
1026
1027 let mut buf = String::new();
1028 for token in tokens {
1029 buf.push('/');
1030 buf.push_str(token.encoded());
1031 }
1032 self.0 = buf;
1033
1034 Ok(old)
1035 }
1036
1037 pub fn clear(&mut self) {
1039 self.0.clear();
1040 }
1041}
1042
1043impl FromStr for PointerBuf {
1044 type Err = ParseError;
1045 fn from_str(s: &str) -> Result<Self, Self::Err> {
1046 Self::try_from(s)
1047 }
1048}
1049
1050impl Borrow<Pointer> for PointerBuf {
1051 fn borrow(&self) -> &Pointer {
1052 self.as_ptr()
1053 }
1054}
1055
1056impl Deref for PointerBuf {
1057 type Target = Pointer;
1058 fn deref(&self) -> &Self::Target {
1059 unsafe { Pointer::new_unchecked(self.0.as_str()) }
1061 }
1062}
1063
1064impl From<PointerBuf> for Box<Pointer> {
1065 fn from(value: PointerBuf) -> Self {
1066 let s = value.0.into_boxed_str();
1067 unsafe { Box::from_raw(Box::into_raw(s) as *mut Pointer) }
1069 }
1070}
1071
1072#[cfg(feature = "serde")]
1073impl<'de> serde::Deserialize<'de> for PointerBuf {
1074 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
1075 where
1076 D: serde::Deserializer<'de>,
1077 {
1078 use serde::de::Error;
1079 let s = String::deserialize(deserializer)?;
1080 PointerBuf::try_from(s).map_err(D::Error::custom)
1081 }
1082}
1083
1084#[cfg(feature = "serde")]
1085impl serde::Serialize for PointerBuf {
1086 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
1087 where
1088 S: serde::Serializer,
1089 {
1090 String::serialize(&self.0, serializer)
1091 }
1092}
1093
1094impl From<PointerBuf> for Cow<'static, Pointer> {
1095 fn from(value: PointerBuf) -> Self {
1096 Cow::Owned(value)
1097 }
1098}
1099
1100impl From<Token<'_>> for PointerBuf {
1101 fn from(t: Token) -> Self {
1102 PointerBuf::from_tokens([t])
1103 }
1104}
1105
1106impl TryFrom<String> for PointerBuf {
1107 type Error = ParseError;
1108 fn try_from(value: String) -> Result<Self, Self::Error> {
1109 let _ = validate(&value)?;
1110 Ok(Self(value))
1111 }
1112}
1113
1114impl From<usize> for PointerBuf {
1115 fn from(value: usize) -> Self {
1116 PointerBuf::from_tokens([value])
1117 }
1118}
1119
1120impl<'a> IntoIterator for &'a PointerBuf {
1121 type Item = Token<'a>;
1122 type IntoIter = Tokens<'a>;
1123 fn into_iter(self) -> Self::IntoIter {
1124 self.tokens()
1125 }
1126}
1127
1128impl TryFrom<&str> for PointerBuf {
1129 type Error = ParseError;
1130 fn try_from(value: &str) -> Result<Self, Self::Error> {
1131 Pointer::parse(value).map(Pointer::to_buf)
1132 }
1133}
1134
1135impl PartialEq<&str> for PointerBuf {
1136 fn eq(&self, other: &&str) -> bool {
1137 &self.0 == other
1138 }
1139}
1140
1141impl PartialEq<str> for PointerBuf {
1142 fn eq(&self, other: &str) -> bool {
1143 self.0 == other
1144 }
1145}
1146
1147impl core::fmt::Display for PointerBuf {
1148 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
1149 self.0.fmt(f)
1150 }
1151}
1152
1153#[derive(Debug, PartialEq, Eq, Clone, Copy)]
1156pub struct NoLeadingSlash;
1157
1158impl fmt::Display for NoLeadingSlash {
1159 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1160 write!(
1161 f,
1162 "json pointer must start with a slash ('/') and is not empty"
1163 )
1164 }
1165}
1166
1167#[derive(Debug, PartialEq)]
1169pub enum ParseError {
1170 NoLeadingSlash,
1172
1173 InvalidEncoding {
1176 offset: usize,
1179 source: EncodingError,
1181 },
1182}
1183
1184impl ParseError {
1185 pub fn offset(&self) -> usize {
1188 match self {
1189 Self::NoLeadingSlash => 0,
1190 Self::InvalidEncoding { offset, .. } => *offset,
1191 }
1192 }
1193 pub fn invalid_encoding_len(&self, subject: &str) -> usize {
1195 match self {
1196 Self::NoLeadingSlash => 0,
1197 Self::InvalidEncoding { offset, .. } => {
1198 if *offset < subject.len() - 1 {
1199 2
1200 } else {
1201 1
1202 }
1203 }
1204 }
1205 }
1206}
1207
1208impl Diagnostic for ParseError {
1209 type Subject = String;
1210
1211 fn url() -> &'static str {
1212 diagnostic_url!(struct ParseError)
1213 }
1214
1215 fn labels(&self, subject: &Self::Subject) -> Option<Box<dyn Iterator<Item = Label>>> {
1216 let offset = self.complete_offset();
1217 let len = self.invalid_encoding_len(subject);
1218 let text = match self {
1219 ParseError::NoLeadingSlash => "must start with a slash ('/')",
1220 ParseError::InvalidEncoding { .. } => "'~' must be followed by '0' or '1'",
1221 }
1222 .to_string();
1223 Some(Box::new(once(Label::new(text, offset, len))))
1224 }
1225}
1226
1227#[cfg(feature = "miette")]
1228impl miette::Diagnostic for ParseError {}
1229
1230impl fmt::Display for ParseError {
1231 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1232 match self {
1233 Self::NoLeadingSlash { .. } => {
1234 write!(
1235 f,
1236 "json pointer failed to parse; does not start with a slash ('/') and is not empty"
1237 )
1238 }
1239 Self::InvalidEncoding { offset, .. } => {
1240 write!(
1241 f,
1242 "json pointer failed to parse; the first token in the partial-pointer starting at offset {offset} is malformed"
1243 )
1244 }
1245 }
1246 }
1247}
1248
1249impl ParseError {
1250 #[deprecated(note = "renamed to `is_no_leading_slash`", since = "0.7.0")]
1251 pub fn is_no_leading_backslash(&self) -> bool {
1253 matches!(self, Self::NoLeadingSlash { .. })
1254 }
1255
1256 pub fn is_no_leading_slash(&self) -> bool {
1258 matches!(self, Self::NoLeadingSlash { .. })
1259 }
1260
1261 pub fn is_invalid_encoding(&self) -> bool {
1263 matches!(self, Self::InvalidEncoding { .. })
1264 }
1265
1266 pub fn pointer_offset(&self) -> usize {
1279 match *self {
1280 Self::NoLeadingSlash { .. } => 0,
1281 Self::InvalidEncoding { offset, .. } => offset,
1282 }
1283 }
1284
1285 pub fn source_offset(&self) -> usize {
1299 match self {
1300 Self::NoLeadingSlash { .. } => 0,
1301 Self::InvalidEncoding { source, .. } => source.offset,
1302 }
1303 }
1304
1305 pub fn complete_offset(&self) -> usize {
1317 self.source_offset() + self.pointer_offset()
1318 }
1319}
1320
1321#[cfg(feature = "std")]
1322impl std::error::Error for ParseError {
1323 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
1324 match self {
1325 Self::InvalidEncoding { source, .. } => Some(source),
1326 Self::NoLeadingSlash => None,
1327 }
1328 }
1329}
1330
1331pub type RichParseError = Report<ParseError>;
1333
1334#[derive(Debug, PartialEq, Eq)]
1337pub struct ReplaceError {
1338 pub index: usize,
1340 pub count: usize,
1342}
1343
1344impl fmt::Display for ReplaceError {
1345 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1346 write!(f, "index {} is out of bounds ({})", self.index, self.count)
1347 }
1348}
1349
1350#[cfg(feature = "std")]
1351impl std::error::Error for ReplaceError {}
1352
1353const fn validate(value: &str) -> Result<&str, ParseError> {
1354 if value.is_empty() {
1355 return Ok(value);
1356 }
1357 if let Err(err) = validate_bytes(value.as_bytes(), 0) {
1358 return Err(err);
1359 }
1360 Ok(value)
1361}
1362
1363const fn validate_bytes(bytes: &[u8], offset: usize) -> Result<(), ParseError> {
1364 if bytes[0] != b'/' && offset == 0 {
1365 return Err(ParseError::NoLeadingSlash);
1366 }
1367
1368 let mut ptr_offset = offset; let mut tok_offset = 0; let mut i = offset;
1372 while i < bytes.len() {
1373 match bytes[i] {
1374 b'/' => {
1375 ptr_offset = i;
1376 tok_offset = 0;
1378 }
1379 b'~' => {
1380 if i + 1 >= bytes.len() || (bytes[i + 1] != b'0' && bytes[i + 1] != b'1') {
1383 return Err(ParseError::InvalidEncoding {
1397 offset: ptr_offset,
1398 source: EncodingError {
1399 offset: tok_offset,
1400 source: InvalidEncoding::Tilde,
1401 },
1402 });
1403 }
1404 i += 1;
1406 tok_offset += 1;
1409 }
1410 _ => {}
1411 }
1412 i += 1;
1413 tok_offset += 1;
1415 }
1416 Ok(())
1417}
1418
1419#[cfg(test)]
1420mod tests {
1421 use std::error::Error;
1422
1423 use super::*;
1424 use quickcheck::TestResult;
1425 use quickcheck_macros::quickcheck;
1426
1427 #[test]
1428 #[should_panic = "invalid json pointer"]
1429 fn from_const_validates() {
1430 let _ = Pointer::from_static("foo/bar");
1431 }
1432
1433 #[test]
1434 fn root_is_alias_of_new_pathbuf() {
1435 assert_eq!(PointerBuf::root(), PointerBuf::new());
1436 }
1437
1438 #[test]
1439 fn from_unchecked_pathbuf() {
1440 let s = "/foo/bar/0";
1441 assert_eq!(
1442 unsafe { PointerBuf::new_unchecked(String::from(s)) },
1443 PointerBuf::parse(s).unwrap()
1444 );
1445 }
1446
1447 #[test]
1448 fn strip_suffix() {
1449 let p = Pointer::from_static("/example/pointer/to/some/value");
1450 let stripped = p
1451 .strip_suffix(Pointer::from_static("/to/some/value"))
1452 .unwrap();
1453 assert_eq!(stripped, "/example/pointer");
1454 }
1455
1456 #[test]
1457 fn strip_prefix() {
1458 let p = Pointer::from_static("/example/pointer/to/some/value");
1459 let stripped = p
1460 .strip_prefix(Pointer::from_static("/example/pointer"))
1461 .unwrap();
1462 assert_eq!(stripped, "/to/some/value");
1463 }
1464
1465 #[test]
1466 fn ends_with() {
1467 let p = Pointer::from_static("/foo/bar");
1469 let q = Pointer::from_static("/bar");
1470 assert!(p.ends_with(q));
1471 let q = Pointer::from_static("/foo/bar");
1472 assert!(p.ends_with(q));
1473
1474 let q = Pointer::from_static("/barz");
1476 assert!(!p.ends_with(q));
1477 let q = Pointer::from_static("/");
1478 assert!(!p.ends_with(q));
1479 let q = Pointer::from_static("");
1480 assert!(!p.ends_with(q));
1481 let q = Pointer::from_static("/qux/foo/bar");
1482 assert!(!p.ends_with(q));
1483
1484 let p = Pointer::root();
1486 let q = Pointer::root();
1487 assert!(p.ends_with(q));
1488 }
1489
1490 #[test]
1491 fn starts_with() {
1492 let p = Pointer::from_static("/foo/bar");
1494 let q = Pointer::from_static("/foo");
1495 assert!(p.starts_with(q));
1496 let q = Pointer::from_static("/foo/bar");
1497 assert!(p.starts_with(q));
1498
1499 let q = Pointer::from_static("/");
1501 assert!(!p.starts_with(q));
1502 let q = Pointer::from_static("/fo");
1503 assert!(!p.starts_with(q));
1504 let q = Pointer::from_static("/foo/");
1505 assert!(!p.starts_with(q));
1506
1507 let p = Pointer::root();
1509 let q = Pointer::root();
1510 assert!(p.starts_with(q));
1511 let p = Pointer::from_static("/");
1512 assert!(p.starts_with(q));
1513 let p = Pointer::from_static("/any/thing");
1514 assert!(p.starts_with(q));
1515 }
1516
1517 #[test]
1518 fn parse() {
1519 let tests = [
1520 ("", Ok("")),
1521 ("/", Ok("/")),
1522 ("/foo", Ok("/foo")),
1523 ("/foo/bar", Ok("/foo/bar")),
1524 ("/foo/bar/baz", Ok("/foo/bar/baz")),
1525 ("/foo/bar/baz/~0", Ok("/foo/bar/baz/~0")),
1526 ("/foo/bar/baz/~1", Ok("/foo/bar/baz/~1")),
1527 ("/foo/bar/baz/~01", Ok("/foo/bar/baz/~01")),
1528 ("/foo/bar/baz/~10", Ok("/foo/bar/baz/~10")),
1529 ("/foo/bar/baz/~11", Ok("/foo/bar/baz/~11")),
1530 ("/foo/bar/baz/~1/~0", Ok("/foo/bar/baz/~1/~0")),
1531 ("missing-slash", Err(ParseError::NoLeadingSlash)),
1532 (
1533 "/~",
1534 Err(ParseError::InvalidEncoding {
1535 offset: 0,
1536 source: EncodingError {
1537 offset: 1,
1538 source: InvalidEncoding::Tilde,
1539 },
1540 }),
1541 ),
1542 (
1543 "/~2",
1544 Err(ParseError::InvalidEncoding {
1545 offset: 0,
1546 source: EncodingError {
1547 offset: 1,
1548 source: InvalidEncoding::Tilde,
1549 },
1550 }),
1551 ),
1552 (
1553 "/~a",
1554 Err(ParseError::InvalidEncoding {
1555 offset: 0,
1556 source: EncodingError {
1557 offset: 1,
1558 source: InvalidEncoding::Tilde,
1559 },
1560 }),
1561 ),
1562 ];
1563 for (input, expected) in tests {
1564 let actual = Pointer::parse(input).map(Pointer::as_str);
1565 assert_eq!(actual, expected);
1566 }
1567 }
1568
1569 #[test]
1570 fn parse_error_offsets() {
1571 let err = Pointer::parse("/foo/invalid~encoding").unwrap_err();
1572 assert_eq!(err.pointer_offset(), 4);
1573 assert_eq!(err.source_offset(), 8);
1574 assert_eq!(err.complete_offset(), 12);
1575
1576 let err = Pointer::parse("invalid~encoding").unwrap_err();
1577 assert_eq!(err.pointer_offset(), 0);
1578 assert_eq!(err.source_offset(), 0);
1579
1580 let err = Pointer::parse("no-leading/slash").unwrap_err();
1581 assert!(err.source().is_none());
1582 }
1583
1584 #[test]
1585 fn pointer_buf_clear() {
1586 let mut ptr = PointerBuf::from_tokens(["foo", "bar"]);
1587 ptr.clear();
1588 assert_eq!(ptr, "");
1589 }
1590
1591 #[test]
1592 fn push_pop_back() {
1593 let mut ptr = PointerBuf::default();
1594 assert_eq!(ptr, "", "default, root pointer should equal \"\"");
1595 assert_eq!(ptr.count(), 0, "default pointer should have 0 tokens");
1596
1597 ptr.push_back("foo");
1598 assert_eq!(ptr, "/foo", "pointer should equal \"/foo\" after push_back");
1599
1600 ptr.push_back("bar");
1601 assert_eq!(ptr, "/foo/bar");
1602 ptr.push_back("/baz");
1603 assert_eq!(ptr, "/foo/bar/~1baz");
1604
1605 let mut ptr = PointerBuf::from_tokens(["foo", "bar"]);
1606 assert_eq!(ptr.pop_back(), Some("bar".into()));
1607 assert_eq!(ptr, "/foo", "pointer should equal \"/foo\" after pop_back");
1608 assert_eq!(ptr.pop_back(), Some("foo".into()));
1609 assert_eq!(ptr, "", "pointer should equal \"\" after pop_back");
1610 }
1611
1612 #[test]
1613 fn replace_token() {
1614 let mut ptr = PointerBuf::try_from("/test/token").unwrap();
1615
1616 let res = ptr.replace(0, "new");
1617 assert!(res.is_ok());
1618 assert_eq!(ptr, "/new/token");
1619
1620 let res = ptr.replace(3, "invalid");
1621
1622 assert!(res.is_err());
1623 }
1624
1625 #[test]
1626 fn push_pop_front() {
1627 let mut ptr = PointerBuf::default();
1628 assert_eq!(ptr, "");
1629 assert_eq!(ptr.count(), 0);
1630 ptr.push_front("bar");
1631 assert_eq!(ptr, "/bar");
1632 assert_eq!(ptr.count(), 1);
1633
1634 ptr.push_front("foo");
1635 assert_eq!(ptr, "/foo/bar");
1636 assert_eq!(ptr.count(), 2);
1637
1638 ptr.push_front("too");
1639 assert_eq!(ptr, "/too/foo/bar");
1640 assert_eq!(ptr.count(), 3);
1641
1642 assert_eq!(ptr.pop_front(), Some("too".into()));
1643 assert_eq!(ptr, "/foo/bar");
1644 assert_eq!(ptr.count(), 2);
1645
1646 assert_eq!(ptr.pop_back(), Some("bar".into()));
1647 assert_eq!(ptr, "/foo");
1648 assert_eq!(ptr.count(), 1);
1649 assert_eq!(ptr.pop_front(), Some("foo".into()));
1650 assert_eq!(ptr, "");
1651 }
1652
1653 #[test]
1654 fn pop_front_works_with_empty_strings() {
1655 {
1656 let mut ptr = PointerBuf::from_tokens(["bar", "", ""]);
1657
1658 assert_eq!(ptr.tokens().count(), 3);
1659 let mut token = ptr.pop_front();
1660 assert_eq!(token, Some(Token::new("bar")));
1661 assert_eq!(ptr.tokens().count(), 2);
1662 token = ptr.pop_front();
1663 assert_eq!(token, Some(Token::new("")));
1664 assert_eq!(ptr.tokens().count(), 1);
1665 token = ptr.pop_front();
1666 assert_eq!(token, Some(Token::new("")));
1667 assert_eq!(ptr.tokens().count(), 0);
1668 assert_eq!(ptr, Pointer::root());
1669 }
1670 {
1671 let mut ptr = PointerBuf::new();
1672 assert_eq!(ptr.tokens().count(), 0);
1673 ptr.push_back("");
1674 assert_eq!(ptr.tokens().count(), 1);
1675 ptr.pop_back();
1676 assert_eq!(ptr.tokens().count(), 0);
1677 }
1678 {
1679 let mut ptr = PointerBuf::new();
1680 let input = ["", "", "", "foo", "", "bar", "baz", ""];
1681 for (idx, &s) in input.iter().enumerate() {
1682 assert_eq!(ptr.tokens().count(), idx);
1683 ptr.push_back(s);
1684 }
1685 assert_eq!(ptr.tokens().count(), input.len());
1686 for (idx, s) in input.iter().enumerate() {
1687 assert_eq!(ptr.tokens().count(), 8 - idx);
1688 assert_eq!(ptr.front().unwrap().decoded(), *s);
1689 assert_eq!(ptr.pop_front().unwrap().decoded(), *s);
1690 }
1691 assert_eq!(ptr.tokens().count(), 0);
1692 assert!(ptr.front().is_none());
1693 assert!(ptr.pop_front().is_none());
1694 }
1695 }
1696
1697 #[test]
1698 fn formatting() {
1699 assert_eq!(PointerBuf::from_tokens(["foo", "bar"]), "/foo/bar");
1700 assert_eq!(
1701 PointerBuf::from_tokens(["~/foo", "~bar", "/baz"]),
1702 "/~0~1foo/~0bar/~1baz"
1703 );
1704 assert_eq!(PointerBuf::from_tokens(["field", "", "baz"]), "/field//baz");
1705 assert_eq!(PointerBuf::default(), "");
1706
1707 let ptr = PointerBuf::from_tokens(["foo", "bar", "baz"]);
1708 assert_eq!(ptr.to_string(), "/foo/bar/baz");
1709 }
1710
1711 #[test]
1712 fn last() {
1713 let ptr = Pointer::from_static("/foo/bar");
1714
1715 assert_eq!(ptr.last(), Some("bar".into()));
1716
1717 let ptr = Pointer::from_static("/foo/bar/-");
1718 assert_eq!(ptr.last(), Some("-".into()));
1719
1720 let ptr = Pointer::from_static("/-");
1721 assert_eq!(ptr.last(), Some("-".into()));
1722
1723 let ptr = Pointer::root();
1724 assert_eq!(ptr.last(), None);
1725
1726 let ptr = Pointer::from_static("/bar");
1727 assert_eq!(ptr.last(), Some("bar".into()));
1728 }
1729
1730 #[test]
1731 fn first() {
1732 let ptr = Pointer::from_static("/foo/bar");
1733 assert_eq!(ptr.first(), Some("foo".into()));
1734
1735 let ptr = Pointer::from_static("/foo/bar/-");
1736 assert_eq!(ptr.first(), Some("foo".into()));
1737
1738 let ptr = Pointer::root();
1739 assert_eq!(ptr.first(), None);
1740 }
1741
1742 #[test]
1743 fn pointerbuf_try_from() {
1744 let ptr = PointerBuf::from_tokens(["foo", "bar", "~/"]);
1745
1746 assert_eq!(PointerBuf::try_from("/foo/bar/~0~1").unwrap(), ptr);
1747 let into: PointerBuf = "/foo/bar/~0~1".try_into().unwrap();
1748 assert_eq!(ptr, into);
1749 }
1750
1751 #[test]
1752 #[cfg(all(feature = "serde", feature = "json"))]
1753 fn to_json_value() {
1754 use serde_json::Value;
1755 let ptr = Pointer::from_static("/foo/bar");
1756 assert_eq!(ptr.to_json_value(), Value::String(String::from("/foo/bar")));
1757 }
1758
1759 #[cfg(all(feature = "resolve", feature = "json"))]
1760 #[test]
1761 fn resolve() {
1762 use serde_json::json;
1764 let value = json!({
1765 "foo": {
1766 "bar": {
1767 "baz": "qux"
1768 }
1769 }
1770 });
1771 let ptr = Pointer::from_static("/foo/bar/baz");
1772 let resolved = ptr.resolve(&value).unwrap();
1773 assert_eq!(resolved, &json!("qux"));
1774 }
1775
1776 #[cfg(all(feature = "delete", feature = "json"))]
1777 #[test]
1778 fn delete() {
1779 use serde_json::json;
1780 let mut value = json!({
1781 "foo": {
1782 "bar": {
1783 "baz": "qux"
1784 }
1785 }
1786 });
1787 let ptr = Pointer::from_static("/foo/bar/baz");
1788 let deleted = ptr.delete(&mut value).unwrap();
1789 assert_eq!(deleted, json!("qux"));
1790 assert_eq!(
1791 value,
1792 json!({
1793 "foo": {
1794 "bar": {}
1795 }
1796 })
1797 );
1798 }
1799
1800 #[cfg(all(feature = "assign", feature = "json"))]
1801 #[test]
1802 fn assign() {
1803 use serde_json::json;
1804 let mut value = json!({});
1805 let ptr = Pointer::from_static("/foo/bar");
1806 let replaced = ptr.assign(&mut value, json!("baz")).unwrap();
1807 assert_eq!(replaced, None);
1808 assert_eq!(
1809 value,
1810 json!({
1811 "foo": {
1812 "bar": "baz"
1813 }
1814 })
1815 );
1816 }
1817
1818 #[test]
1819 fn get() {
1820 let ptr = Pointer::from_static("/0/1/2/3/4/5/6/7/8/9");
1821 for i in 0..10 {
1822 assert_eq!(ptr.get(i).unwrap().decoded(), i.to_string());
1823 }
1824 }
1825
1826 #[test]
1827 fn replace_token_success() {
1828 let mut ptr = PointerBuf::from_tokens(["foo", "bar", "baz"]);
1829 assert!(ptr.replace(1, "qux").is_ok());
1830 assert_eq!(ptr, PointerBuf::from_tokens(["foo", "qux", "baz"]));
1831
1832 assert!(ptr.replace(0, "corge").is_ok());
1833 assert_eq!(ptr, PointerBuf::from_tokens(["corge", "qux", "baz"]));
1834
1835 assert!(ptr.replace(2, "quux").is_ok());
1836 assert_eq!(ptr, PointerBuf::from_tokens(["corge", "qux", "quux"]));
1837 }
1838
1839 #[test]
1840 fn replace_token_out_of_bounds() {
1841 let mut ptr = PointerBuf::from_tokens(["foo", "bar"]);
1842 assert!(ptr.replace(2, "baz").is_err());
1843 assert_eq!(ptr, PointerBuf::from_tokens(["foo", "bar"])); }
1845
1846 #[test]
1847 fn replace_token_with_empty_string() {
1848 let mut ptr = PointerBuf::from_tokens(["foo", "bar", "baz"]);
1849 assert!(ptr.replace(1, "").is_ok());
1850 assert_eq!(ptr, PointerBuf::from_tokens(["foo", "", "baz"]));
1851 }
1852
1853 #[test]
1854 fn replace_token_in_empty_pointer() {
1855 let mut ptr = PointerBuf::default();
1856 assert!(ptr.replace(0, "foo").is_err());
1857 assert_eq!(ptr, PointerBuf::default()); }
1859
1860 #[test]
1861 fn pop_back_works_with_empty_strings() {
1862 {
1863 let mut ptr = PointerBuf::new();
1864 ptr.push_back("");
1865 ptr.push_back("");
1866 ptr.push_back("bar");
1867
1868 assert_eq!(ptr.tokens().count(), 3);
1869 ptr.pop_back();
1870 assert_eq!(ptr.tokens().count(), 2);
1871 ptr.pop_back();
1872 assert_eq!(ptr.tokens().count(), 1);
1873 ptr.pop_back();
1874 assert_eq!(ptr.tokens().count(), 0);
1875 assert_eq!(ptr, PointerBuf::new());
1876 }
1877 {
1878 let mut ptr = PointerBuf::new();
1879 assert_eq!(ptr.tokens().count(), 0);
1880 ptr.push_back("");
1881 assert_eq!(ptr.tokens().count(), 1);
1882 ptr.pop_back();
1883 assert_eq!(ptr.tokens().count(), 0);
1884 }
1885 {
1886 let mut ptr = PointerBuf::new();
1887 let input = ["", "", "", "foo", "", "bar", "baz", ""];
1888 for (idx, &s) in input.iter().enumerate() {
1889 assert_eq!(ptr.tokens().count(), idx);
1890 ptr.push_back(s);
1891 }
1892 assert_eq!(ptr.tokens().count(), input.len());
1893 for (idx, s) in input.iter().enumerate().rev() {
1894 assert_eq!(ptr.tokens().count(), idx + 1);
1895 assert_eq!(ptr.back().unwrap().decoded(), *s);
1896 assert_eq!(ptr.pop_back().unwrap().decoded(), *s);
1897 }
1898 assert_eq!(ptr.tokens().count(), 0);
1899 assert!(ptr.back().is_none());
1900 assert!(ptr.pop_back().is_none());
1901 }
1902 }
1903
1904 #[test]
1905 #[allow(clippy::useless_asref)]
1909 fn pointerbuf_as_ref_returns_pointer() {
1910 let ptr_str = "/foo/bar";
1911 let ptr = Pointer::from_static(ptr_str);
1912 let ptr_buf = ptr.to_buf();
1913 assert_eq!(ptr_buf.as_ref(), ptr);
1914 let r: &Pointer = ptr.as_ref();
1915 assert_eq!(ptr, r);
1916
1917 let s: &str = ptr.as_ref();
1918 assert_eq!(s, ptr_str);
1919
1920 let b: &[u8] = ptr.as_ref();
1921 assert_eq!(b, ptr_str.as_bytes());
1922 }
1923
1924 #[test]
1925 fn from_tokens() {
1926 let ptr = PointerBuf::from_tokens(["foo", "bar", "baz"]);
1927 assert_eq!(ptr, "/foo/bar/baz");
1928 }
1929
1930 #[test]
1931 fn pointer_borrow() {
1932 let ptr = Pointer::from_static("/foo/bar");
1933 let borrowed: &str = ptr.borrow();
1934 assert_eq!(borrowed, "/foo/bar");
1935 }
1936
1937 #[test]
1938 #[cfg(feature = "json")]
1939 fn into_value() {
1940 use alloc::string::ToString;
1941 use serde_json::Value;
1942 let ptr = Pointer::from_static("/foo/bar");
1943 let value: Value = ptr.into();
1944 assert_eq!(value, Value::String("/foo/bar".to_string()));
1945 }
1946
1947 #[test]
1948 fn intersect() {
1949 let base = Pointer::from_static("/foo/bar");
1950 let a = Pointer::from_static("/foo/bar/qux");
1951 let b = Pointer::from_static("/foo/bar");
1952 assert_eq!(a.intersection(b), base);
1953
1954 let base = Pointer::from_static("");
1955 let a = Pointer::from_static("/foo");
1956 let b = Pointer::from_static("/");
1957 assert_eq!(a.intersection(b), base);
1958
1959 let base = Pointer::from_static("");
1960 let a = Pointer::from_static("/fooqux");
1961 let b = Pointer::from_static("/foobar");
1962 assert_eq!(a.intersection(b), base);
1963 }
1964
1965 #[quickcheck]
1966 fn qc_pop_and_push(mut ptr: PointerBuf) -> bool {
1967 let subjectal_ptr = ptr.clone();
1968 let mut tokens = Vec::with_capacity(ptr.count());
1969 while let Some(token) = ptr.pop_back() {
1970 tokens.push(token);
1971 }
1972 if ptr.count() != 0 || !ptr.is_root() || ptr.last().is_some() || ptr.first().is_some() {
1973 return false;
1974 }
1975 for token in tokens.drain(..) {
1976 ptr.push_front(token);
1977 }
1978 if ptr != subjectal_ptr {
1979 return false;
1980 }
1981 while let Some(token) = ptr.pop_front() {
1982 tokens.push(token);
1983 }
1984 if ptr.count() != 0 || !ptr.is_root() || ptr.last().is_some() || ptr.first().is_some() {
1985 return false;
1986 }
1987 for token in tokens {
1988 ptr.push_back(token);
1989 }
1990 ptr == subjectal_ptr
1991 }
1992
1993 #[quickcheck]
1994 fn qc_split(ptr: PointerBuf) -> bool {
1995 if let Some((head, tail)) = ptr.split_front() {
1996 {
1997 let Some(first) = ptr.first() else {
1998 return false;
1999 };
2000 if first != head {
2001 return false;
2002 }
2003 }
2004 {
2005 let mut copy = ptr.clone();
2006 copy.pop_front();
2007 if copy != tail {
2008 return false;
2009 }
2010 }
2011 {
2012 let mut buf = tail.to_buf();
2013 buf.push_front(head.clone());
2014 if buf != ptr {
2015 return false;
2016 }
2017 }
2018 {
2019 let fmt = alloc::format!("/{}{tail}", head.encoded());
2020 if Pointer::parse(&fmt).unwrap() != ptr {
2021 return false;
2022 }
2023 }
2024 } else {
2025 return ptr.is_root()
2026 && ptr.count() == 0
2027 && ptr.last().is_none()
2028 && ptr.first().is_none();
2029 }
2030 if let Some((head, tail)) = ptr.split_back() {
2031 {
2032 let Some(last) = ptr.last() else {
2033 return false;
2034 };
2035 if last != tail {
2036 return false;
2037 }
2038 }
2039 {
2040 let mut copy = ptr.clone();
2041 copy.pop_back();
2042 if copy != head {
2043 return false;
2044 }
2045 }
2046 {
2047 let mut buf = head.to_buf();
2048 buf.push_back(tail.clone());
2049 if buf != ptr {
2050 return false;
2051 }
2052 }
2053 {
2054 let fmt = alloc::format!("{head}/{}", tail.encoded());
2055 if Pointer::parse(&fmt).unwrap() != ptr {
2056 return false;
2057 }
2058 }
2059 if Some(head) != ptr.parent() {
2060 return false;
2061 }
2062 } else {
2063 return ptr.is_root()
2064 && ptr.count() == 0
2065 && ptr.last().is_none()
2066 && ptr.first().is_none();
2067 }
2068 true
2069 }
2070
2071 #[quickcheck]
2072 fn qc_from_tokens(tokens: Vec<String>) -> bool {
2073 let buf = PointerBuf::from_tokens(&tokens);
2074 let reconstructed: Vec<_> = buf.tokens().collect();
2075 reconstructed
2076 .into_iter()
2077 .zip(tokens)
2078 .all(|(a, b)| a.decoded() == b)
2079 }
2080
2081 #[quickcheck]
2082 fn qc_intersection(base: PointerBuf, suffix_0: PointerBuf, suffix_1: PointerBuf) -> TestResult {
2083 if suffix_0.first() == suffix_1.first() {
2084 return TestResult::discard();
2086 }
2087 let mut a = base.clone();
2088 a.append(&suffix_0);
2089 let mut b = base.clone();
2090 b.append(&suffix_1);
2091 let isect = a.intersection(&b);
2092 TestResult::from_bool(isect == base)
2093 }
2094
2095 #[cfg(all(feature = "json", feature = "std", feature = "serde"))]
2096 #[test]
2097 fn serde() {
2098 use serde::Deserialize;
2099 let ptr = PointerBuf::from_tokens(["foo", "bar"]);
2100 let json = serde_json::to_string(&ptr).unwrap();
2101 assert_eq!(json, "\"/foo/bar\"");
2102 let deserialized: PointerBuf = serde_json::from_str(&json).unwrap();
2103 assert_eq!(deserialized, ptr);
2104
2105 let ptr = Pointer::from_static("/foo/bar");
2106 let json = serde_json::to_string(&ptr).unwrap();
2107 assert_eq!(json, "\"/foo/bar\"");
2108
2109 let mut de = serde_json::Deserializer::from_str("\"/foo/bar\"");
2110 let p = <&Pointer>::deserialize(&mut de).unwrap();
2111 assert_eq!(p, ptr);
2112 let s = serde_json::to_string(p).unwrap();
2113 assert_eq!(json, s);
2114
2115 let invalid = serde_json::from_str::<&Pointer>("\"foo/bar\"");
2116 assert!(invalid.is_err());
2117 }
2118
2119 #[test]
2120 fn to_owned() {
2121 let ptr = Pointer::from_static("/bread/crumbs");
2122 let buf = ptr.to_owned();
2123 assert_eq!(buf, "/bread/crumbs");
2124 }
2125
2126 #[test]
2127 fn concat() {
2128 let ptr = Pointer::from_static("/foo");
2129 let barbaz = Pointer::from_static("/bar/baz");
2130 assert_eq!(ptr.concat(barbaz), "/foo/bar/baz");
2131 }
2132
2133 #[test]
2134 fn with_leading_token() {
2135 let ptr = Pointer::from_static("/bar");
2136 let foobar = ptr.with_leading_token("foo");
2137 assert_eq!(foobar, "/foo/bar");
2138 }
2139
2140 #[test]
2141 fn with_trailing_token() {
2142 let ptr = Pointer::from_static("/foo");
2143 let foobar = ptr.with_trailing_token("bar");
2144 assert_eq!(foobar, "/foo/bar");
2145 }
2146
2147 #[test]
2148 fn len() {
2149 let ptr = Pointer::from_static("/foo/bar");
2150 assert_eq!(ptr.len(), 8);
2151 let mut ptr = ptr.to_buf();
2152 ptr.push_back("~");
2153 assert_eq!(ptr.len(), 11);
2154 }
2155
2156 #[test]
2157 fn is_empty() {
2158 assert!(Pointer::from_static("").is_empty());
2159 assert!(!Pointer::from_static("/").is_empty());
2160 }
2161
2162 #[test]
2163 #[allow(clippy::cmp_owned, unused_must_use)]
2164 fn partial_eq() {
2165 let ptr_string = String::from("/bread/crumbs");
2166 let ptr_str = "/bread/crumbs";
2167 let ptr = Pointer::from_static(ptr_str);
2168 let ptr_buf = ptr.to_buf();
2169 <&Pointer as PartialEq<&Pointer>>::eq(&ptr, &ptr);
2170 <Pointer as PartialEq<&str>>::eq(ptr, &ptr_str);
2171 <&Pointer as PartialEq<String>>::eq(&ptr, &ptr_string);
2172 <Pointer as PartialEq<String>>::eq(ptr, &ptr_string);
2173 <Pointer as PartialEq<PointerBuf>>::eq(ptr, &ptr_buf);
2174 <&str as PartialEq<Pointer>>::eq(&ptr_str, ptr);
2175 <String as PartialEq<Pointer>>::eq(&ptr_string, ptr);
2176 <str as PartialEq<Pointer>>::eq(ptr_str, ptr);
2177 <PointerBuf as PartialEq<str>>::eq(&ptr_buf, ptr_str);
2178 <PointerBuf as PartialEq<PointerBuf>>::eq(&ptr_buf, &ptr_buf);
2179 <PointerBuf as PartialEq<Pointer>>::eq(&ptr_buf, ptr);
2180 <Pointer as PartialEq<PointerBuf>>::eq(ptr, &ptr_buf);
2181 <PointerBuf as PartialEq<&Pointer>>::eq(&ptr_buf, &ptr);
2182 <PointerBuf as PartialEq<&str>>::eq(&ptr_buf, &ptr_str);
2183 <PointerBuf as PartialEq<String>>::eq(&ptr_buf, &ptr_string);
2184 <&Pointer as PartialEq<PointerBuf>>::eq(&ptr, &ptr_buf);
2185 <str as PartialEq<PointerBuf>>::eq(ptr_str, &ptr_buf);
2186 <&str as PartialEq<PointerBuf>>::eq(&ptr_str, &ptr_buf);
2187 <String as PartialEq<PointerBuf>>::eq(&ptr_string, &ptr_buf);
2188 }
2189
2190 #[test]
2191 fn partial_ord() {
2192 let a_str = "/foo/bar";
2193 let a_string = a_str.to_string();
2194 let a_ptr = Pointer::from_static(a_str);
2195 let a_buf = a_ptr.to_buf();
2196 let b_str = "/foo/bar";
2197 let b_string = b_str.to_string();
2198 let b_ptr = Pointer::from_static(b_str);
2199 let b_buf = b_ptr.to_buf();
2200 let c_str = "/foo/bar/baz";
2201 let c_string = c_str.to_string();
2202 let c_ptr = Pointer::from_static(c_str);
2203 let c_buf = c_ptr.to_buf();
2204
2205 assert!(<Pointer as PartialOrd<PointerBuf>>::lt(a_ptr, &c_buf));
2206 assert!(<PointerBuf as PartialOrd<Pointer>>::lt(&a_buf, c_ptr));
2207 assert!(<String as PartialOrd<Pointer>>::lt(&a_string, c_ptr));
2208 assert!(<str as PartialOrd<Pointer>>::lt(a_str, c_ptr));
2209 assert!(<str as PartialOrd<PointerBuf>>::lt(a_str, &c_buf));
2210 assert!(<&str as PartialOrd<Pointer>>::lt(&a_str, c_ptr));
2211 assert!(<&str as PartialOrd<PointerBuf>>::lt(&a_str, &c_buf));
2212 assert!(<&Pointer as PartialOrd<PointerBuf>>::lt(&a_ptr, &c_buf));
2213 assert!(<&Pointer as PartialOrd<&str>>::lt(&b_ptr, &c_str));
2214 assert!(<Pointer as PartialOrd<String>>::lt(a_ptr, &c_string));
2215 assert!(<PointerBuf as PartialOrd<&str>>::lt(&a_buf, &c_str));
2216 assert!(<PointerBuf as PartialOrd<String>>::lt(&a_buf, &c_string));
2217 assert!(a_ptr < c_buf);
2218 assert!(c_buf > a_ptr);
2219 assert!(a_buf < c_ptr);
2220 assert!(a_ptr < c_buf);
2221 assert!(a_ptr < c_ptr);
2222 assert!(a_ptr <= c_ptr);
2223 assert!(c_ptr > a_ptr);
2224 assert!(c_ptr >= a_ptr);
2225 assert!(a_ptr == b_ptr);
2226 assert!(a_ptr <= b_ptr);
2227 assert!(a_ptr >= b_ptr);
2228 assert!(a_string < c_buf);
2229 assert!(a_string <= c_buf);
2230 assert!(c_string > a_buf);
2231 assert!(c_string >= a_buf);
2232 assert!(a_string == b_buf);
2233 assert!(a_ptr < c_buf);
2234 assert!(a_ptr <= c_buf);
2235 assert!(c_ptr > a_buf);
2236 assert!(c_ptr >= a_buf);
2237 assert!(a_ptr == b_buf);
2238 assert!(a_ptr <= b_buf);
2239 assert!(a_ptr >= b_buf);
2240 assert!(a_ptr < c_buf);
2241 assert!(c_ptr > b_string);
2242 #[allow(clippy::nonminimal_bool)]
2244 let not = !(a_ptr > c_buf);
2245 assert!(not);
2246 }
2247
2248 #[test]
2249 fn intersection() {
2250 struct Test {
2251 base: &'static str,
2252 a_suffix: &'static str,
2253 b_suffix: &'static str,
2254 }
2255
2256 let tests = [
2257 Test {
2258 base: "",
2259 a_suffix: "/",
2260 b_suffix: "/a/b/c",
2261 },
2262 Test {
2263 base: "",
2264 a_suffix: "",
2265 b_suffix: "",
2266 },
2267 Test {
2268 base: "/a",
2269 a_suffix: "/",
2270 b_suffix: "/suffix",
2271 },
2272 Test {
2273 base: "/a",
2274 a_suffix: "/suffix",
2275 b_suffix: "",
2276 },
2277 Test {
2278 base: "/¦\\>‶“lv\u{eedd}\u{8a}Y\n\u{99}𘐷vT\n\u{4}Hª\\ 嗱\\Yl6Y`\"1\u{6dd}\u{17}\0\u{10}ዄ8\"Z닍6i)V;\u{6be4c}\u{b}\u{59836}`\u{1e}㑍§~05\u{1d}\u{8a}[뵔\u{437c3}j\u{f326}\";*\u{c}*U\u{1b}\u{8a}I\u{4}묁",
2279 a_suffix: "/Y\u{2064}",
2280 b_suffix: "",
2281 }
2282 ];
2283
2284 for Test {
2285 base,
2286 a_suffix,
2287 b_suffix,
2288 } in tests
2289 {
2290 let base = PointerBuf::parse(base).expect(&format!("failed to parse ${base}"));
2291 let mut a = base.clone();
2292 let mut b = base.clone();
2293 a.append(PointerBuf::parse(a_suffix).unwrap());
2294 b.append(PointerBuf::parse(b_suffix).unwrap());
2295 let intersection = a.intersection(&b);
2296 assert_eq!(intersection, base);
2297 }
2298 }
2299
2300 #[test]
2301 fn into_iter() {
2302 use core::iter::IntoIterator;
2303
2304 let ptr = PointerBuf::from_tokens(["foo", "bar", "baz"]);
2305 let tokens: Vec<Token> = ptr.into_iter().collect();
2306 let from_tokens = PointerBuf::from_tokens(tokens);
2307 assert_eq!(ptr, from_tokens);
2308
2309 let ptr = Pointer::from_static("/foo/bar/baz");
2310 let tokens: Vec<_> = ptr.into_iter().collect();
2311 assert_eq!(ptr, PointerBuf::from_tokens(tokens));
2312 }
2313
2314 #[test]
2315 fn from_str() {
2316 let p = PointerBuf::from_str("/foo/bar").unwrap();
2317 assert_eq!(p, "/foo/bar");
2318 }
2319
2320 #[test]
2321 fn from_token() {
2322 let p = PointerBuf::from(Token::new("foo"));
2323 assert_eq!(p, "/foo");
2324 }
2325
2326 #[test]
2327 fn from_usize() {
2328 let p = PointerBuf::from(0);
2329 assert_eq!(p, "/0");
2330 }
2331
2332 #[test]
2333 fn borrow() {
2334 let ptr = PointerBuf::from_tokens(["foo", "bar"]);
2335 let borrowed: &Pointer = ptr.borrow();
2336 assert_eq!(borrowed, "/foo/bar");
2337 }
2338
2339 #[test]
2340 fn from_box_to_buf() {
2341 let subjectal = PointerBuf::parse("/foo/bar/0").unwrap();
2342 let boxed: Box<Pointer> = subjectal.clone().into();
2343 let unboxed = boxed.into_buf();
2344 assert_eq!(subjectal, unboxed);
2345 }
2346
2347 #[test]
2348 #[cfg(feature = "miette")]
2349 fn quick_miette_spike() {
2350 let err = PointerBuf::parse("hello-world").unwrap_err();
2351 println!("{:?}", miette::Report::from(err));
2352 }
2353}