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 &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_offset(&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 #[deprecated(
250 since = "0.8.0",
251 note = "renamed to `split_at_offset` - `split_at` will become position (index) based by 1.0"
252 )]
253 pub fn split_at(&self, offset: usize) -> Option<(&Self, &Self)> {
254 self.split_at_offset(offset)
255 }
256
257 pub fn split_back(&self) -> Option<(&Self, Token<'_>)> {
259 self.0.rsplit_once('/').map(|(front, back)| {
260 (
261 unsafe { Self::new_unchecked(front) },
263 unsafe { Token::from_encoded_unchecked(back) },
265 )
266 })
267 }
268
269 pub fn parent(&self) -> Option<&Self> {
271 self.0
273 .rsplit_once('/')
274 .map(|(front, _)| unsafe { Self::new_unchecked(front) })
275 }
276
277 pub fn strip_suffix<'a>(&'a self, suffix: &Self) -> Option<&'a Self> {
279 self.0
280 .strip_suffix(&suffix.0)
281 .map(|s| unsafe { Self::new_unchecked(s) })
284 }
285
286 pub fn strip_prefix<'a>(&'a self, prefix: &Self) -> Option<&'a Self> {
288 self.0
289 .strip_prefix(&prefix.0)
290 .map(|s| unsafe { Self::new_unchecked(s) })
293 }
294
295 pub fn ends_with(&self, other: &Self) -> bool {
299 (self.is_root() && other.is_root())
300 || (!other.is_root() && self.as_str().ends_with(&other.0))
301 }
302
303 pub fn starts_with(&self, other: &Self) -> bool {
308 self.as_str().starts_with(&other.0)
309 && (other.len() == self.len() || self.0.as_bytes()[other.len()] == b'/')
311 }
312
313 pub fn get<'p, I>(&'p self, index: I) -> Option<I::Output>
334 where
335 I: PointerIndex<'p>,
336 {
337 index.get(self)
338 }
339
340 #[cfg(feature = "resolve")]
361 pub fn resolve<'v, R: crate::Resolve>(&self, value: &'v R) -> Result<&'v R::Value, R::Error> {
362 value.resolve(self)
363 }
364
365 #[cfg(feature = "resolve")]
388 pub fn resolve_mut<'v, R: crate::ResolveMut>(
389 &self,
390 value: &'v mut R,
391 ) -> Result<&'v mut R::Value, R::Error> {
392 value.resolve_mut(self)
393 }
394
395 pub fn intersection<'a>(&'a self, other: &Self) -> &'a Self {
397 if self.is_root() || other.is_root() {
398 return Self::root();
399 }
400 let mut idx = 0;
401 for (a, b) in self.tokens().zip(other.tokens()) {
402 if a != b {
403 break;
404 }
405 idx += a.encoded().len() + 1;
406 }
407 self.split_at_offset(idx).map_or(self, |(head, _)| head)
408 }
409
410 #[cfg(feature = "delete")]
457 pub fn delete<D: crate::Delete>(&self, value: &mut D) -> Option<D::Value> {
458 value.delete(self)
459 }
460
461 #[cfg(feature = "assign")]
484 pub fn assign<D, V>(&self, dest: &mut D, src: V) -> Result<Option<D::Value>, D::Error>
485 where
486 D: crate::Assign,
487 V: Into<D::Value>,
488 {
489 dest.assign(self, src)
490 }
491
492 pub fn components(&self) -> Components<'_> {
507 self.into()
508 }
509
510 pub fn with_trailing_token<'t>(&self, token: impl Into<Token<'t>>) -> PointerBuf {
525 let mut buf = self.to_buf();
526 buf.push_back(token.into());
527 buf
528 }
529
530 pub fn with_leading_token<'t>(&self, token: impl Into<Token<'t>>) -> PointerBuf {
545 let mut buf = self.to_buf();
546 buf.push_front(token);
547 buf
548 }
549
550 pub fn concat(&self, other: &Pointer) -> PointerBuf {
566 let mut buf = self.to_buf();
567 buf.append(other);
568 buf
569 }
570
571 pub fn len(&self) -> usize {
586 self.0.len()
587 }
588
589 pub fn is_empty(&self) -> bool {
600 self.0.is_empty()
601 }
602
603 pub fn into_buf(self: Box<Pointer>) -> PointerBuf {
605 let inner = Box::into_raw(self);
606 let inner = unsafe { Box::<str>::from_raw(inner as *mut str) };
608 PointerBuf(inner.into_string())
609 }
610}
611
612#[cfg(feature = "serde")]
613impl serde::Serialize for Pointer {
614 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
615 where
616 S: serde::Serializer,
617 {
618 <str>::serialize(&self.0, serializer)
619 }
620}
621
622#[cfg(feature = "serde")]
623impl<'de: 'p, 'p> serde::Deserialize<'de> for &'p Pointer {
624 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
625 where
626 D: serde::Deserializer<'de>,
627 {
628 use serde::de::{Error, Visitor};
629
630 struct PointerVisitor;
631
632 impl<'a> Visitor<'a> for PointerVisitor {
633 type Value = &'a Pointer;
634
635 fn expecting(&self, formatter: &mut core::fmt::Formatter) -> core::fmt::Result {
636 formatter.write_str("a borrowed Pointer")
637 }
638
639 fn visit_borrowed_str<E>(self, v: &'a str) -> Result<Self::Value, E>
640 where
641 E: Error,
642 {
643 use alloc::format;
644 Pointer::parse(v).map_err(|err| {
645 Error::custom(format!("failed to parse json pointer\n\ncaused by:\n{err}"))
646 })
647 }
648 }
649
650 deserializer.deserialize_str(PointerVisitor)
651 }
652}
653
654macro_rules! impl_source_code {
655 ($($ty:ty),+) => {
656 $(
657 #[cfg(feature = "miette")]
658 impl miette::SourceCode for $ty {
659 fn read_span<'a>(
660 &'a self,
661 span: &miette::SourceSpan,
662 context_lines_before: usize,
663 context_lines_after: usize,
664 ) -> Result<Box<dyn miette::SpanContents<'a> + 'a>, miette::MietteError> {
665 miette::SourceCode::read_span(
666 self.0.as_bytes(),
667 span,
668 context_lines_before,
669 context_lines_after,
670 )
671 }
672 }
673 )*
674 };
675}
676
677impl_source_code!(Pointer, &Pointer, PointerBuf);
678
679impl<'p> From<&'p Pointer> for Cow<'p, Pointer> {
680 fn from(value: &'p Pointer) -> Self {
681 Cow::Borrowed(value)
682 }
683}
684
685impl ToOwned for Pointer {
686 type Owned = PointerBuf;
687
688 fn to_owned(&self) -> Self::Owned {
689 self.to_buf()
690 }
691}
692
693impl PartialEq<&str> for Pointer {
694 fn eq(&self, other: &&str) -> bool {
695 &&self.0 == other
696 }
697}
698impl PartialEq<String> for &Pointer {
699 fn eq(&self, other: &String) -> bool {
700 self.0.eq(other)
701 }
702}
703impl PartialEq<str> for Pointer {
704 fn eq(&self, other: &str) -> bool {
705 &self.0 == other
706 }
707}
708
709impl PartialEq<Pointer> for &str {
710 fn eq(&self, other: &Pointer) -> bool {
711 *self == (&other.0)
712 }
713}
714
715impl PartialEq<Pointer> for String {
716 fn eq(&self, other: &Pointer) -> bool {
717 self == &other.0
718 }
719}
720
721impl PartialEq<Pointer> for str {
722 fn eq(&self, other: &Pointer) -> bool {
723 self == &other.0
724 }
725}
726
727impl PartialEq<String> for Pointer {
728 fn eq(&self, other: &String) -> bool {
729 &self.0 == other
730 }
731}
732
733impl PartialEq<PointerBuf> for Pointer {
734 fn eq(&self, other: &PointerBuf) -> bool {
735 self.0 == other.0
736 }
737}
738
739impl PartialEq<Pointer> for PointerBuf {
740 fn eq(&self, other: &Pointer) -> bool {
741 self.0 == other.0
742 }
743}
744impl PartialEq<PointerBuf> for String {
745 fn eq(&self, other: &PointerBuf) -> bool {
746 self == &other.0
747 }
748}
749impl PartialEq<String> for PointerBuf {
750 fn eq(&self, other: &String) -> bool {
751 &self.0 == other
752 }
753}
754
755impl PartialEq<PointerBuf> for str {
756 fn eq(&self, other: &PointerBuf) -> bool {
757 self == other.0
758 }
759}
760impl PartialEq<PointerBuf> for &str {
761 fn eq(&self, other: &PointerBuf) -> bool {
762 *self == other.0
763 }
764}
765
766impl AsRef<Pointer> for Pointer {
767 fn as_ref(&self) -> &Pointer {
768 self
769 }
770}
771impl AsRef<Pointer> for PointerBuf {
772 fn as_ref(&self) -> &Pointer {
773 self
774 }
775}
776
777impl PartialEq<PointerBuf> for &Pointer {
778 fn eq(&self, other: &PointerBuf) -> bool {
779 self.0 == other.0
780 }
781}
782
783impl PartialEq<&Pointer> for PointerBuf {
784 fn eq(&self, other: &&Pointer) -> bool {
785 self.0 == other.0
786 }
787}
788
789#[cfg(feature = "json")]
790impl From<&Pointer> for serde_json::Value {
791 fn from(ptr: &Pointer) -> Self {
792 ptr.to_json_value()
793 }
794}
795
796impl AsRef<str> for Pointer {
797 fn as_ref(&self) -> &str {
798 &self.0
799 }
800}
801
802impl Borrow<str> for Pointer {
803 fn borrow(&self) -> &str {
804 &self.0
805 }
806}
807
808impl AsRef<[u8]> for Pointer {
809 fn as_ref(&self) -> &[u8] {
810 self.0.as_bytes()
811 }
812}
813
814impl PartialOrd<PointerBuf> for Pointer {
815 fn partial_cmp(&self, other: &PointerBuf) -> Option<Ordering> {
816 self.0.partial_cmp(other.0.as_str())
817 }
818}
819
820impl PartialOrd<Pointer> for PointerBuf {
821 fn partial_cmp(&self, other: &Pointer) -> Option<Ordering> {
822 self.0.as_str().partial_cmp(&other.0)
823 }
824}
825impl PartialOrd<&Pointer> for PointerBuf {
826 fn partial_cmp(&self, other: &&Pointer) -> Option<Ordering> {
827 self.0.as_str().partial_cmp(&other.0)
828 }
829}
830
831impl PartialOrd<Pointer> for String {
832 fn partial_cmp(&self, other: &Pointer) -> Option<Ordering> {
833 self.as_str().partial_cmp(&other.0)
834 }
835}
836impl PartialOrd<String> for &Pointer {
837 fn partial_cmp(&self, other: &String) -> Option<Ordering> {
838 self.0.partial_cmp(other.as_str())
839 }
840}
841
842impl PartialOrd<PointerBuf> for String {
843 fn partial_cmp(&self, other: &PointerBuf) -> Option<Ordering> {
844 self.as_str().partial_cmp(other.0.as_str())
845 }
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<PointerBuf> for str {
855 fn partial_cmp(&self, other: &PointerBuf) -> Option<Ordering> {
856 self.partial_cmp(other.0.as_str())
857 }
858}
859impl PartialOrd<PointerBuf> for &str {
860 fn partial_cmp(&self, other: &PointerBuf) -> Option<Ordering> {
861 (*self).partial_cmp(other.0.as_str())
862 }
863}
864impl PartialOrd<Pointer> for &str {
865 fn partial_cmp(&self, other: &Pointer) -> Option<Ordering> {
866 (*self).partial_cmp(&other.0)
867 }
868}
869
870impl PartialOrd<&str> for &Pointer {
871 fn partial_cmp(&self, other: &&str) -> Option<Ordering> {
872 PartialOrd::partial_cmp(&self.0[..], &other[..])
873 }
874}
875
876impl PartialOrd<String> for Pointer {
877 fn partial_cmp(&self, other: &String) -> Option<Ordering> {
878 self.0.partial_cmp(other.as_str())
879 }
880}
881
882impl PartialOrd<&str> for PointerBuf {
883 fn partial_cmp(&self, other: &&str) -> Option<Ordering> {
884 PartialOrd::partial_cmp(&self.0[..], &other[..])
885 }
886}
887
888impl PartialOrd<PointerBuf> for &Pointer {
889 fn partial_cmp(&self, other: &PointerBuf) -> Option<Ordering> {
890 self.0.partial_cmp(other.0.as_str())
891 }
892}
893
894impl PartialOrd<String> for PointerBuf {
895 fn partial_cmp(&self, other: &String) -> Option<Ordering> {
896 self.0.partial_cmp(other)
897 }
898}
899
900impl<'a> IntoIterator for &'a Pointer {
901 type Item = Token<'a>;
902 type IntoIter = Tokens<'a>;
903 fn into_iter(self) -> Self::IntoIter {
904 self.tokens()
905 }
906}
907
908#[derive(Clone, Default, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
915pub struct PointerBuf(String);
916
917impl PointerBuf {
918 pub fn root() -> Self {
922 Self::new()
923 }
924
925 pub fn new() -> Self {
927 Self(String::new())
928 }
929
930 pub unsafe fn new_unchecked(s: impl Into<String>) -> Self {
935 Self(s.into())
936 }
937
938 pub fn parse(s: impl Into<String>) -> Result<Self, RichParseError> {
943 let s = s.into();
944 match validate(&s) {
945 Ok(_) => Ok(Self(s)),
946 Err(err) => Err(err.into_report(s)),
947 }
948 }
949
950 pub fn from_tokens<'t>(tokens: impl IntoIterator<Item: Into<Token<'t>>>) -> Self {
952 let mut inner = String::new();
953 for t in tokens.into_iter().map(Into::into) {
954 inner.push('/');
955 inner.push_str(t.encoded());
956 }
957 PointerBuf(inner)
958 }
959
960 pub fn as_ptr(&self) -> &Pointer {
962 self
963 }
964
965 pub fn push_front<'t>(&mut self, token: impl Into<Token<'t>>) {
967 self.0.insert(0, '/');
968 self.0.insert_str(1, token.into().encoded());
969 }
970
971 pub fn push_back<'t>(&mut self, token: impl Into<Token<'t>>) {
973 self.0.push('/');
974 self.0.push_str(token.into().encoded());
975 }
976
977 pub fn pop_back(&mut self) -> Option<Token<'static>> {
979 if let Some(idx) = self.0.rfind('/') {
980 let back = unsafe { Token::from_encoded_unchecked(self.0.split_off(idx + 1)) };
982 self.0.pop(); Some(back)
984 } else {
985 None
986 }
987 }
988
989 pub fn pop_front(&mut self) -> Option<Token<'static>> {
991 (!self.is_root()).then(|| {
992 let mut token = if let Some(idx) = self.0[1..].find('/') {
994 let token = self.0.split_off(idx + 1);
995 core::mem::replace(&mut self.0, token)
996 } else {
997 core::mem::take(&mut self.0)
998 };
999 token.remove(0);
1001 unsafe { Token::from_encoded_unchecked(token) }
1003 })
1004 }
1005
1006 pub fn append<P: AsRef<Pointer>>(&mut self, other: P) -> &PointerBuf {
1008 let other = other.as_ref();
1009 if self.is_root() {
1010 self.0 = other.0.to_string();
1011 } else if !other.is_root() {
1012 self.0.push_str(&other.0);
1013 }
1014 self
1015 }
1016
1017 pub fn replace<'t>(
1023 &mut self,
1024 index: usize,
1025 token: impl Into<Token<'t>>,
1026 ) -> Result<Option<Token<'_>>, ReplaceError> {
1027 if self.is_root() {
1028 return Err(ReplaceError {
1029 count: self.count(),
1030 index,
1031 });
1032 }
1033 let mut tokens = self.tokens().collect::<Vec<_>>();
1034 if index >= tokens.len() {
1035 return Err(ReplaceError {
1036 count: tokens.len(),
1037 index,
1038 });
1039 }
1040 let old = tokens.get(index).map(super::token::Token::to_owned);
1041 tokens[index] = token.into();
1042
1043 let mut buf = String::new();
1044 for token in tokens {
1045 buf.push('/');
1046 buf.push_str(token.encoded());
1047 }
1048 self.0 = buf;
1049
1050 Ok(old)
1051 }
1052
1053 pub fn clear(&mut self) {
1055 self.0.clear();
1056 }
1057}
1058
1059impl FromStr for PointerBuf {
1060 type Err = ParseError;
1061 fn from_str(s: &str) -> Result<Self, Self::Err> {
1062 Self::try_from(s)
1063 }
1064}
1065
1066impl Borrow<Pointer> for PointerBuf {
1067 fn borrow(&self) -> &Pointer {
1068 self.as_ptr()
1069 }
1070}
1071
1072impl Deref for PointerBuf {
1073 type Target = Pointer;
1074 fn deref(&self) -> &Self::Target {
1075 unsafe { Pointer::new_unchecked(self.0.as_str()) }
1077 }
1078}
1079
1080impl From<PointerBuf> for Box<Pointer> {
1081 fn from(value: PointerBuf) -> Self {
1082 let s = value.0.into_boxed_str();
1083 unsafe { Box::from_raw(Box::into_raw(s) as *mut Pointer) }
1085 }
1086}
1087
1088#[cfg(feature = "serde")]
1089impl<'de> serde::Deserialize<'de> for PointerBuf {
1090 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
1091 where
1092 D: serde::Deserializer<'de>,
1093 {
1094 use serde::de::Error;
1095 let s = String::deserialize(deserializer)?;
1096 PointerBuf::try_from(s).map_err(D::Error::custom)
1097 }
1098}
1099
1100#[cfg(feature = "serde")]
1101impl serde::Serialize for PointerBuf {
1102 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
1103 where
1104 S: serde::Serializer,
1105 {
1106 String::serialize(&self.0, serializer)
1107 }
1108}
1109
1110impl From<PointerBuf> for Cow<'static, Pointer> {
1111 fn from(value: PointerBuf) -> Self {
1112 Cow::Owned(value)
1113 }
1114}
1115
1116impl From<Token<'_>> for PointerBuf {
1117 fn from(t: Token) -> Self {
1118 PointerBuf::from_tokens([t])
1119 }
1120}
1121
1122impl TryFrom<String> for PointerBuf {
1123 type Error = ParseError;
1124 fn try_from(value: String) -> Result<Self, Self::Error> {
1125 let _ = validate(&value)?;
1126 Ok(Self(value))
1127 }
1128}
1129
1130impl From<usize> for PointerBuf {
1131 fn from(value: usize) -> Self {
1132 PointerBuf::from_tokens([value])
1133 }
1134}
1135
1136impl<'a> IntoIterator for &'a PointerBuf {
1137 type Item = Token<'a>;
1138 type IntoIter = Tokens<'a>;
1139 fn into_iter(self) -> Self::IntoIter {
1140 self.tokens()
1141 }
1142}
1143
1144impl TryFrom<&str> for PointerBuf {
1145 type Error = ParseError;
1146 fn try_from(value: &str) -> Result<Self, Self::Error> {
1147 Pointer::parse(value).map(Pointer::to_buf)
1148 }
1149}
1150
1151impl PartialEq<&str> for PointerBuf {
1152 fn eq(&self, other: &&str) -> bool {
1153 &self.0 == other
1154 }
1155}
1156
1157impl PartialEq<str> for PointerBuf {
1158 fn eq(&self, other: &str) -> bool {
1159 self.0 == other
1160 }
1161}
1162
1163impl core::fmt::Display for PointerBuf {
1164 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
1165 self.0.fmt(f)
1166 }
1167}
1168
1169#[derive(Debug, PartialEq)]
1171pub enum ParseError {
1172 NoLeadingSlash,
1174
1175 InvalidEncoding {
1178 offset: usize,
1181 source: EncodingError,
1183 },
1184}
1185
1186impl ParseError {
1187 pub fn offset(&self) -> usize {
1190 match self {
1191 Self::NoLeadingSlash => 0,
1192 Self::InvalidEncoding { offset, .. } => *offset,
1193 }
1194 }
1195 pub fn invalid_encoding_len(&self, subject: &str) -> usize {
1197 match self {
1198 Self::NoLeadingSlash => 0,
1199 Self::InvalidEncoding { offset, .. } => {
1200 if *offset < subject.len() - 1 {
1201 2
1202 } else {
1203 1
1204 }
1205 }
1206 }
1207 }
1208}
1209
1210impl Diagnostic for ParseError {
1211 type Subject = String;
1212
1213 fn url() -> &'static str {
1214 diagnostic_url!(struct ParseError)
1215 }
1216
1217 fn labels(&self, subject: &Self::Subject) -> Option<Box<dyn Iterator<Item = Label>>> {
1218 let offset = self.complete_offset();
1219 let len = self.invalid_encoding_len(subject);
1220 let text = match self {
1221 ParseError::NoLeadingSlash => "must start with a slash ('/')",
1222 ParseError::InvalidEncoding { .. } => "'~' must be followed by '0' or '1'",
1223 }
1224 .to_string();
1225 Some(Box::new(once(Label::new(text, offset, len))))
1226 }
1227}
1228
1229#[cfg(feature = "miette")]
1230impl miette::Diagnostic for ParseError {}
1231
1232impl fmt::Display for ParseError {
1233 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1234 match self {
1235 Self::NoLeadingSlash { .. } => {
1236 write!(
1237 f,
1238 "json pointer failed to parse; does not start with a slash ('/') and is not empty"
1239 )
1240 }
1241 Self::InvalidEncoding { offset, .. } => {
1242 write!(
1243 f,
1244 "json pointer failed to parse; the first token in the partial-pointer starting at offset {offset} is malformed"
1245 )
1246 }
1247 }
1248 }
1249}
1250
1251impl ParseError {
1252 #[deprecated(note = "renamed to `is_no_leading_slash`", since = "0.7.0")]
1253 pub fn is_no_leading_backslash(&self) -> bool {
1255 matches!(self, Self::NoLeadingSlash { .. })
1256 }
1257
1258 pub fn is_no_leading_slash(&self) -> bool {
1260 matches!(self, Self::NoLeadingSlash { .. })
1261 }
1262
1263 pub fn is_invalid_encoding(&self) -> bool {
1265 matches!(self, Self::InvalidEncoding { .. })
1266 }
1267
1268 pub fn pointer_offset(&self) -> usize {
1281 match *self {
1282 Self::NoLeadingSlash { .. } => 0,
1283 Self::InvalidEncoding { offset, .. } => offset,
1284 }
1285 }
1286
1287 pub fn source_offset(&self) -> usize {
1301 match self {
1302 Self::NoLeadingSlash { .. } => 0,
1303 Self::InvalidEncoding { source, .. } => source.offset,
1304 }
1305 }
1306
1307 pub fn complete_offset(&self) -> usize {
1319 self.source_offset() + self.pointer_offset()
1320 }
1321}
1322
1323#[cfg(feature = "std")]
1324impl std::error::Error for ParseError {
1325 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
1326 match self {
1327 Self::InvalidEncoding { source, .. } => Some(source),
1328 Self::NoLeadingSlash => None,
1329 }
1330 }
1331}
1332
1333pub type RichParseError = Report<ParseError>;
1335
1336#[derive(Debug, PartialEq, Eq)]
1339pub struct ReplaceError {
1340 pub index: usize,
1342 pub count: usize,
1344}
1345
1346impl fmt::Display for ReplaceError {
1347 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1348 write!(f, "index {} is out of bounds ({})", self.index, self.count)
1349 }
1350}
1351
1352#[cfg(feature = "std")]
1353impl std::error::Error for ReplaceError {}
1354
1355const fn validate(value: &str) -> Result<&str, ParseError> {
1356 if value.is_empty() {
1357 return Ok(value);
1358 }
1359 if let Err(err) = validate_bytes(value.as_bytes(), 0) {
1360 return Err(err);
1361 }
1362 Ok(value)
1363}
1364
1365const fn validate_bytes(bytes: &[u8], offset: usize) -> Result<(), ParseError> {
1371 if bytes[0] != b'/' && offset == 0 {
1372 return Err(ParseError::NoLeadingSlash);
1373 }
1374
1375 let mut ptr_offset = offset; let mut tok_offset = 0; let mut i = offset;
1379 while i < bytes.len() {
1380 match bytes[i] {
1381 b'/' => {
1382 ptr_offset = i;
1383 tok_offset = 0;
1385 }
1386 b'~' => {
1387 if i + 1 >= bytes.len() || (bytes[i + 1] != b'0' && bytes[i + 1] != b'1') {
1390 return Err(ParseError::InvalidEncoding {
1404 offset: ptr_offset,
1405 source: EncodingError {
1406 offset: tok_offset,
1407 source: InvalidEncoding::Tilde,
1408 },
1409 });
1410 }
1411 i += 1;
1413 tok_offset += 1;
1416 }
1417 _ => {}
1418 }
1419 i += 1;
1420 tok_offset += 1;
1422 }
1423 Ok(())
1424}
1425
1426#[cfg(test)]
1427mod tests {
1428 use std::error::Error;
1429
1430 use super::*;
1431 use quickcheck::TestResult;
1432 use quickcheck_macros::quickcheck;
1433
1434 #[test]
1435 #[should_panic = "invalid json pointer"]
1436 fn from_const_validates() {
1437 let _ = Pointer::from_static("foo/bar");
1438 }
1439
1440 #[test]
1441 fn root_is_alias_of_new_pathbuf() {
1442 assert_eq!(PointerBuf::root(), PointerBuf::new());
1443 }
1444
1445 #[test]
1446 fn from_unchecked_pathbuf() {
1447 let s = "/foo/bar/0";
1448 assert_eq!(
1449 unsafe { PointerBuf::new_unchecked(String::from(s)) },
1450 PointerBuf::parse(s).unwrap()
1451 );
1452 }
1453
1454 #[test]
1455 fn split_at_offset() {
1456 let ptr = Pointer::from_static("/foo/bar/baz");
1457 for (offset, head, tail) in [
1459 (0, "", "/foo/bar/baz"),
1460 (4, "/foo", "/bar/baz"),
1461 (8, "/foo/bar", "/baz"),
1462 ] {
1463 let (h, t) = ptr.split_at_offset(offset).unwrap();
1464 assert_eq!(h, Pointer::from_static(head));
1465 assert_eq!(t, Pointer::from_static(tail));
1466 }
1467 assert_eq!(ptr.split_at_offset(3), None);
1469 assert_eq!(ptr.split_at_offset(ptr.as_str().len()), None);
1471 assert_eq!(ptr.split_at_offset(usize::MAX), None);
1472 }
1473
1474 #[test]
1475 #[allow(deprecated)]
1476 fn split_at_delegates_to_split_at_offset() {
1477 let ptr = Pointer::from_static("/foo/bar/baz");
1478 assert_eq!(ptr.split_at(4), ptr.split_at_offset(4));
1479 assert_eq!(ptr.split_at(3), None);
1480 }
1481
1482 #[test]
1483 fn strip_suffix() {
1484 let p = Pointer::from_static("/example/pointer/to/some/value");
1485 let stripped = p
1486 .strip_suffix(Pointer::from_static("/to/some/value"))
1487 .unwrap();
1488 assert_eq!(stripped, "/example/pointer");
1489 }
1490
1491 #[test]
1492 fn strip_prefix() {
1493 let p = Pointer::from_static("/example/pointer/to/some/value");
1494 let stripped = p
1495 .strip_prefix(Pointer::from_static("/example/pointer"))
1496 .unwrap();
1497 assert_eq!(stripped, "/to/some/value");
1498 }
1499
1500 #[test]
1501 fn ends_with() {
1502 let p = Pointer::from_static("/foo/bar");
1504 let q = Pointer::from_static("/bar");
1505 assert!(p.ends_with(q));
1506 let q = Pointer::from_static("/foo/bar");
1507 assert!(p.ends_with(q));
1508
1509 let q = Pointer::from_static("/barz");
1511 assert!(!p.ends_with(q));
1512 let q = Pointer::from_static("/");
1513 assert!(!p.ends_with(q));
1514 let q = Pointer::from_static("");
1515 assert!(!p.ends_with(q));
1516 let q = Pointer::from_static("/qux/foo/bar");
1517 assert!(!p.ends_with(q));
1518
1519 let p = Pointer::root();
1521 let q = Pointer::root();
1522 assert!(p.ends_with(q));
1523 }
1524
1525 #[test]
1526 fn starts_with() {
1527 let p = Pointer::from_static("/foo/bar");
1529 let q = Pointer::from_static("/foo");
1530 assert!(p.starts_with(q));
1531 let q = Pointer::from_static("/foo/bar");
1532 assert!(p.starts_with(q));
1533
1534 let q = Pointer::from_static("/");
1536 assert!(!p.starts_with(q));
1537 let q = Pointer::from_static("/fo");
1538 assert!(!p.starts_with(q));
1539 let q = Pointer::from_static("/foo/");
1540 assert!(!p.starts_with(q));
1541
1542 let p = Pointer::root();
1544 let q = Pointer::root();
1545 assert!(p.starts_with(q));
1546 let p = Pointer::from_static("/");
1547 assert!(p.starts_with(q));
1548 let p = Pointer::from_static("/any/thing");
1549 assert!(p.starts_with(q));
1550 }
1551
1552 #[test]
1553 fn parse() {
1554 let tests = [
1555 ("", Ok("")),
1556 ("/", Ok("/")),
1557 ("/foo", Ok("/foo")),
1558 ("/foo/bar", Ok("/foo/bar")),
1559 ("/foo/bar/baz", Ok("/foo/bar/baz")),
1560 ("/foo/bar/baz/~0", Ok("/foo/bar/baz/~0")),
1561 ("/foo/bar/baz/~1", Ok("/foo/bar/baz/~1")),
1562 ("/foo/bar/baz/~01", Ok("/foo/bar/baz/~01")),
1563 ("/foo/bar/baz/~10", Ok("/foo/bar/baz/~10")),
1564 ("/foo/bar/baz/~11", Ok("/foo/bar/baz/~11")),
1565 ("/foo/bar/baz/~1/~0", Ok("/foo/bar/baz/~1/~0")),
1566 ("missing-slash", Err(ParseError::NoLeadingSlash)),
1567 (
1568 "/~",
1569 Err(ParseError::InvalidEncoding {
1570 offset: 0,
1571 source: EncodingError {
1572 offset: 1,
1573 source: InvalidEncoding::Tilde,
1574 },
1575 }),
1576 ),
1577 (
1578 "/~2",
1579 Err(ParseError::InvalidEncoding {
1580 offset: 0,
1581 source: EncodingError {
1582 offset: 1,
1583 source: InvalidEncoding::Tilde,
1584 },
1585 }),
1586 ),
1587 (
1588 "/~a",
1589 Err(ParseError::InvalidEncoding {
1590 offset: 0,
1591 source: EncodingError {
1592 offset: 1,
1593 source: InvalidEncoding::Tilde,
1594 },
1595 }),
1596 ),
1597 ];
1598 for (input, expected) in tests {
1599 let actual = Pointer::parse(input).map(Pointer::as_str);
1600 assert_eq!(actual, expected);
1601 }
1602 }
1603
1604 #[test]
1605 fn parse_error_offsets() {
1606 let err = Pointer::parse("/foo/invalid~encoding").unwrap_err();
1607 assert_eq!(err.pointer_offset(), 4);
1608 assert_eq!(err.source_offset(), 8);
1609 assert_eq!(err.complete_offset(), 12);
1610
1611 let err = Pointer::parse("invalid~encoding").unwrap_err();
1612 assert_eq!(err.pointer_offset(), 0);
1613 assert_eq!(err.source_offset(), 0);
1614
1615 let err = Pointer::parse("no-leading/slash").unwrap_err();
1616 assert!(err.source().is_none());
1617 }
1618
1619 #[test]
1620 fn pointer_buf_clear() {
1621 let mut ptr = PointerBuf::from_tokens(["foo", "bar"]);
1622 ptr.clear();
1623 assert_eq!(ptr, "");
1624 }
1625
1626 #[test]
1627 fn push_pop_back() {
1628 let mut ptr = PointerBuf::default();
1629 assert_eq!(ptr, "", "default, root pointer should equal \"\"");
1630 assert_eq!(ptr.count(), 0, "default pointer should have 0 tokens");
1631
1632 ptr.push_back("foo");
1633 assert_eq!(ptr, "/foo", "pointer should equal \"/foo\" after push_back");
1634
1635 ptr.push_back("bar");
1636 assert_eq!(ptr, "/foo/bar");
1637 ptr.push_back("/baz");
1638 assert_eq!(ptr, "/foo/bar/~1baz");
1639
1640 let mut ptr = PointerBuf::from_tokens(["foo", "bar"]);
1641 assert_eq!(ptr.pop_back(), Some("bar".into()));
1642 assert_eq!(ptr, "/foo", "pointer should equal \"/foo\" after pop_back");
1643 assert_eq!(ptr.pop_back(), Some("foo".into()));
1644 assert_eq!(ptr, "", "pointer should equal \"\" after pop_back");
1645 }
1646
1647 #[test]
1648 fn replace_token() {
1649 let mut ptr = PointerBuf::try_from("/test/token").unwrap();
1650
1651 let res = ptr.replace(0, "new");
1652 assert!(res.is_ok());
1653 assert_eq!(ptr, "/new/token");
1654
1655 let res = ptr.replace(3, "invalid");
1656
1657 assert!(res.is_err());
1658 }
1659
1660 #[test]
1661 fn push_pop_front() {
1662 let mut ptr = PointerBuf::default();
1663 assert_eq!(ptr, "");
1664 assert_eq!(ptr.count(), 0);
1665 ptr.push_front("bar");
1666 assert_eq!(ptr, "/bar");
1667 assert_eq!(ptr.count(), 1);
1668
1669 ptr.push_front("foo");
1670 assert_eq!(ptr, "/foo/bar");
1671 assert_eq!(ptr.count(), 2);
1672
1673 ptr.push_front("too");
1674 assert_eq!(ptr, "/too/foo/bar");
1675 assert_eq!(ptr.count(), 3);
1676
1677 assert_eq!(ptr.pop_front(), Some("too".into()));
1678 assert_eq!(ptr, "/foo/bar");
1679 assert_eq!(ptr.count(), 2);
1680
1681 assert_eq!(ptr.pop_back(), Some("bar".into()));
1682 assert_eq!(ptr, "/foo");
1683 assert_eq!(ptr.count(), 1);
1684 assert_eq!(ptr.pop_front(), Some("foo".into()));
1685 assert_eq!(ptr, "");
1686 }
1687
1688 #[test]
1689 fn pop_front_works_with_empty_strings() {
1690 {
1691 let mut ptr = PointerBuf::from_tokens(["bar", "", ""]);
1692
1693 assert_eq!(ptr.tokens().count(), 3);
1694 let mut token = ptr.pop_front();
1695 assert_eq!(token, Some(Token::new("bar")));
1696 assert_eq!(ptr.tokens().count(), 2);
1697 token = ptr.pop_front();
1698 assert_eq!(token, Some(Token::new("")));
1699 assert_eq!(ptr.tokens().count(), 1);
1700 token = ptr.pop_front();
1701 assert_eq!(token, Some(Token::new("")));
1702 assert_eq!(ptr.tokens().count(), 0);
1703 assert_eq!(ptr, Pointer::root());
1704 }
1705 {
1706 let mut ptr = PointerBuf::new();
1707 assert_eq!(ptr.tokens().count(), 0);
1708 ptr.push_back("");
1709 assert_eq!(ptr.tokens().count(), 1);
1710 ptr.pop_back();
1711 assert_eq!(ptr.tokens().count(), 0);
1712 }
1713 {
1714 let mut ptr = PointerBuf::new();
1715 let input = ["", "", "", "foo", "", "bar", "baz", ""];
1716 for (idx, &s) in input.iter().enumerate() {
1717 assert_eq!(ptr.tokens().count(), idx);
1718 ptr.push_back(s);
1719 }
1720 assert_eq!(ptr.tokens().count(), input.len());
1721 for (idx, s) in input.iter().enumerate() {
1722 assert_eq!(ptr.tokens().count(), 8 - idx);
1723 assert_eq!(ptr.front().unwrap().decoded(), *s);
1724 assert_eq!(ptr.pop_front().unwrap().decoded(), *s);
1725 }
1726 assert_eq!(ptr.tokens().count(), 0);
1727 assert!(ptr.front().is_none());
1728 assert!(ptr.pop_front().is_none());
1729 }
1730 }
1731
1732 #[test]
1733 fn formatting() {
1734 assert_eq!(PointerBuf::from_tokens(["foo", "bar"]), "/foo/bar");
1735 assert_eq!(
1736 PointerBuf::from_tokens(["~/foo", "~bar", "/baz"]),
1737 "/~0~1foo/~0bar/~1baz"
1738 );
1739 assert_eq!(PointerBuf::from_tokens(["field", "", "baz"]), "/field//baz");
1740 assert_eq!(PointerBuf::default(), "");
1741
1742 let ptr = PointerBuf::from_tokens(["foo", "bar", "baz"]);
1743 assert_eq!(ptr.to_string(), "/foo/bar/baz");
1744 }
1745
1746 #[test]
1747 fn last() {
1748 let ptr = Pointer::from_static("/foo/bar");
1749
1750 assert_eq!(ptr.last(), Some("bar".into()));
1751
1752 let ptr = Pointer::from_static("/foo/bar/-");
1753 assert_eq!(ptr.last(), Some("-".into()));
1754
1755 let ptr = Pointer::from_static("/-");
1756 assert_eq!(ptr.last(), Some("-".into()));
1757
1758 let ptr = Pointer::root();
1759 assert_eq!(ptr.last(), None);
1760
1761 let ptr = Pointer::from_static("/bar");
1762 assert_eq!(ptr.last(), Some("bar".into()));
1763 }
1764
1765 #[test]
1766 fn first() {
1767 let ptr = Pointer::from_static("/foo/bar");
1768 assert_eq!(ptr.first(), Some("foo".into()));
1769
1770 let ptr = Pointer::from_static("/foo/bar/-");
1771 assert_eq!(ptr.first(), Some("foo".into()));
1772
1773 let ptr = Pointer::root();
1774 assert_eq!(ptr.first(), None);
1775 }
1776
1777 #[test]
1778 fn pointerbuf_try_from() {
1779 let ptr = PointerBuf::from_tokens(["foo", "bar", "~/"]);
1780
1781 assert_eq!(PointerBuf::try_from("/foo/bar/~0~1").unwrap(), ptr);
1782 let into: PointerBuf = "/foo/bar/~0~1".try_into().unwrap();
1783 assert_eq!(ptr, into);
1784 }
1785
1786 #[test]
1787 #[cfg(all(feature = "serde", feature = "json"))]
1788 fn to_json_value() {
1789 use serde_json::Value;
1790 let ptr = Pointer::from_static("/foo/bar");
1791 assert_eq!(ptr.to_json_value(), Value::String(String::from("/foo/bar")));
1792 }
1793
1794 #[cfg(all(feature = "resolve", feature = "json"))]
1795 #[test]
1796 fn resolve() {
1797 use serde_json::json;
1799 let value = json!({
1800 "foo": {
1801 "bar": {
1802 "baz": "qux"
1803 }
1804 }
1805 });
1806 let ptr = Pointer::from_static("/foo/bar/baz");
1807 let resolved = ptr.resolve(&value).unwrap();
1808 assert_eq!(resolved, &json!("qux"));
1809 }
1810
1811 #[cfg(all(feature = "delete", feature = "json"))]
1812 #[test]
1813 fn delete() {
1814 use serde_json::json;
1815 let mut value = json!({
1816 "foo": {
1817 "bar": {
1818 "baz": "qux"
1819 }
1820 }
1821 });
1822 let ptr = Pointer::from_static("/foo/bar/baz");
1823 let deleted = ptr.delete(&mut value).unwrap();
1824 assert_eq!(deleted, json!("qux"));
1825 assert_eq!(
1826 value,
1827 json!({
1828 "foo": {
1829 "bar": {}
1830 }
1831 })
1832 );
1833 }
1834
1835 #[cfg(all(feature = "assign", feature = "json"))]
1836 #[test]
1837 fn assign() {
1838 use serde_json::json;
1839 let mut value = json!({});
1840 let ptr = Pointer::from_static("/foo/bar");
1841 let replaced = ptr.assign(&mut value, json!("baz")).unwrap();
1842 assert_eq!(replaced, None);
1843 assert_eq!(
1844 value,
1845 json!({
1846 "foo": {
1847 "bar": "baz"
1848 }
1849 })
1850 );
1851 }
1852
1853 #[test]
1854 fn get() {
1855 let ptr = Pointer::from_static("/0/1/2/3/4/5/6/7/8/9");
1856 for i in 0..10 {
1857 assert_eq!(ptr.get(i).unwrap().decoded(), i.to_string());
1858 }
1859 }
1860
1861 #[test]
1862 fn replace_token_success() {
1863 let mut ptr = PointerBuf::from_tokens(["foo", "bar", "baz"]);
1864 assert!(ptr.replace(1, "qux").is_ok());
1865 assert_eq!(ptr, PointerBuf::from_tokens(["foo", "qux", "baz"]));
1866
1867 assert!(ptr.replace(0, "corge").is_ok());
1868 assert_eq!(ptr, PointerBuf::from_tokens(["corge", "qux", "baz"]));
1869
1870 assert!(ptr.replace(2, "quux").is_ok());
1871 assert_eq!(ptr, PointerBuf::from_tokens(["corge", "qux", "quux"]));
1872 }
1873
1874 #[test]
1875 fn replace_token_out_of_bounds() {
1876 let mut ptr = PointerBuf::from_tokens(["foo", "bar"]);
1877 assert!(ptr.replace(2, "baz").is_err());
1878 assert_eq!(ptr, PointerBuf::from_tokens(["foo", "bar"])); }
1880
1881 #[test]
1882 fn replace_token_with_empty_string() {
1883 let mut ptr = PointerBuf::from_tokens(["foo", "bar", "baz"]);
1884 assert!(ptr.replace(1, "").is_ok());
1885 assert_eq!(ptr, PointerBuf::from_tokens(["foo", "", "baz"]));
1886 }
1887
1888 #[test]
1889 fn replace_token_in_empty_pointer() {
1890 let mut ptr = PointerBuf::default();
1891 assert!(ptr.replace(0, "foo").is_err());
1892 assert_eq!(ptr, PointerBuf::default()); }
1894
1895 #[test]
1896 fn pop_back_works_with_empty_strings() {
1897 {
1898 let mut ptr = PointerBuf::new();
1899 ptr.push_back("");
1900 ptr.push_back("");
1901 ptr.push_back("bar");
1902
1903 assert_eq!(ptr.tokens().count(), 3);
1904 ptr.pop_back();
1905 assert_eq!(ptr.tokens().count(), 2);
1906 ptr.pop_back();
1907 assert_eq!(ptr.tokens().count(), 1);
1908 ptr.pop_back();
1909 assert_eq!(ptr.tokens().count(), 0);
1910 assert_eq!(ptr, PointerBuf::new());
1911 }
1912 {
1913 let mut ptr = PointerBuf::new();
1914 assert_eq!(ptr.tokens().count(), 0);
1915 ptr.push_back("");
1916 assert_eq!(ptr.tokens().count(), 1);
1917 ptr.pop_back();
1918 assert_eq!(ptr.tokens().count(), 0);
1919 }
1920 {
1921 let mut ptr = PointerBuf::new();
1922 let input = ["", "", "", "foo", "", "bar", "baz", ""];
1923 for (idx, &s) in input.iter().enumerate() {
1924 assert_eq!(ptr.tokens().count(), idx);
1925 ptr.push_back(s);
1926 }
1927 assert_eq!(ptr.tokens().count(), input.len());
1928 for (idx, s) in input.iter().enumerate().rev() {
1929 assert_eq!(ptr.tokens().count(), idx + 1);
1930 assert_eq!(ptr.back().unwrap().decoded(), *s);
1931 assert_eq!(ptr.pop_back().unwrap().decoded(), *s);
1932 }
1933 assert_eq!(ptr.tokens().count(), 0);
1934 assert!(ptr.back().is_none());
1935 assert!(ptr.pop_back().is_none());
1936 }
1937 }
1938
1939 #[test]
1940 #[allow(clippy::useless_asref)]
1944 fn pointerbuf_as_ref_returns_pointer() {
1945 let ptr_str = "/foo/bar";
1946 let ptr = Pointer::from_static(ptr_str);
1947 let ptr_buf = ptr.to_buf();
1948 assert_eq!(ptr_buf.as_ref(), ptr);
1949 let r: &Pointer = ptr.as_ref();
1950 assert_eq!(ptr, r);
1951
1952 let s: &str = ptr.as_ref();
1953 assert_eq!(s, ptr_str);
1954
1955 let b: &[u8] = ptr.as_ref();
1956 assert_eq!(b, ptr_str.as_bytes());
1957 }
1958
1959 #[test]
1960 fn from_tokens() {
1961 let ptr = PointerBuf::from_tokens(["foo", "bar", "baz"]);
1962 assert_eq!(ptr, "/foo/bar/baz");
1963 }
1964
1965 #[test]
1966 fn pointer_borrow() {
1967 let ptr = Pointer::from_static("/foo/bar");
1968 let borrowed: &str = ptr.borrow();
1969 assert_eq!(borrowed, "/foo/bar");
1970 }
1971
1972 #[test]
1973 #[cfg(feature = "json")]
1974 fn into_value() {
1975 use alloc::string::ToString;
1976 use serde_json::Value;
1977 let ptr = Pointer::from_static("/foo/bar");
1978 let value: Value = ptr.into();
1979 assert_eq!(value, Value::String("/foo/bar".to_string()));
1980 }
1981
1982 #[test]
1983 fn intersect() {
1984 let base = Pointer::from_static("/foo/bar");
1985 let a = Pointer::from_static("/foo/bar/qux");
1986 let b = Pointer::from_static("/foo/bar");
1987 assert_eq!(a.intersection(b), base);
1988
1989 let base = Pointer::from_static("");
1990 let a = Pointer::from_static("/foo");
1991 let b = Pointer::from_static("/");
1992 assert_eq!(a.intersection(b), base);
1993
1994 let base = Pointer::from_static("");
1995 let a = Pointer::from_static("/fooqux");
1996 let b = Pointer::from_static("/foobar");
1997 assert_eq!(a.intersection(b), base);
1998 }
1999
2000 #[quickcheck]
2001 fn qc_pop_and_push(mut ptr: PointerBuf) -> bool {
2002 let subjectal_ptr = ptr.clone();
2003 let mut tokens = Vec::with_capacity(ptr.count());
2004 while let Some(token) = ptr.pop_back() {
2005 tokens.push(token);
2006 }
2007 if ptr.count() != 0 || !ptr.is_root() || ptr.last().is_some() || ptr.first().is_some() {
2008 return false;
2009 }
2010 for token in tokens.drain(..) {
2011 ptr.push_front(token);
2012 }
2013 if ptr != subjectal_ptr {
2014 return false;
2015 }
2016 while let Some(token) = ptr.pop_front() {
2017 tokens.push(token);
2018 }
2019 if ptr.count() != 0 || !ptr.is_root() || ptr.last().is_some() || ptr.first().is_some() {
2020 return false;
2021 }
2022 for token in tokens {
2023 ptr.push_back(token);
2024 }
2025 ptr == subjectal_ptr
2026 }
2027
2028 #[quickcheck]
2029 fn qc_split(ptr: PointerBuf) -> bool {
2030 if let Some((head, tail)) = ptr.split_front() {
2031 {
2032 let Some(first) = ptr.first() else {
2033 return false;
2034 };
2035 if first != head {
2036 return false;
2037 }
2038 }
2039 {
2040 let mut copy = ptr.clone();
2041 copy.pop_front();
2042 if copy != tail {
2043 return false;
2044 }
2045 }
2046 {
2047 let mut buf = tail.to_buf();
2048 buf.push_front(head.clone());
2049 if buf != ptr {
2050 return false;
2051 }
2052 }
2053 {
2054 let fmt = alloc::format!("/{}{tail}", head.encoded());
2055 if Pointer::parse(&fmt).unwrap() != ptr {
2056 return false;
2057 }
2058 }
2059 } else {
2060 return ptr.is_root()
2061 && ptr.count() == 0
2062 && ptr.last().is_none()
2063 && ptr.first().is_none();
2064 }
2065 if let Some((head, tail)) = ptr.split_back() {
2066 {
2067 let Some(last) = ptr.last() else {
2068 return false;
2069 };
2070 if last != tail {
2071 return false;
2072 }
2073 }
2074 {
2075 let mut copy = ptr.clone();
2076 copy.pop_back();
2077 if copy != head {
2078 return false;
2079 }
2080 }
2081 {
2082 let mut buf = head.to_buf();
2083 buf.push_back(tail.clone());
2084 if buf != ptr {
2085 return false;
2086 }
2087 }
2088 {
2089 let fmt = alloc::format!("{head}/{}", tail.encoded());
2090 if Pointer::parse(&fmt).unwrap() != ptr {
2091 return false;
2092 }
2093 }
2094 if Some(head) != ptr.parent() {
2095 return false;
2096 }
2097 } else {
2098 return ptr.is_root()
2099 && ptr.count() == 0
2100 && ptr.last().is_none()
2101 && ptr.first().is_none();
2102 }
2103 true
2104 }
2105
2106 #[quickcheck]
2107 fn qc_from_tokens(tokens: Vec<String>) -> bool {
2108 let buf = PointerBuf::from_tokens(&tokens);
2109 let reconstructed: Vec<_> = buf.tokens().collect();
2110 reconstructed
2111 .into_iter()
2112 .zip(tokens)
2113 .all(|(a, b)| a.decoded() == b)
2114 }
2115
2116 #[quickcheck]
2117 fn qc_intersection(base: PointerBuf, suffix_0: PointerBuf, suffix_1: PointerBuf) -> TestResult {
2118 if suffix_0.first() == suffix_1.first() {
2119 return TestResult::discard();
2121 }
2122 let mut a = base.clone();
2123 a.append(&suffix_0);
2124 let mut b = base.clone();
2125 b.append(&suffix_1);
2126 let isect = a.intersection(&b);
2127 TestResult::from_bool(isect == base)
2128 }
2129
2130 #[cfg(all(feature = "json", feature = "std", feature = "serde"))]
2131 #[test]
2132 fn serde() {
2133 use serde::Deserialize;
2134 let ptr = PointerBuf::from_tokens(["foo", "bar"]);
2135 let json = serde_json::to_string(&ptr).unwrap();
2136 assert_eq!(json, "\"/foo/bar\"");
2137 let deserialized: PointerBuf = serde_json::from_str(&json).unwrap();
2138 assert_eq!(deserialized, ptr);
2139
2140 let ptr = Pointer::from_static("/foo/bar");
2141 let json = serde_json::to_string(&ptr).unwrap();
2142 assert_eq!(json, "\"/foo/bar\"");
2143
2144 let mut de = serde_json::Deserializer::from_str("\"/foo/bar\"");
2145 let p = <&Pointer>::deserialize(&mut de).unwrap();
2146 assert_eq!(p, ptr);
2147 let s = serde_json::to_string(p).unwrap();
2148 assert_eq!(json, s);
2149
2150 let invalid = serde_json::from_str::<&Pointer>("\"foo/bar\"");
2151 assert!(invalid.is_err());
2152 }
2153
2154 #[test]
2155 fn to_owned() {
2156 let ptr = Pointer::from_static("/bread/crumbs");
2157 let buf = ptr.to_owned();
2158 assert_eq!(buf, "/bread/crumbs");
2159 }
2160
2161 #[test]
2162 fn concat() {
2163 let ptr = Pointer::from_static("/foo");
2164 let barbaz = Pointer::from_static("/bar/baz");
2165 assert_eq!(ptr.concat(barbaz), "/foo/bar/baz");
2166 }
2167
2168 #[test]
2169 fn with_leading_token() {
2170 let ptr = Pointer::from_static("/bar");
2171 let foobar = ptr.with_leading_token("foo");
2172 assert_eq!(foobar, "/foo/bar");
2173 }
2174
2175 #[test]
2176 fn with_trailing_token() {
2177 let ptr = Pointer::from_static("/foo");
2178 let foobar = ptr.with_trailing_token("bar");
2179 assert_eq!(foobar, "/foo/bar");
2180 }
2181
2182 #[test]
2183 fn len() {
2184 let ptr = Pointer::from_static("/foo/bar");
2185 assert_eq!(ptr.len(), 8);
2186 let mut ptr = ptr.to_buf();
2187 ptr.push_back("~");
2188 assert_eq!(ptr.len(), 11);
2189 }
2190
2191 #[test]
2192 fn is_empty() {
2193 assert!(Pointer::from_static("").is_empty());
2194 assert!(!Pointer::from_static("/").is_empty());
2195 }
2196
2197 #[test]
2198 #[allow(clippy::cmp_owned, unused_must_use)]
2199 fn partial_eq() {
2200 let ptr_string = String::from("/bread/crumbs");
2201 let ptr_str = "/bread/crumbs";
2202 let ptr = Pointer::from_static(ptr_str);
2203 let ptr_buf = ptr.to_buf();
2204 <&Pointer as PartialEq<&Pointer>>::eq(&ptr, &ptr);
2205 <Pointer as PartialEq<&str>>::eq(ptr, &ptr_str);
2206 <&Pointer as PartialEq<String>>::eq(&ptr, &ptr_string);
2207 <Pointer as PartialEq<String>>::eq(ptr, &ptr_string);
2208 <Pointer as PartialEq<PointerBuf>>::eq(ptr, &ptr_buf);
2209 <&str as PartialEq<Pointer>>::eq(&ptr_str, ptr);
2210 <String as PartialEq<Pointer>>::eq(&ptr_string, ptr);
2211 <str as PartialEq<Pointer>>::eq(ptr_str, ptr);
2212 <PointerBuf as PartialEq<str>>::eq(&ptr_buf, ptr_str);
2213 <PointerBuf as PartialEq<PointerBuf>>::eq(&ptr_buf, &ptr_buf);
2214 <PointerBuf as PartialEq<Pointer>>::eq(&ptr_buf, ptr);
2215 <Pointer as PartialEq<PointerBuf>>::eq(ptr, &ptr_buf);
2216 <PointerBuf as PartialEq<&Pointer>>::eq(&ptr_buf, &ptr);
2217 <PointerBuf as PartialEq<&str>>::eq(&ptr_buf, &ptr_str);
2218 <PointerBuf as PartialEq<String>>::eq(&ptr_buf, &ptr_string);
2219 <&Pointer as PartialEq<PointerBuf>>::eq(&ptr, &ptr_buf);
2220 <str as PartialEq<PointerBuf>>::eq(ptr_str, &ptr_buf);
2221 <&str as PartialEq<PointerBuf>>::eq(&ptr_str, &ptr_buf);
2222 <String as PartialEq<PointerBuf>>::eq(&ptr_string, &ptr_buf);
2223 }
2224
2225 #[test]
2226 fn partial_ord() {
2227 let a_str = "/foo/bar";
2228 let a_string = a_str.to_string();
2229 let a_ptr = Pointer::from_static(a_str);
2230 let a_buf = a_ptr.to_buf();
2231 let b_str = "/foo/bar";
2232 let b_string = b_str.to_string();
2233 let b_ptr = Pointer::from_static(b_str);
2234 let b_buf = b_ptr.to_buf();
2235 let c_str = "/foo/bar/baz";
2236 let c_string = c_str.to_string();
2237 let c_ptr = Pointer::from_static(c_str);
2238 let c_buf = c_ptr.to_buf();
2239
2240 assert!(<Pointer as PartialOrd<PointerBuf>>::lt(a_ptr, &c_buf));
2241 assert!(<PointerBuf as PartialOrd<Pointer>>::lt(&a_buf, c_ptr));
2242 assert!(<String as PartialOrd<Pointer>>::lt(&a_string, c_ptr));
2243 assert!(<str as PartialOrd<Pointer>>::lt(a_str, c_ptr));
2244 assert!(<str as PartialOrd<PointerBuf>>::lt(a_str, &c_buf));
2245 assert!(<&str as PartialOrd<Pointer>>::lt(&a_str, c_ptr));
2246 assert!(<&str as PartialOrd<PointerBuf>>::lt(&a_str, &c_buf));
2247 assert!(<&Pointer as PartialOrd<PointerBuf>>::lt(&a_ptr, &c_buf));
2248 assert!(<&Pointer as PartialOrd<&str>>::lt(&b_ptr, &c_str));
2249 assert!(<Pointer as PartialOrd<String>>::lt(a_ptr, &c_string));
2250 assert!(<PointerBuf as PartialOrd<&str>>::lt(&a_buf, &c_str));
2251 assert!(<PointerBuf as PartialOrd<String>>::lt(&a_buf, &c_string));
2252 assert!(a_ptr < c_buf);
2253 assert!(c_buf > a_ptr);
2254 assert!(a_buf < c_ptr);
2255 assert!(a_ptr < c_buf);
2256 assert!(a_ptr < c_ptr);
2257 assert!(a_ptr <= c_ptr);
2258 assert!(c_ptr > a_ptr);
2259 assert!(c_ptr >= a_ptr);
2260 assert!(a_ptr == b_ptr);
2261 assert!(a_ptr <= b_ptr);
2262 assert!(a_ptr >= b_ptr);
2263 assert!(a_string < c_buf);
2264 assert!(a_string <= c_buf);
2265 assert!(c_string > a_buf);
2266 assert!(c_string >= a_buf);
2267 assert!(a_string == b_buf);
2268 assert!(a_ptr < c_buf);
2269 assert!(a_ptr <= c_buf);
2270 assert!(c_ptr > a_buf);
2271 assert!(c_ptr >= a_buf);
2272 assert!(a_ptr == b_buf);
2273 assert!(a_ptr <= b_buf);
2274 assert!(a_ptr >= b_buf);
2275 assert!(a_ptr < c_buf);
2276 assert!(c_ptr > b_string);
2277 #[allow(clippy::nonminimal_bool)]
2279 let not = !(a_ptr > c_buf);
2280 assert!(not);
2281 }
2282
2283 #[test]
2284 fn intersection() {
2285 struct Test {
2286 base: &'static str,
2287 a_suffix: &'static str,
2288 b_suffix: &'static str,
2289 }
2290
2291 let tests = [
2292 Test {
2293 base: "",
2294 a_suffix: "/",
2295 b_suffix: "/a/b/c",
2296 },
2297 Test {
2298 base: "",
2299 a_suffix: "",
2300 b_suffix: "",
2301 },
2302 Test {
2303 base: "/a",
2304 a_suffix: "/",
2305 b_suffix: "/suffix",
2306 },
2307 Test {
2308 base: "/a",
2309 a_suffix: "/suffix",
2310 b_suffix: "",
2311 },
2312 Test {
2313 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}묁",
2314 a_suffix: "/Y\u{2064}",
2315 b_suffix: "",
2316 }
2317 ];
2318
2319 for Test {
2320 base,
2321 a_suffix,
2322 b_suffix,
2323 } in tests
2324 {
2325 let base = PointerBuf::parse(base).expect(&format!("failed to parse ${base}"));
2326 let mut a = base.clone();
2327 let mut b = base.clone();
2328 a.append(PointerBuf::parse(a_suffix).unwrap());
2329 b.append(PointerBuf::parse(b_suffix).unwrap());
2330 let intersection = a.intersection(&b);
2331 assert_eq!(intersection, base);
2332 }
2333 }
2334
2335 #[test]
2336 fn into_iter() {
2337 use core::iter::IntoIterator;
2338
2339 let ptr = PointerBuf::from_tokens(["foo", "bar", "baz"]);
2340 let tokens: Vec<Token> = ptr.into_iter().collect();
2341 let from_tokens = PointerBuf::from_tokens(tokens);
2342 assert_eq!(ptr, from_tokens);
2343
2344 let ptr = Pointer::from_static("/foo/bar/baz");
2345 let tokens: Vec<_> = ptr.into_iter().collect();
2346 assert_eq!(ptr, PointerBuf::from_tokens(tokens));
2347 }
2348
2349 #[test]
2350 fn from_str() {
2351 let p = PointerBuf::from_str("/foo/bar").unwrap();
2352 assert_eq!(p, "/foo/bar");
2353 }
2354
2355 #[test]
2356 fn from_token() {
2357 let p = PointerBuf::from(Token::new("foo"));
2358 assert_eq!(p, "/foo");
2359 }
2360
2361 #[test]
2362 fn from_usize() {
2363 let p = PointerBuf::from(0);
2364 assert_eq!(p, "/0");
2365 }
2366
2367 #[test]
2368 fn borrow() {
2369 let ptr = PointerBuf::from_tokens(["foo", "bar"]);
2370 let borrowed: &Pointer = ptr.borrow();
2371 assert_eq!(borrowed, "/foo/bar");
2372 }
2373
2374 #[test]
2375 fn from_box_to_buf() {
2376 let subjectal = PointerBuf::parse("/foo/bar/0").unwrap();
2377 let boxed: Box<Pointer> = subjectal.clone().into();
2378 let unboxed = boxed.into_buf();
2379 assert_eq!(subjectal, unboxed);
2380 }
2381
2382 #[test]
2383 fn default_lifetime_is_correct() {
2384 #[allow(clippy::unnecessary_literal_unwrap)]
2388 fn or_default(ptr: &Pointer) -> &Pointer {
2389 Some(ptr).unwrap_or_default()
2390 }
2391 or_default(Pointer::root());
2393 }
2394}