1use crate::{token::InvalidEncodingError, Components, Token, Tokens};
2use alloc::{
3 borrow::ToOwned,
4 fmt,
5 string::{String, ToString},
6 vec::Vec,
7};
8use core::{borrow::Borrow, cmp::Ordering, ops::Deref, str::FromStr};
9
10#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
37#[cfg_attr(not(doc), repr(transparent))]
39pub struct Pointer(str);
40
41impl Default for &'static Pointer {
42 fn default() -> Self {
43 Pointer::root()
44 }
45}
46impl core::fmt::Display for Pointer {
47 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
48 self.0.fmt(f)
49 }
50}
51impl Pointer {
52 fn new<S: AsRef<str> + ?Sized>(s: &S) -> &Self {
56 unsafe { &*(core::ptr::from_ref::<str>(s.as_ref()) as *const Self) }
57 }
58
59 pub const fn root() -> &'static Self {
61 #[allow(clippy::ref_as_ptr)]
63 unsafe {
64 &*("" as *const str as *const Self)
65 }
66 }
67
68 pub fn parse<S: AsRef<str> + ?Sized>(s: &S) -> Result<&Self, ParseError> {
75 validate(s.as_ref()).map(Self::new)
76 }
77
78 pub const fn from_static(s: &'static str) -> &'static Self {
96 assert!(validate(s).is_ok(), "invalid json pointer");
97 unsafe { &*(core::ptr::from_ref::<str>(s) as *const Self) }
98 }
99
100 pub fn as_str(&self) -> &str {
102 &self.0
103 }
104
105 pub fn to_buf(&self) -> PointerBuf {
107 PointerBuf(self.0.to_string())
108 }
109
110 pub fn tokens(&self) -> Tokens {
112 let mut s = self.0.split('/');
113 s.next();
115 Tokens::new(s)
116 }
117
118 pub fn count(&self) -> usize {
120 self.tokens().count()
121 }
122
123 pub fn is_root(&self) -> bool {
125 self.0.is_empty()
126 }
127
128 #[cfg(feature = "json")]
130 pub fn to_json_value(&self) -> serde_json::Value {
131 serde_json::Value::String(self.0.to_string())
132 }
133
134 pub fn back(&self) -> Option<Token> {
136 self.0
137 .rsplit_once('/')
138 .map(|(_, back)| Token::from_encoded_unchecked(back))
139 }
140
141 pub fn last(&self) -> Option<Token> {
145 self.back()
146 }
147
148 pub fn front(&self) -> Option<Token> {
150 if self.is_root() {
151 return None;
152 }
153 self.0[1..]
154 .split_once('/')
155 .map_or_else(
156 || Token::from_encoded_unchecked(&self.0[1..]),
157 |(front, _)| Token::from_encoded_unchecked(front),
158 )
159 .into()
160 }
161
162 pub fn first(&self) -> Option<Token> {
166 self.front()
167 }
168
169 pub fn split_front(&self) -> Option<(Token, &Self)> {
171 if self.is_root() {
172 return None;
173 }
174 self.0[1..]
175 .find('/')
176 .map_or_else(
177 || (Token::from_encoded_unchecked(&self.0[1..]), Self::root()),
178 |idx| {
179 let (front, back) = self.0[1..].split_at(idx);
180 (Token::from_encoded_unchecked(front), Self::new(back))
181 },
182 )
183 .into()
184 }
185 pub fn split_at(&self, offset: usize) -> Option<(&Self, &Self)> {
208 if self.0.as_bytes().get(offset).copied() != Some(b'/') {
209 return None;
210 }
211 let (head, tail) = self.0.split_at(offset);
212 Some((Self::new(head), Self::new(tail)))
213 }
214
215 pub fn split_back(&self) -> Option<(&Self, Token)> {
217 self.0
218 .rsplit_once('/')
219 .map(|(front, back)| (Self::new(front), Token::from_encoded_unchecked(back)))
220 }
221
222 pub fn parent(&self) -> Option<&Self> {
224 self.0.rsplit_once('/').map(|(front, _)| Self::new(front))
225 }
226
227 pub fn strip_suffix<'a>(&'a self, suffix: &Self) -> Option<&'a Self> {
229 self.0.strip_suffix(&suffix.0).map(Self::new)
230 }
231
232 pub fn strip_prefix<'a>(&'a self, prefix: &Self) -> Option<&'a Self> {
234 self.0.strip_prefix(&prefix.0).map(Self::new)
235 }
236 pub fn get(&self, index: usize) -> Option<Token> {
252 self.tokens().nth(index).clone()
253 }
254
255 #[cfg(feature = "resolve")]
276 pub fn resolve<'v, R: crate::Resolve>(&self, value: &'v R) -> Result<&'v R::Value, R::Error> {
277 value.resolve(self)
278 }
279
280 #[cfg(feature = "resolve")]
304 pub fn resolve_mut<'v, R: crate::ResolveMut>(
305 &self,
306 value: &'v mut R,
307 ) -> Result<&'v mut R::Value, R::Error> {
308 value.resolve_mut(self)
309 }
310
311 pub fn intersection<'a>(&'a self, other: &Self) -> &'a Self {
313 if self.is_root() || other.is_root() {
314 return Self::root();
315 }
316 let mut idx = 0;
317 for (a, b) in self.tokens().zip(other.tokens()) {
318 if a != b {
319 break;
320 }
321 idx += a.encoded().len() + 1;
322 }
323 self.split_at(idx).map_or(self, |(head, _)| head)
324 }
325
326 #[cfg(feature = "delete")]
373 pub fn delete<D: crate::Delete>(&self, value: &mut D) -> Option<D::Value> {
374 value.delete(self)
375 }
376
377 #[cfg(feature = "assign")]
400 pub fn assign<D, V>(&self, dest: &mut D, src: V) -> Result<Option<D::Value>, D::Error>
401 where
402 D: crate::Assign,
403 V: Into<D::Value>,
404 {
405 dest.assign(self, src)
406 }
407
408 pub fn components(&self) -> Components {
423 self.into()
424 }
425
426 pub fn with_trailing_token<'t>(&self, token: impl Into<Token<'t>>) -> PointerBuf {
441 let mut buf = self.to_buf();
442 buf.push_back(token.into());
443 buf
444 }
445
446 pub fn with_leading_token<'t>(&self, token: impl Into<Token<'t>>) -> PointerBuf {
461 let mut buf = self.to_buf();
462 buf.push_front(token);
463 buf
464 }
465
466 pub fn concat(&self, other: &Pointer) -> PointerBuf {
482 let mut buf = self.to_buf();
483 buf.append(other);
484 buf
485 }
486
487 pub fn len(&self) -> usize {
502 self.0.len()
503 }
504
505 pub fn is_empty(&self) -> bool {
516 self.0.is_empty()
517 }
518}
519
520#[cfg(feature = "serde")]
521impl serde::Serialize for Pointer {
522 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
523 where
524 S: serde::Serializer,
525 {
526 <str>::serialize(&self.0, serializer)
527 }
528}
529
530#[cfg(feature = "serde")]
531impl<'de: 'p, 'p> serde::Deserialize<'de> for &'p Pointer {
532 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
533 where
534 D: serde::Deserializer<'de>,
535 {
536 use serde::de::{Error, Visitor};
537
538 struct PointerVisitor;
539
540 impl<'a> Visitor<'a> for PointerVisitor {
541 type Value = &'a Pointer;
542
543 fn expecting(&self, formatter: &mut core::fmt::Formatter) -> core::fmt::Result {
544 formatter.write_str("a borrowed Pointer")
545 }
546
547 fn visit_borrowed_str<E>(self, v: &'a str) -> Result<Self::Value, E>
548 where
549 E: Error,
550 {
551 Pointer::parse(v).map_err(|err| {
552 Error::custom(format!("failed to parse json pointer\n\ncaused by:\n{err}"))
553 })
554 }
555 }
556
557 deserializer.deserialize_str(PointerVisitor)
558 }
559}
560
561impl ToOwned for Pointer {
562 type Owned = PointerBuf;
563
564 fn to_owned(&self) -> Self::Owned {
565 self.to_buf()
566 }
567}
568
569impl PartialEq<&str> for Pointer {
570 fn eq(&self, other: &&str) -> bool {
571 &&self.0 == other
572 }
573}
574impl<'p> PartialEq<String> for &'p Pointer {
575 fn eq(&self, other: &String) -> bool {
576 self.0.eq(other)
577 }
578}
579impl PartialEq<str> for Pointer {
580 fn eq(&self, other: &str) -> bool {
581 &self.0 == other
582 }
583}
584
585impl PartialEq<Pointer> for &str {
586 fn eq(&self, other: &Pointer) -> bool {
587 *self == (&other.0)
588 }
589}
590
591impl PartialEq<Pointer> for String {
592 fn eq(&self, other: &Pointer) -> bool {
593 self == &other.0
594 }
595}
596
597impl PartialEq<Pointer> for str {
598 fn eq(&self, other: &Pointer) -> bool {
599 self == &other.0
600 }
601}
602
603impl PartialEq<String> for Pointer {
604 fn eq(&self, other: &String) -> bool {
605 &self.0 == other
606 }
607}
608
609impl PartialEq<PointerBuf> for Pointer {
610 fn eq(&self, other: &PointerBuf) -> bool {
611 self.0 == other.0
612 }
613}
614
615impl PartialEq<Pointer> for PointerBuf {
616 fn eq(&self, other: &Pointer) -> bool {
617 self.0 == other.0
618 }
619}
620impl PartialEq<PointerBuf> for String {
621 fn eq(&self, other: &PointerBuf) -> bool {
622 self == &other.0
623 }
624}
625impl PartialEq<String> for PointerBuf {
626 fn eq(&self, other: &String) -> bool {
627 &self.0 == other
628 }
629}
630
631impl PartialEq<PointerBuf> for str {
632 fn eq(&self, other: &PointerBuf) -> bool {
633 self == other.0
634 }
635}
636impl PartialEq<PointerBuf> for &str {
637 fn eq(&self, other: &PointerBuf) -> bool {
638 *self == other.0
639 }
640}
641
642impl AsRef<Pointer> for Pointer {
643 fn as_ref(&self) -> &Pointer {
644 self
645 }
646}
647impl AsRef<Pointer> for PointerBuf {
648 fn as_ref(&self) -> &Pointer {
649 self
650 }
651}
652
653impl PartialEq<PointerBuf> for &Pointer {
654 fn eq(&self, other: &PointerBuf) -> bool {
655 self.0 == other.0
656 }
657}
658
659impl PartialEq<&Pointer> for PointerBuf {
660 fn eq(&self, other: &&Pointer) -> bool {
661 self.0 == other.0
662 }
663}
664
665#[cfg(feature = "json")]
666impl From<&Pointer> for serde_json::Value {
667 fn from(ptr: &Pointer) -> Self {
668 ptr.to_json_value()
669 }
670}
671
672impl AsRef<str> for Pointer {
673 fn as_ref(&self) -> &str {
674 &self.0
675 }
676}
677
678impl Borrow<str> for Pointer {
679 fn borrow(&self) -> &str {
680 &self.0
681 }
682}
683
684impl AsRef<[u8]> for Pointer {
685 fn as_ref(&self) -> &[u8] {
686 self.0.as_bytes()
687 }
688}
689
690impl PartialOrd<PointerBuf> for Pointer {
691 fn partial_cmp(&self, other: &PointerBuf) -> Option<Ordering> {
692 self.0.partial_cmp(other.0.as_str())
693 }
694}
695
696impl PartialOrd<Pointer> for PointerBuf {
697 fn partial_cmp(&self, other: &Pointer) -> Option<Ordering> {
698 self.0.as_str().partial_cmp(&other.0)
699 }
700}
701impl PartialOrd<&Pointer> for PointerBuf {
702 fn partial_cmp(&self, other: &&Pointer) -> Option<Ordering> {
703 self.0.as_str().partial_cmp(&other.0)
704 }
705}
706
707impl PartialOrd<Pointer> for String {
708 fn partial_cmp(&self, other: &Pointer) -> Option<Ordering> {
709 self.as_str().partial_cmp(&other.0)
710 }
711}
712impl PartialOrd<String> for &Pointer {
713 fn partial_cmp(&self, other: &String) -> Option<Ordering> {
714 self.0.partial_cmp(other.as_str())
715 }
716}
717
718impl PartialOrd<PointerBuf> for String {
719 fn partial_cmp(&self, other: &PointerBuf) -> Option<Ordering> {
720 self.as_str().partial_cmp(other.0.as_str())
721 }
722}
723
724impl PartialOrd<Pointer> for str {
725 fn partial_cmp(&self, other: &Pointer) -> Option<Ordering> {
726 self.partial_cmp(&other.0)
727 }
728}
729
730impl PartialOrd<PointerBuf> for str {
731 fn partial_cmp(&self, other: &PointerBuf) -> Option<Ordering> {
732 self.partial_cmp(other.0.as_str())
733 }
734}
735impl PartialOrd<PointerBuf> for &str {
736 fn partial_cmp(&self, other: &PointerBuf) -> Option<Ordering> {
737 (*self).partial_cmp(other.0.as_str())
738 }
739}
740impl PartialOrd<Pointer> for &str {
741 fn partial_cmp(&self, other: &Pointer) -> Option<Ordering> {
742 (*self).partial_cmp(&other.0)
743 }
744}
745
746impl PartialOrd<&str> for &Pointer {
747 fn partial_cmp(&self, other: &&str) -> Option<Ordering> {
748 PartialOrd::partial_cmp(&self.0[..], &other[..])
749 }
750}
751
752impl PartialOrd<String> for Pointer {
753 fn partial_cmp(&self, other: &String) -> Option<Ordering> {
754 self.0.partial_cmp(other.as_str())
755 }
756}
757
758impl PartialOrd<&str> for PointerBuf {
759 fn partial_cmp(&self, other: &&str) -> Option<Ordering> {
760 PartialOrd::partial_cmp(&self.0[..], &other[..])
761 }
762}
763
764impl<'p> PartialOrd<PointerBuf> for &'p Pointer {
765 fn partial_cmp(&self, other: &PointerBuf) -> Option<Ordering> {
766 self.0.partial_cmp(other.0.as_str())
767 }
768}
769
770impl PartialOrd<String> for PointerBuf {
771 fn partial_cmp(&self, other: &String) -> Option<Ordering> {
772 self.0.partial_cmp(other)
773 }
774}
775
776impl<'a> IntoIterator for &'a Pointer {
777 type Item = Token<'a>;
778 type IntoIter = Tokens<'a>;
779 fn into_iter(self) -> Self::IntoIter {
780 self.tokens()
781 }
782}
783
784#[derive(Clone, Default, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
801pub struct PointerBuf(String);
802
803impl PointerBuf {
804 pub fn new() -> Self {
806 Self(String::new())
807 }
808
809 pub fn parse<S: AsRef<str> + ?Sized>(s: &S) -> Result<Self, ParseError> {
814 Pointer::parse(&s).map(Pointer::to_buf)
815 }
816
817 pub fn from_tokens<'a, T>(tokens: impl IntoIterator<Item = T>) -> Self
819 where
820 T: Into<Token<'a>>,
821 {
822 let mut inner = String::new();
823 for t in tokens.into_iter().map(Into::into) {
824 inner.push('/');
825 inner.push_str(t.encoded());
826 }
827 PointerBuf(inner)
828 }
829
830 pub fn as_ptr(&self) -> &Pointer {
832 self
833 }
834
835 pub fn push_front<'t>(&mut self, token: impl Into<Token<'t>>) {
837 self.0.insert(0, '/');
838 self.0.insert_str(1, token.into().encoded());
839 }
840
841 pub fn push_back<'t>(&mut self, token: impl Into<Token<'t>>) {
843 self.0.push('/');
844 self.0.push_str(token.into().encoded());
845 }
846
847 pub fn pop_back(&mut self) -> Option<Token<'static>> {
849 if let Some(idx) = self.0.rfind('/') {
850 let back = Token::from_encoded_unchecked(self.0.split_off(idx + 1));
851 self.0.pop(); Some(back)
853 } else {
854 None
855 }
856 }
857
858 pub fn pop_front(&mut self) -> Option<Token<'static>> {
860 (!self.is_root()).then(|| {
861 let mut token = if let Some(idx) = self.0[1..].find('/') {
863 let token = self.0.split_off(idx + 1);
864 core::mem::replace(&mut self.0, token)
865 } else {
866 core::mem::take(&mut self.0)
867 };
868 token.remove(0); Token::from_encoded_unchecked(token)
870 })
871 }
872
873 pub fn append<P: AsRef<Pointer>>(&mut self, other: P) -> &PointerBuf {
875 let other = other.as_ref();
876 if self.is_root() {
877 self.0 = other.0.to_string();
878 } else if !other.is_root() {
879 self.0.push_str(&other.0);
880 }
881 self
882 }
883
884 pub fn replace<'t>(
890 &mut self,
891 index: usize,
892 token: impl Into<Token<'t>>,
893 ) -> Result<Option<Token>, ReplaceError> {
894 if self.is_root() {
895 return Err(ReplaceError {
896 count: self.count(),
897 index,
898 });
899 }
900 let mut tokens = self.tokens().collect::<Vec<_>>();
901 if index >= tokens.len() {
902 return Err(ReplaceError {
903 count: tokens.len(),
904 index,
905 });
906 }
907 let old = tokens.get(index).map(super::token::Token::to_owned);
908 tokens[index] = token.into();
909
910 let mut buf = String::new();
911 for token in tokens {
912 buf.push('/');
913 buf.push_str(token.encoded());
914 }
915 self.0 = buf;
916
917 Ok(old)
918 }
919
920 pub fn clear(&mut self) {
922 self.0.clear();
923 }
924}
925
926impl FromStr for PointerBuf {
927 type Err = ParseError;
928 fn from_str(s: &str) -> Result<Self, Self::Err> {
929 Self::try_from(s)
930 }
931}
932
933impl Borrow<Pointer> for PointerBuf {
934 fn borrow(&self) -> &Pointer {
935 self.as_ptr()
936 }
937}
938
939impl Deref for PointerBuf {
940 type Target = Pointer;
941 fn deref(&self) -> &Self::Target {
942 Pointer::new(&self.0)
943 }
944}
945
946#[cfg(feature = "serde")]
947impl<'de> serde::Deserialize<'de> for PointerBuf {
948 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
949 where
950 D: serde::Deserializer<'de>,
951 {
952 use serde::de::Error;
953 let s = String::deserialize(deserializer)?;
954 PointerBuf::try_from(s).map_err(D::Error::custom)
955 }
956}
957
958#[cfg(feature = "serde")]
959impl serde::Serialize for PointerBuf {
960 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
961 where
962 S: serde::Serializer,
963 {
964 String::serialize(&self.0, serializer)
965 }
966}
967
968impl From<Token<'_>> for PointerBuf {
969 fn from(t: Token) -> Self {
970 PointerBuf::from_tokens([t])
971 }
972}
973
974impl TryFrom<String> for PointerBuf {
975 type Error = ParseError;
976 fn try_from(value: String) -> Result<Self, Self::Error> {
977 let _ = validate(&value)?;
978 Ok(Self(value))
979 }
980}
981
982impl From<usize> for PointerBuf {
983 fn from(value: usize) -> Self {
984 PointerBuf::from_tokens([value])
985 }
986}
987
988impl<'a> IntoIterator for &'a PointerBuf {
989 type Item = Token<'a>;
990 type IntoIter = Tokens<'a>;
991 fn into_iter(self) -> Self::IntoIter {
992 self.tokens()
993 }
994}
995
996impl TryFrom<&str> for PointerBuf {
997 type Error = ParseError;
998 fn try_from(value: &str) -> Result<Self, Self::Error> {
999 Pointer::parse(value).map(Pointer::to_buf)
1000 }
1001}
1002
1003impl PartialEq<&str> for PointerBuf {
1004 fn eq(&self, other: &&str) -> bool {
1005 &self.0 == other
1006 }
1007}
1008
1009impl PartialEq<str> for PointerBuf {
1010 fn eq(&self, other: &str) -> bool {
1011 self.0 == other
1012 }
1013}
1014
1015impl core::fmt::Display for PointerBuf {
1016 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
1017 self.0.fmt(f)
1018 }
1019}
1020
1021const fn validate(value: &str) -> Result<&str, ParseError> {
1022 if value.is_empty() {
1023 return Ok(value);
1024 }
1025 let bytes = value.as_bytes();
1026 if bytes[0] != b'/' {
1027 return Err(ParseError::NoLeadingBackslash);
1028 }
1029 let mut ptr_offset = 0; let mut tok_offset = 0; let bytes = value.as_bytes();
1033 let mut i = 0;
1034 while i < bytes.len() {
1035 match bytes[i] {
1036 b'/' => {
1037 ptr_offset = i;
1040 tok_offset = 0;
1042 }
1043 b'~' => {
1044 if i + 1 >= bytes.len() || (bytes[i + 1] != b'0' && bytes[i + 1] != b'1') {
1047 return Err(ParseError::InvalidEncoding {
1061 offset: ptr_offset,
1062 source: InvalidEncodingError { offset: tok_offset },
1063 });
1064 }
1065 i += 1;
1067 tok_offset += 1;
1070 }
1071 _ => {}
1072 }
1073 i += 1;
1074 tok_offset += 1;
1076 }
1077 Ok(value)
1078}
1079
1080#[derive(Debug, PartialEq)]
1092pub enum ParseError {
1093 NoLeadingBackslash,
1095
1096 InvalidEncoding {
1099 offset: usize,
1102 source: InvalidEncodingError,
1104 },
1105}
1106
1107impl fmt::Display for ParseError {
1108 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1109 match self {
1110 Self::NoLeadingBackslash { .. } => {
1111 write!(
1112 f,
1113 "json pointer is malformed as it does not start with a backslash ('/')"
1114 )
1115 }
1116 Self::InvalidEncoding { source, .. } => write!(f, "{source}"),
1117 }
1118 }
1119}
1120
1121impl ParseError {
1122 pub fn is_no_leading_backslash(&self) -> bool {
1124 matches!(self, Self::NoLeadingBackslash { .. })
1125 }
1126
1127 pub fn is_invalid_encoding(&self) -> bool {
1129 matches!(self, Self::InvalidEncoding { .. })
1130 }
1131
1132 pub fn pointer_offset(&self) -> usize {
1145 match *self {
1146 Self::NoLeadingBackslash { .. } => 0,
1147 Self::InvalidEncoding { offset, .. } => offset,
1148 }
1149 }
1150
1151 pub fn source_offset(&self) -> usize {
1165 match self {
1166 Self::NoLeadingBackslash { .. } => 0,
1167 Self::InvalidEncoding { source, .. } => source.offset,
1168 }
1169 }
1170
1171 pub fn complete_offset(&self) -> usize {
1183 self.source_offset() + self.pointer_offset()
1184 }
1185}
1186
1187#[cfg(feature = "std")]
1188impl std::error::Error for ParseError {
1189 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
1190 match self {
1191 Self::InvalidEncoding { source, .. } => Some(source),
1192 Self::NoLeadingBackslash => None,
1193 }
1194 }
1195}
1196
1197#[derive(Debug, PartialEq, Eq)]
1210pub struct ReplaceError {
1211 pub index: usize,
1213 pub count: usize,
1215}
1216
1217impl fmt::Display for ReplaceError {
1218 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1219 write!(f, "index {} is out of bounds ({})", self.index, self.count)
1220 }
1221}
1222
1223#[cfg(feature = "std")]
1224impl std::error::Error for ReplaceError {}
1225
1226#[cfg(test)]
1237mod tests {
1238 use std::error::Error;
1239
1240 use super::*;
1241 use quickcheck::TestResult;
1242 use quickcheck_macros::quickcheck;
1243
1244 #[test]
1245 #[should_panic = "invalid json pointer"]
1246 fn from_const_validates() {
1247 let _ = Pointer::from_static("foo/bar");
1248 }
1249
1250 #[test]
1251 fn strip_suffix() {
1252 let p = Pointer::new("/example/pointer/to/some/value");
1253 let stripped = p.strip_suffix(Pointer::new("/to/some/value")).unwrap();
1254 assert_eq!(stripped, "/example/pointer");
1255 }
1256
1257 #[test]
1258 fn strip_prefix() {
1259 let p = Pointer::new("/example/pointer/to/some/value");
1260 let stripped = p.strip_prefix(Pointer::new("/example/pointer")).unwrap();
1261 assert_eq!(stripped, "/to/some/value");
1262 }
1263
1264 #[test]
1265 fn parse_error_is_no_leading_backslash() {
1266 let err = ParseError::NoLeadingBackslash;
1267 assert!(err.is_no_leading_backslash());
1268 assert!(!err.is_invalid_encoding());
1269 }
1270
1271 #[test]
1272 fn parse_error_is_invalid_encoding() {
1273 let err = ParseError::InvalidEncoding {
1274 offset: 0,
1275 source: InvalidEncodingError { offset: 1 },
1276 };
1277 assert!(!err.is_no_leading_backslash());
1278 assert!(err.is_invalid_encoding());
1279 }
1280
1281 #[test]
1282 fn parse() {
1283 let tests = [
1284 ("", Ok("")),
1285 ("/", Ok("/")),
1286 ("/foo", Ok("/foo")),
1287 ("/foo/bar", Ok("/foo/bar")),
1288 ("/foo/bar/baz", Ok("/foo/bar/baz")),
1289 ("/foo/bar/baz/~0", Ok("/foo/bar/baz/~0")),
1290 ("/foo/bar/baz/~1", Ok("/foo/bar/baz/~1")),
1291 ("/foo/bar/baz/~01", Ok("/foo/bar/baz/~01")),
1292 ("/foo/bar/baz/~10", Ok("/foo/bar/baz/~10")),
1293 ("/foo/bar/baz/~11", Ok("/foo/bar/baz/~11")),
1294 ("/foo/bar/baz/~1/~0", Ok("/foo/bar/baz/~1/~0")),
1295 ("missing-slash", Err(ParseError::NoLeadingBackslash)),
1296 (
1297 "/~",
1298 Err(ParseError::InvalidEncoding {
1299 offset: 0,
1300 source: InvalidEncodingError { offset: 1 },
1301 }),
1302 ),
1303 (
1304 "/~2",
1305 Err(ParseError::InvalidEncoding {
1306 offset: 0,
1307 source: InvalidEncodingError { offset: 1 },
1308 }),
1309 ),
1310 (
1311 "/~a",
1312 Err(ParseError::InvalidEncoding {
1313 offset: 0,
1314 source: InvalidEncodingError { offset: 1 },
1315 }),
1316 ),
1317 ];
1318 for (input, expected) in tests {
1319 let actual = Pointer::parse(input).map(Pointer::as_str);
1320 assert_eq!(actual, expected);
1321 }
1322 }
1323
1324 #[test]
1325 fn parse_error_offsets() {
1326 let err = Pointer::parse("/foo/invalid~encoding").unwrap_err();
1327 assert_eq!(err.pointer_offset(), 4);
1328 assert_eq!(err.source_offset(), 8);
1329 assert_eq!(err.complete_offset(), 12);
1330
1331 let err = Pointer::parse("invalid~encoding").unwrap_err();
1332 assert_eq!(err.pointer_offset(), 0);
1333 assert_eq!(err.source_offset(), 0);
1334
1335 let err = Pointer::parse("no-leading/slash").unwrap_err();
1336 assert!(err.source().is_none());
1337 }
1338
1339 #[test]
1340 #[cfg(feature = "std")]
1341 fn parse_error_source() {
1342 use std::error::Error;
1343 let err = Pointer::parse("/foo/invalid~encoding").unwrap_err();
1344 assert!(err.source().is_some());
1345 let source = err.source().unwrap();
1346 assert!(source.is::<InvalidEncodingError>());
1347
1348 let err = Pointer::parse("no-leading/slash").unwrap_err();
1349 assert!(err.source().is_none());
1350 }
1351
1352 #[test]
1353 fn pointerbuf_as_pointer_returns_pointer() {
1354 let ptr = PointerBuf::parse("/foo/bar").unwrap();
1355 assert_eq!(ptr.as_ptr(), ptr);
1356 }
1357
1358 #[test]
1359 fn pointer_buf_clear() {
1360 let mut ptr = PointerBuf::from_tokens(["foo", "bar"]);
1361 ptr.clear();
1362 assert_eq!(ptr, "");
1363 }
1364
1365 #[test]
1366 fn push_pop_back() {
1367 let mut ptr = PointerBuf::default();
1368 assert_eq!(ptr, "", "default, root pointer should equal \"\"");
1369 assert_eq!(ptr.count(), 0, "default pointer should have 0 tokens");
1370
1371 ptr.push_back("foo");
1372 assert_eq!(ptr, "/foo", "pointer should equal \"/foo\" after push_back");
1373
1374 ptr.push_back("bar");
1375 assert_eq!(ptr, "/foo/bar");
1376 ptr.push_back("/baz");
1377 assert_eq!(ptr, "/foo/bar/~1baz");
1378
1379 let mut ptr = PointerBuf::from_tokens(["foo", "bar"]);
1380 assert_eq!(ptr.pop_back(), Some("bar".into()));
1381 assert_eq!(ptr, "/foo", "pointer should equal \"/foo\" after pop_back");
1382 assert_eq!(ptr.pop_back(), Some("foo".into()));
1383 assert_eq!(ptr, "", "pointer should equal \"\" after pop_back");
1384 }
1385
1386 #[test]
1387 fn replace_token() {
1388 let mut ptr = PointerBuf::try_from("/test/token").unwrap();
1389
1390 let res = ptr.replace(0, "new");
1391 assert!(res.is_ok());
1392 assert_eq!(ptr, "/new/token");
1393
1394 let res = ptr.replace(3, "invalid");
1395
1396 assert!(res.is_err());
1397 }
1398
1399 #[test]
1400 fn push_pop_front() {
1401 let mut ptr = PointerBuf::default();
1402 assert_eq!(ptr, "");
1403 assert_eq!(ptr.count(), 0);
1404 ptr.push_front("bar");
1405 assert_eq!(ptr, "/bar");
1406 assert_eq!(ptr.count(), 1);
1407
1408 ptr.push_front("foo");
1409 assert_eq!(ptr, "/foo/bar");
1410 assert_eq!(ptr.count(), 2);
1411
1412 ptr.push_front("too");
1413 assert_eq!(ptr, "/too/foo/bar");
1414 assert_eq!(ptr.count(), 3);
1415
1416 assert_eq!(ptr.pop_front(), Some("too".into()));
1417 assert_eq!(ptr, "/foo/bar");
1418 assert_eq!(ptr.count(), 2);
1419
1420 assert_eq!(ptr.pop_back(), Some("bar".into()));
1421 assert_eq!(ptr, "/foo");
1422 assert_eq!(ptr.count(), 1);
1423 assert_eq!(ptr.pop_front(), Some("foo".into()));
1424 assert_eq!(ptr, "");
1425 }
1426
1427 #[test]
1428 fn display_replace_token_error() {
1429 let err = ReplaceError { index: 3, count: 2 };
1430 assert_eq!(format!("{err}"), "index 3 is out of bounds (2)");
1431 }
1432
1433 #[test]
1434 fn pop_front_works_with_empty_strings() {
1435 {
1436 let mut ptr = PointerBuf::from_tokens(["bar", "", ""]);
1437
1438 assert_eq!(ptr.tokens().count(), 3);
1439 let mut token = ptr.pop_front();
1440 assert_eq!(token, Some(Token::from_encoded_unchecked("bar")));
1441 assert_eq!(ptr.tokens().count(), 2);
1442 token = ptr.pop_front();
1443 assert_eq!(token, Some(Token::from_encoded_unchecked("")));
1444 assert_eq!(ptr.tokens().count(), 1);
1445 token = ptr.pop_front();
1446 assert_eq!(token, Some(Token::from_encoded_unchecked("")));
1447 assert_eq!(ptr.tokens().count(), 0);
1448 assert_eq!(ptr, Pointer::root());
1449 }
1450 {
1451 let mut ptr = PointerBuf::new();
1452 assert_eq!(ptr.tokens().count(), 0);
1453 ptr.push_back("");
1454 assert_eq!(ptr.tokens().count(), 1);
1455 ptr.pop_back();
1456 assert_eq!(ptr.tokens().count(), 0);
1457 }
1458 {
1459 let mut ptr = PointerBuf::new();
1460 let input = ["", "", "", "foo", "", "bar", "baz", ""];
1461 for (idx, &s) in input.iter().enumerate() {
1462 assert_eq!(ptr.tokens().count(), idx);
1463 ptr.push_back(s);
1464 }
1465 assert_eq!(ptr.tokens().count(), input.len());
1466 for (idx, s) in input.iter().enumerate() {
1467 assert_eq!(ptr.tokens().count(), 8 - idx);
1468 assert_eq!(ptr.front().unwrap().decoded(), *s);
1469 assert_eq!(ptr.pop_front().unwrap().decoded(), *s);
1470 }
1471 assert_eq!(ptr.tokens().count(), 0);
1472 assert!(ptr.front().is_none());
1473 assert!(ptr.pop_front().is_none());
1474 }
1475 }
1476
1477 #[test]
1478 fn formatting() {
1479 assert_eq!(PointerBuf::from_tokens(["foo", "bar"]), "/foo/bar");
1480 assert_eq!(
1481 PointerBuf::from_tokens(["~/foo", "~bar", "/baz"]),
1482 "/~0~1foo/~0bar/~1baz"
1483 );
1484 assert_eq!(PointerBuf::from_tokens(["field", "", "baz"]), "/field//baz");
1485 assert_eq!(PointerBuf::default(), "");
1486
1487 let ptr = PointerBuf::from_tokens(["foo", "bar", "baz"]);
1488 assert_eq!(ptr.to_string(), "/foo/bar/baz");
1489 }
1490
1491 #[test]
1492 fn last() {
1493 let ptr = Pointer::from_static("/foo/bar");
1494
1495 assert_eq!(ptr.last(), Some("bar".into()));
1496
1497 let ptr = Pointer::from_static("/foo/bar/-");
1498 assert_eq!(ptr.last(), Some("-".into()));
1499
1500 let ptr = Pointer::from_static("/-");
1501 assert_eq!(ptr.last(), Some("-".into()));
1502
1503 let ptr = Pointer::root();
1504 assert_eq!(ptr.last(), None);
1505
1506 let ptr = Pointer::from_static("/bar");
1507 assert_eq!(ptr.last(), Some("bar".into()));
1508 }
1509
1510 #[test]
1511 fn first() {
1512 let ptr = Pointer::from_static("/foo/bar");
1513 assert_eq!(ptr.first(), Some("foo".into()));
1514
1515 let ptr = Pointer::from_static("/foo/bar/-");
1516 assert_eq!(ptr.first(), Some("foo".into()));
1517
1518 let ptr = Pointer::root();
1519 assert_eq!(ptr.first(), None);
1520 }
1521
1522 #[test]
1523 fn pointerbuf_try_from() {
1524 let ptr = PointerBuf::from_tokens(["foo", "bar", "~/"]);
1525
1526 assert_eq!(PointerBuf::try_from("/foo/bar/~0~1").unwrap(), ptr);
1527 let into: PointerBuf = "/foo/bar/~0~1".try_into().unwrap();
1528 assert_eq!(ptr, into);
1529 }
1530
1531 #[test]
1532 fn default() {
1533 let ptr = PointerBuf::default();
1534 assert_eq!(ptr, "");
1535 assert_eq!(ptr.count(), 0);
1536
1537 let ptr = <&Pointer>::default();
1538 assert_eq!(ptr, "");
1539 }
1540
1541 #[test]
1542 #[cfg(all(feature = "serde", feature = "json"))]
1543 fn to_json_value() {
1544 use serde_json::Value;
1545 let ptr = Pointer::from_static("/foo/bar");
1546 assert_eq!(ptr.to_json_value(), Value::String(String::from("/foo/bar")));
1547 }
1548
1549 #[cfg(all(feature = "resolve", feature = "json"))]
1550 #[test]
1551 fn resolve() {
1552 use serde_json::json;
1554 let value = json!({
1555 "foo": {
1556 "bar": {
1557 "baz": "qux"
1558 }
1559 }
1560 });
1561 let ptr = Pointer::from_static("/foo/bar/baz");
1562 let resolved = ptr.resolve(&value).unwrap();
1563 assert_eq!(resolved, &json!("qux"));
1564 }
1565
1566 #[cfg(all(feature = "delete", feature = "json"))]
1567 #[test]
1568 fn delete() {
1569 use serde_json::json;
1570 let mut value = json!({
1571 "foo": {
1572 "bar": {
1573 "baz": "qux"
1574 }
1575 }
1576 });
1577 let ptr = Pointer::from_static("/foo/bar/baz");
1578 let deleted = ptr.delete(&mut value).unwrap();
1579 assert_eq!(deleted, json!("qux"));
1580 assert_eq!(
1581 value,
1582 json!({
1583 "foo": {
1584 "bar": {}
1585 }
1586 })
1587 );
1588 }
1589
1590 #[cfg(all(feature = "assign", feature = "json"))]
1591 #[test]
1592 fn assign() {
1593 use serde_json::json;
1594 let mut value = json!({});
1595 let ptr = Pointer::from_static("/foo/bar");
1596 let replaced = ptr.assign(&mut value, json!("baz")).unwrap();
1597 assert_eq!(replaced, None);
1598 assert_eq!(
1599 value,
1600 json!({
1601 "foo": {
1602 "bar": "baz"
1603 }
1604 })
1605 );
1606 }
1607
1608 #[test]
1609 fn get() {
1610 let ptr = Pointer::from_static("/0/1/2/3/4/5/6/7/8/9");
1611 for i in 0..10 {
1612 assert_eq!(ptr.get(i).unwrap().decoded(), i.to_string());
1613 }
1614 }
1615
1616 #[test]
1617 fn replace_token_success() {
1618 let mut ptr = PointerBuf::from_tokens(["foo", "bar", "baz"]);
1619 assert!(ptr.replace(1, "qux").is_ok());
1620 assert_eq!(ptr, PointerBuf::from_tokens(["foo", "qux", "baz"]));
1621
1622 assert!(ptr.replace(0, "corge").is_ok());
1623 assert_eq!(ptr, PointerBuf::from_tokens(["corge", "qux", "baz"]));
1624
1625 assert!(ptr.replace(2, "quux").is_ok());
1626 assert_eq!(ptr, PointerBuf::from_tokens(["corge", "qux", "quux"]));
1627 }
1628
1629 #[test]
1630 fn replace_token_out_of_bounds() {
1631 let mut ptr = PointerBuf::from_tokens(["foo", "bar"]);
1632 assert!(ptr.replace(2, "baz").is_err());
1633 assert_eq!(ptr, PointerBuf::from_tokens(["foo", "bar"])); }
1635
1636 #[test]
1637 fn replace_token_with_empty_string() {
1638 let mut ptr = PointerBuf::from_tokens(["foo", "bar", "baz"]);
1639 assert!(ptr.replace(1, "").is_ok());
1640 assert_eq!(ptr, PointerBuf::from_tokens(["foo", "", "baz"]));
1641 }
1642
1643 #[test]
1644 fn replace_token_in_empty_pointer() {
1645 let mut ptr = PointerBuf::default();
1646 assert!(ptr.replace(0, "foo").is_err());
1647 assert_eq!(ptr, PointerBuf::default()); }
1649
1650 #[test]
1651 fn pop_back_works_with_empty_strings() {
1652 {
1653 let mut ptr = PointerBuf::new();
1654 ptr.push_back("");
1655 ptr.push_back("");
1656 ptr.push_back("bar");
1657
1658 assert_eq!(ptr.tokens().count(), 3);
1659 ptr.pop_back();
1660 assert_eq!(ptr.tokens().count(), 2);
1661 ptr.pop_back();
1662 assert_eq!(ptr.tokens().count(), 1);
1663 ptr.pop_back();
1664 assert_eq!(ptr.tokens().count(), 0);
1665 assert_eq!(ptr, PointerBuf::new());
1666 }
1667 {
1668 let mut ptr = PointerBuf::new();
1669 assert_eq!(ptr.tokens().count(), 0);
1670 ptr.push_back("");
1671 assert_eq!(ptr.tokens().count(), 1);
1672 ptr.pop_back();
1673 assert_eq!(ptr.tokens().count(), 0);
1674 }
1675 {
1676 let mut ptr = PointerBuf::new();
1677 let input = ["", "", "", "foo", "", "bar", "baz", ""];
1678 for (idx, &s) in input.iter().enumerate() {
1679 assert_eq!(ptr.tokens().count(), idx);
1680 ptr.push_back(s);
1681 }
1682 assert_eq!(ptr.tokens().count(), input.len());
1683 for (idx, s) in input.iter().enumerate().rev() {
1684 assert_eq!(ptr.tokens().count(), idx + 1);
1685 assert_eq!(ptr.back().unwrap().decoded(), *s);
1686 assert_eq!(ptr.pop_back().unwrap().decoded(), *s);
1687 }
1688 assert_eq!(ptr.tokens().count(), 0);
1689 assert!(ptr.back().is_none());
1690 assert!(ptr.pop_back().is_none());
1691 }
1692 }
1693
1694 #[test]
1695 #[allow(clippy::useless_asref)]
1699 fn pointerbuf_as_ref_returns_pointer() {
1700 let ptr_str = "/foo/bar";
1701 let ptr = Pointer::from_static(ptr_str);
1702 let ptr_buf = ptr.to_buf();
1703 assert_eq!(ptr_buf.as_ref(), ptr);
1704 let r: &Pointer = ptr.as_ref();
1705 assert_eq!(ptr, r);
1706
1707 let s: &str = ptr.as_ref();
1708 assert_eq!(s, ptr_str);
1709
1710 let b: &[u8] = ptr.as_ref();
1711 assert_eq!(b, ptr_str.as_bytes());
1712 }
1713
1714 #[test]
1715 fn from_tokens() {
1716 let ptr = PointerBuf::from_tokens(["foo", "bar", "baz"]);
1717 assert_eq!(ptr, "/foo/bar/baz");
1718 }
1719
1720 #[test]
1721 fn pointer_borrow() {
1722 let ptr = Pointer::from_static("/foo/bar");
1723 let borrowed: &str = ptr.borrow();
1724 assert_eq!(borrowed, "/foo/bar");
1725 }
1726
1727 #[test]
1728 #[cfg(feature = "json")]
1729 fn into_value() {
1730 use serde_json::Value;
1731 let ptr = Pointer::from_static("/foo/bar");
1732 let value: Value = ptr.into();
1733 assert_eq!(value, Value::String("/foo/bar".to_string()));
1734 }
1735
1736 #[test]
1737 fn intersect() {
1738 let base = Pointer::from_static("/foo/bar");
1739 let a = Pointer::from_static("/foo/bar/qux");
1740 let b = Pointer::from_static("/foo/bar");
1741 assert_eq!(a.intersection(b), base);
1742
1743 let base = Pointer::from_static("");
1744 let a = Pointer::from_static("/foo");
1745 let b = Pointer::from_static("/");
1746 assert_eq!(a.intersection(b), base);
1747
1748 let base = Pointer::from_static("");
1749 let a = Pointer::from_static("/fooqux");
1750 let b = Pointer::from_static("/foobar");
1751 assert_eq!(a.intersection(b), base);
1752 }
1753
1754 #[quickcheck]
1755 fn qc_pop_and_push(mut ptr: PointerBuf) -> bool {
1756 let original_ptr = ptr.clone();
1757 let mut tokens = Vec::with_capacity(ptr.count());
1758 while let Some(token) = ptr.pop_back() {
1759 tokens.push(token);
1760 }
1761 if ptr.count() != 0 || !ptr.is_root() || ptr.last().is_some() || ptr.first().is_some() {
1762 return false;
1763 }
1764 for token in tokens.drain(..) {
1765 ptr.push_front(token);
1766 }
1767 if ptr != original_ptr {
1768 return false;
1769 }
1770 while let Some(token) = ptr.pop_front() {
1771 tokens.push(token);
1772 }
1773 if ptr.count() != 0 || !ptr.is_root() || ptr.last().is_some() || ptr.first().is_some() {
1774 return false;
1775 }
1776 for token in tokens {
1777 ptr.push_back(token);
1778 }
1779 ptr == original_ptr
1780 }
1781
1782 #[quickcheck]
1783 fn qc_split(ptr: PointerBuf) -> bool {
1784 if let Some((head, tail)) = ptr.split_front() {
1785 {
1786 let Some(first) = ptr.first() else {
1787 return false;
1788 };
1789 if first != head {
1790 return false;
1791 }
1792 }
1793 {
1794 let mut copy = ptr.clone();
1795 copy.pop_front();
1796 if copy != tail {
1797 return false;
1798 }
1799 }
1800 {
1801 let mut buf = tail.to_buf();
1802 buf.push_front(head.clone());
1803 if buf != ptr {
1804 return false;
1805 }
1806 }
1807 {
1808 let fmt = alloc::format!("/{}{tail}", head.encoded());
1809 if Pointer::parse(&fmt).unwrap() != ptr {
1810 return false;
1811 }
1812 }
1813 } else {
1814 return ptr.is_root()
1815 && ptr.count() == 0
1816 && ptr.last().is_none()
1817 && ptr.first().is_none();
1818 }
1819 if let Some((head, tail)) = ptr.split_back() {
1820 {
1821 let Some(last) = ptr.last() else {
1822 return false;
1823 };
1824 if last != tail {
1825 return false;
1826 }
1827 }
1828 {
1829 let mut copy = ptr.clone();
1830 copy.pop_back();
1831 if copy != head {
1832 return false;
1833 }
1834 }
1835 {
1836 let mut buf = head.to_buf();
1837 buf.push_back(tail.clone());
1838 if buf != ptr {
1839 return false;
1840 }
1841 }
1842 {
1843 let fmt = alloc::format!("{head}/{}", tail.encoded());
1844 if Pointer::parse(&fmt).unwrap() != ptr {
1845 return false;
1846 }
1847 }
1848 if Some(head) != ptr.parent() {
1849 return false;
1850 }
1851 } else {
1852 return ptr.is_root()
1853 && ptr.count() == 0
1854 && ptr.last().is_none()
1855 && ptr.first().is_none();
1856 }
1857 true
1858 }
1859
1860 #[quickcheck]
1861 fn qc_from_tokens(tokens: Vec<String>) -> bool {
1862 let buf = PointerBuf::from_tokens(&tokens);
1863 let reconstructed: Vec<_> = buf.tokens().collect();
1864 reconstructed
1865 .into_iter()
1866 .zip(tokens)
1867 .all(|(a, b)| a.decoded() == b)
1868 }
1869
1870 #[quickcheck]
1871 fn qc_intersection(base: PointerBuf, suffix_0: PointerBuf, suffix_1: PointerBuf) -> TestResult {
1872 if suffix_0.first() == suffix_1.first() {
1873 return TestResult::discard();
1875 }
1876 let mut a = base.clone();
1877 a.append(&suffix_0);
1878 let mut b = base.clone();
1879 b.append(&suffix_1);
1880 let isect = a.intersection(&b);
1881 TestResult::from_bool(isect == base)
1882 }
1883
1884 #[cfg(all(feature = "json", feature = "std", feature = "serde"))]
1885 #[test]
1886 fn serde() {
1887 use serde::Deserialize;
1888 let ptr = PointerBuf::from_tokens(["foo", "bar"]);
1889 let json = serde_json::to_string(&ptr).unwrap();
1890 assert_eq!(json, "\"/foo/bar\"");
1891 let deserialized: PointerBuf = serde_json::from_str(&json).unwrap();
1892 assert_eq!(deserialized, ptr);
1893
1894 let ptr = Pointer::from_static("/foo/bar");
1895 let json = serde_json::to_string(&ptr).unwrap();
1896 assert_eq!(json, "\"/foo/bar\"");
1897
1898 let mut de = serde_json::Deserializer::from_str("\"/foo/bar\"");
1899 let p = <&Pointer>::deserialize(&mut de).unwrap();
1900 assert_eq!(p, ptr);
1901 let s = serde_json::to_string(p).unwrap();
1902 assert_eq!(json, s);
1903
1904 let invalid = serde_json::from_str::<&Pointer>("\"foo/bar\"");
1905 assert!(invalid.is_err());
1906 assert_eq!(
1907 invalid.unwrap_err().to_string(),
1908 "failed to parse json pointer\n\ncaused by:\njson pointer is malformed as it does not start with a backslash ('/') at line 1 column 9"
1909 );
1910 }
1911
1912 #[test]
1913 fn to_owned() {
1914 let ptr = Pointer::from_static("/bread/crumbs");
1915 let buf = ptr.to_owned();
1916 assert_eq!(buf, "/bread/crumbs");
1917 }
1918
1919 #[test]
1920 fn concat() {
1921 let ptr = Pointer::from_static("/foo");
1922 let barbaz = Pointer::from_static("/bar/baz");
1923 assert_eq!(ptr.concat(barbaz), "/foo/bar/baz");
1924 }
1925
1926 #[test]
1927 fn with_leading_token() {
1928 let ptr = Pointer::from_static("/bar");
1929 let foobar = ptr.with_leading_token("foo");
1930 assert_eq!(foobar, "/foo/bar");
1931 }
1932
1933 #[test]
1934 fn with_trailing_token() {
1935 let ptr = Pointer::from_static("/foo");
1936 let foobar = ptr.with_trailing_token("bar");
1937 assert_eq!(foobar, "/foo/bar");
1938 }
1939
1940 #[test]
1941 fn len() {
1942 let ptr = Pointer::from_static("/foo/bar");
1943 assert_eq!(ptr.len(), 8);
1944 let mut ptr = ptr.to_buf();
1945 ptr.push_back("~");
1946 assert_eq!(ptr.len(), 11);
1947 }
1948
1949 #[test]
1950 fn is_empty() {
1951 assert!(Pointer::from_static("").is_empty());
1952 assert!(!Pointer::from_static("/").is_empty());
1953 }
1954
1955 #[test]
1956 #[allow(clippy::cmp_owned, unused_must_use)]
1957 fn partial_eq() {
1958 let ptr_string = String::from("/bread/crumbs");
1959 let ptr_str = "/bread/crumbs";
1960 let ptr = Pointer::from_static(ptr_str);
1961 let ptr_buf = ptr.to_buf();
1962 <&Pointer as PartialEq<&Pointer>>::eq(&ptr, &ptr);
1963 <Pointer as PartialEq<&str>>::eq(ptr, &ptr_str);
1964 <&Pointer as PartialEq<String>>::eq(&ptr, &ptr_string);
1965 <Pointer as PartialEq<String>>::eq(ptr, &ptr_string);
1966 <Pointer as PartialEq<PointerBuf>>::eq(ptr, &ptr_buf);
1967 <&str as PartialEq<Pointer>>::eq(&ptr_str, ptr);
1968 <String as PartialEq<Pointer>>::eq(&ptr_string, ptr);
1969 <str as PartialEq<Pointer>>::eq(ptr_str, ptr);
1970 <PointerBuf as PartialEq<str>>::eq(&ptr_buf, ptr_str);
1971 <PointerBuf as PartialEq<PointerBuf>>::eq(&ptr_buf, &ptr_buf);
1972 <PointerBuf as PartialEq<Pointer>>::eq(&ptr_buf, ptr);
1973 <Pointer as PartialEq<PointerBuf>>::eq(ptr, &ptr_buf);
1974 <PointerBuf as PartialEq<&Pointer>>::eq(&ptr_buf, &ptr);
1975 <PointerBuf as PartialEq<&str>>::eq(&ptr_buf, &ptr_str);
1976 <PointerBuf as PartialEq<String>>::eq(&ptr_buf, &ptr_string);
1977 <&Pointer as PartialEq<PointerBuf>>::eq(&ptr, &ptr_buf);
1978 <str as PartialEq<PointerBuf>>::eq(ptr_str, &ptr_buf);
1979 <&str as PartialEq<PointerBuf>>::eq(&ptr_str, &ptr_buf);
1980 <String as PartialEq<PointerBuf>>::eq(&ptr_string, &ptr_buf);
1981 }
1982
1983 #[test]
1984 fn partial_ord() {
1985 let a_str = "/foo/bar";
1986 let a_string = a_str.to_string();
1987 let a_ptr = Pointer::from_static(a_str);
1988 let a_buf = a_ptr.to_buf();
1989 let b_str = "/foo/bar";
1990 let b_string = b_str.to_string();
1991 let b_ptr = Pointer::from_static(b_str);
1992 let b_buf = b_ptr.to_buf();
1993 let c_str = "/foo/bar/baz";
1994 let c_string = c_str.to_string();
1995 let c_ptr = Pointer::from_static(c_str);
1996 let c_buf = c_ptr.to_buf();
1997
1998 assert!(<Pointer as PartialOrd<PointerBuf>>::lt(a_ptr, &c_buf));
1999 assert!(<PointerBuf as PartialOrd<Pointer>>::lt(&a_buf, c_ptr));
2000 assert!(<String as PartialOrd<Pointer>>::lt(&a_string, c_ptr));
2001 assert!(<str as PartialOrd<Pointer>>::lt(a_str, c_ptr));
2002 assert!(<str as PartialOrd<PointerBuf>>::lt(a_str, &c_buf));
2003 assert!(<&str as PartialOrd<Pointer>>::lt(&a_str, c_ptr));
2004 assert!(<&str as PartialOrd<PointerBuf>>::lt(&a_str, &c_buf));
2005 assert!(<&Pointer as PartialOrd<PointerBuf>>::lt(&a_ptr, &c_buf));
2006 assert!(<&Pointer as PartialOrd<&str>>::lt(&b_ptr, &c_str));
2007 assert!(<Pointer as PartialOrd<String>>::lt(a_ptr, &c_string));
2008 assert!(<PointerBuf as PartialOrd<&str>>::lt(&a_buf, &c_str));
2009 assert!(<PointerBuf as PartialOrd<String>>::lt(&a_buf, &c_string));
2010 assert!(a_ptr < c_buf);
2011 assert!(c_buf > a_ptr);
2012 assert!(a_buf < c_ptr);
2013 assert!(a_ptr < c_buf);
2014 assert!(a_ptr < c_ptr);
2015 assert!(a_ptr <= c_ptr);
2016 assert!(c_ptr > a_ptr);
2017 assert!(c_ptr >= a_ptr);
2018 assert!(a_ptr == b_ptr);
2019 assert!(a_ptr <= b_ptr);
2020 assert!(a_ptr >= b_ptr);
2021 assert!(a_string < c_buf);
2022 assert!(a_string <= c_buf);
2023 assert!(c_string > a_buf);
2024 assert!(c_string >= a_buf);
2025 assert!(a_string == b_buf);
2026 assert!(a_ptr < c_buf);
2027 assert!(a_ptr <= c_buf);
2028 assert!(c_ptr > a_buf);
2029 assert!(c_ptr >= a_buf);
2030 assert!(a_ptr == b_buf);
2031 assert!(a_ptr <= b_buf);
2032 assert!(a_ptr >= b_buf);
2033 assert!(a_ptr < c_buf);
2034 assert!(c_ptr > b_string);
2035 #[allow(clippy::nonminimal_bool)]
2037 let not = !(a_ptr > c_buf);
2038 assert!(not);
2039 }
2040
2041 #[test]
2042 fn intersection() {
2043 struct Test {
2044 base: &'static str,
2045 a_suffix: &'static str,
2046 b_suffix: &'static str,
2047 }
2048
2049 let tests = [
2050 Test {
2051 base: "",
2052 a_suffix: "/",
2053 b_suffix: "/a/b/c",
2054 },
2055 Test {
2056 base: "",
2057 a_suffix: "",
2058 b_suffix: "",
2059 },
2060 Test {
2061 base: "/a",
2062 a_suffix: "/",
2063 b_suffix: "/suffix",
2064 },
2065 Test {
2066 base: "/a",
2067 a_suffix: "/suffix",
2068 b_suffix: "",
2069 },
2070 Test {
2071 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}묁",
2072 a_suffix: "/Y\u{2064}",
2073 b_suffix: "",
2074 }
2075 ];
2076
2077 for Test {
2078 base,
2079 a_suffix,
2080 b_suffix,
2081 } in tests
2082 {
2083 let base = PointerBuf::parse(base).expect(&format!("failed to parse ${base}"));
2084 let mut a = base.clone();
2085 let mut b = base.clone();
2086 a.append(PointerBuf::parse(a_suffix).unwrap());
2087 b.append(PointerBuf::parse(b_suffix).unwrap());
2088 let intersection = a.intersection(&b);
2089 assert_eq!(intersection, base);
2090 }
2091 }
2092 #[test]
2093 fn parse_error_display() {
2094 assert_eq!(
2095 ParseError::NoLeadingBackslash.to_string(),
2096 "json pointer is malformed as it does not start with a backslash ('/')"
2097 );
2098 }
2099
2100 #[test]
2101 fn into_iter() {
2102 use core::iter::IntoIterator;
2103
2104 let ptr = PointerBuf::from_tokens(["foo", "bar", "baz"]);
2105 let tokens: Vec<Token> = ptr.into_iter().collect();
2106 let from_tokens = PointerBuf::from_tokens(tokens);
2107 assert_eq!(ptr, from_tokens);
2108
2109 let ptr = Pointer::from_static("/foo/bar/baz");
2110 let tokens: Vec<_> = ptr.into_iter().collect();
2111 assert_eq!(ptr, PointerBuf::from_tokens(tokens));
2112 }
2113
2114 #[test]
2115 fn from_str() {
2116 let p = PointerBuf::from_str("/foo/bar").unwrap();
2117 assert_eq!(p, "/foo/bar");
2118 }
2119
2120 #[test]
2121 fn from_token() {
2122 let p = PointerBuf::from(Token::new("foo"));
2123 assert_eq!(p, "/foo");
2124 }
2125
2126 #[test]
2127 fn from_usize() {
2128 let p = PointerBuf::from(0);
2129 assert_eq!(p, "/0");
2130 }
2131
2132 #[test]
2133 fn borrow() {
2134 let ptr = PointerBuf::from_tokens(["foo", "bar"]);
2135 let borrowed: &Pointer = ptr.borrow();
2136 assert_eq!(borrowed, "/foo/bar");
2137 }
2138}