Skip to main content

jsonptr/
pointer.rs

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/// A JSON Pointer is a string containing a sequence of zero or more reference
19/// [`Token`]s, each prefixed by a `'/'` character.
20///
21/// See [RFC 6901 for more
22/// information](https://datatracker.ietf.org/doc/html/rfc6901).
23///
24/// ## Example
25/// ```rust
26/// use jsonptr::{Pointer, resolve::Resolve};
27/// use serde_json::{json, Value};
28///
29/// let data = json!({ "foo": { "bar": "baz" } });
30/// let ptr = Pointer::from_static("/foo/bar");
31/// let bar = data.resolve(&ptr).unwrap();
32/// assert_eq!(bar, "baz");
33/// ```
34#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
35// See https://doc.rust-lang.org/src/std/path.rs.html#1985
36#[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    /// Create a `Pointer` from a string that is known to be correctly encoded.
51    ///
52    /// This is a cost-free conversion.
53    ///
54    /// ## Safety
55    /// The provided string must adhere to [RFC 6901](https://datatracker.ietf.org/doc/html/rfc6901):
56    ///
57    /// - The pointer must start with `'/'` (%x2F) unless empty
58    /// - Tokens must be properly encoded:
59    ///     - `'~'` (%x7E) must be escaped as `"~0"`
60    ///     - `'/'` (%x2F) must be escaped as `"~1"`
61    ///
62    /// For potentially fallible parsing, see [`Pointer::parse`].
63    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    /// Constant reference to a root pointer
68    pub const fn root() -> &'static Self {
69        // unsafe { &*(core::ptr::from_ref::<str>("") as *const Self) }
70        #[allow(clippy::ref_as_ptr)]
71        unsafe {
72            &*("" as *const str as *const Self)
73        }
74    }
75
76    /// Attempts to parse a string into a `Pointer`.
77    ///
78    /// If successful, this does not allocate.
79    ///
80    /// ## Errors
81    /// Returns a `ParseError` if the string is not a valid JSON Pointer.
82    pub fn parse<S: AsRef<str> + ?Sized>(s: &S) -> Result<&Self, ParseError> {
83        // SAFETY: we validate first
84        validate(s.as_ref()).map(|s| unsafe { Self::new_unchecked(s) })
85    }
86
87    /// Creates a static `Pointer` from a string.
88    ///
89    /// # Panics
90    ///
91    /// Will panic if the string does not represent a valid pointer.
92    ///
93    /// # Examples
94    ///
95    /// ```
96    /// use jsonptr::{Pointer, resolve::Resolve};
97    /// use serde_json::{json, Value};
98    ///
99    /// const POINTER: &Pointer = Pointer::from_static("/foo/bar");
100    /// let data = json!({ "foo": { "bar": "baz" } });
101    /// let bar = data.resolve(POINTER).unwrap();
102    /// assert_eq!(bar, "baz");
103    /// ```
104    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    /// The encoded string representation of this `Pointer`
110    pub fn as_str(&self) -> &str {
111        &self.0
112    }
113
114    /// Converts into an owned [`PointerBuf`]
115    pub fn to_buf(&self) -> PointerBuf {
116        PointerBuf(self.0.to_string())
117    }
118
119    /// Returns an iterator of `Token`s in the `Pointer`.
120    pub fn tokens(&self) -> Tokens<'_> {
121        let mut s = self.0.split('/');
122        // skipping the first '/'
123        s.next();
124        Tokens::new(s)
125    }
126
127    /// Returns the number of tokens in the `Pointer`.
128    pub fn count(&self) -> usize {
129        self.tokens().count()
130    }
131
132    /// Returns `true` if the JSON Pointer equals `""`.
133    pub fn is_root(&self) -> bool {
134        self.0.is_empty()
135    }
136
137    /// Returns a `serde_json::Value` representation of this `Pointer`
138    #[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    /// Returns the last `Token` in the `Pointer`.
144    pub fn back(&self) -> Option<Token<'_>> {
145        self.0
146            .rsplit_once('/')
147            // SAFETY: pointer is encoded
148            .map(|(_, back)| unsafe { Token::from_encoded_unchecked(back) })
149    }
150
151    /// Returns the last token in the `Pointer`.
152    ///
153    /// alias for `back`
154    pub fn last(&self) -> Option<Token<'_>> {
155        self.back()
156    }
157
158    /// Returns the first `Token` in the `Pointer`.
159    pub fn front(&self) -> Option<Token<'_>> {
160        if self.is_root() {
161            return None;
162        }
163        self.0[1..]
164            .split_once('/')
165            // SAFETY: source pointer is encoded
166            .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    /// Returns the first `Token` in the `Pointer`.
174    ///
175    /// alias for `front`
176    pub fn first(&self) -> Option<Token<'_>> {
177        self.front()
178    }
179
180    /// Splits the `Pointer` into the first `Token` and a remainder `Pointer`.
181    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                        // SAFETY: source pointer is encoded
191                        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                        // SAFETY: source pointer is encoded
199                        unsafe { Token::from_encoded_unchecked(front) },
200                        // SAFETY: we split at a token boundary, so back is
201                        // valid pointer.
202                        unsafe { Self::new_unchecked(back) },
203                    )
204                },
205            )
206            .into()
207    }
208
209    /// Splits the `Pointer` at the given offset if the character at the offset is
210    /// a separator slash (`'/'`), returning `Some((head, tail))`. Otherwise,
211    /// returns `None`.
212    ///
213    /// For the following JSON Pointer, the following splits are possible (0, 4,
214    /// 8):
215    /// ```text
216    /// /foo/bar/baz
217    /// ↑   ↑   ↑
218    /// 0   4   8
219    /// ```
220    /// All other offsets will return `None`.
221    ///
222    /// ## Example
223    ///
224    /// ```rust
225    /// # use jsonptr::Pointer;
226    /// let ptr = Pointer::from_static("/foo/bar/baz");
227    /// let (head, tail) = ptr.split_at_offset(4).unwrap();
228    /// assert_eq!(head, Pointer::from_static("/foo"));
229    /// assert_eq!(tail, Pointer::from_static("/bar/baz"));
230    /// assert_eq!(ptr.split_at_offset(3), None);
231    /// ```
232    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        // SAFETY: we split at a token boundary, so head and tail are valid pointers
238        unsafe { Some((Self::new_unchecked(head), Self::new_unchecked(tail))) }
239    }
240
241    /// Splits the `Pointer` at the given offset if the character at the offset is
242    /// a separator slash (`'/'`), returning `Some((head, tail))`. Otherwise,
243    /// returns `None`.
244    ///
245    /// This method is deprecated in favor of [`Pointer::split_at_offset`]. The
246    /// `split_at` name is being reserved so that it can be reintroduced as a
247    /// position (index) based split by 1.0, matching the rest of the API (e.g.
248    /// [`Pointer::get`]).
249    #[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    /// Splits the `Pointer` into the parent path and the last `Token`.
258    pub fn split_back(&self) -> Option<(&Self, Token<'_>)> {
259        self.0.rsplit_once('/').map(|(front, back)| {
260            (
261                // SAFETY: we split at a token boundary, so front is a valid pointer
262                unsafe { Self::new_unchecked(front) },
263                // SAFETY: source token is encoded
264                unsafe { Token::from_encoded_unchecked(back) },
265            )
266        })
267    }
268
269    /// A pointer to the parent of the current path.
270    pub fn parent(&self) -> Option<&Self> {
271        // SAFETY: we split at a token boundary, so front is a valid pointer
272        self.0
273            .rsplit_once('/')
274            .map(|(front, _)| unsafe { Self::new_unchecked(front) })
275    }
276
277    /// Returns the pointer stripped of the given suffix.
278    pub fn strip_suffix<'a>(&'a self, suffix: &Self) -> Option<&'a Self> {
279        self.0
280            .strip_suffix(&suffix.0)
281            // SAFETY: the suffix is a valid pointer, so removing it from the
282            // back of another pointer will preserve token boundaries
283            .map(|s| unsafe { Self::new_unchecked(s) })
284    }
285
286    /// Returns the pointer stripped of the given prefix.
287    pub fn strip_prefix<'a>(&'a self, prefix: &Self) -> Option<&'a Self> {
288        self.0
289            .strip_prefix(&prefix.0)
290            // SAFETY: the suffix is a valid pointer, so removing it from the
291            // front of another pointer will preserve token boundaries
292            .map(|s| unsafe { Self::new_unchecked(s) })
293    }
294
295    /// Returns whether `self` has a suffix of `other`.
296    ///
297    /// Note that `Pointer::root` is only a valid suffix of itself.
298    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    /// Returns whether `self` has a prefix of `other.`
304    ///
305    /// Note that `Pointer::root` is a valid prefix of any `Pointer` (including
306    /// itself).
307    pub fn starts_with(&self, other: &Self) -> bool {
308        self.as_str().starts_with(&other.0)
309            // ensure we end at a token boundary
310            && (other.len() == self.len() || self.0.as_bytes()[other.len()] == b'/')
311    }
312
313    /// Attempts to get a `Token` by the index. Returns `None` if the index is
314    /// out of bounds.
315    ///
316    /// ## Example
317    /// ```rust
318    /// use jsonptr::{Pointer, Token};
319    ///
320    /// let ptr = Pointer::from_static("/foo/bar/qux");
321    /// assert_eq!(ptr.get(0), Some("foo".into()));
322    /// assert_eq!(ptr.get(1), Some("bar".into()));
323    /// assert_eq!(ptr.get(3), None);
324    /// assert_eq!(ptr.get(..), Some(Pointer::from_static("/foo/bar/qux")));
325    /// assert_eq!(ptr.get(..1), Some(Pointer::from_static("/foo")));
326    /// assert_eq!(ptr.get(1..3), Some(Pointer::from_static("/bar/qux")));
327    /// assert_eq!(ptr.get(1..=2), Some(Pointer::from_static("/bar/qux")));
328    ///
329    /// let ptr = Pointer::root();
330    /// assert_eq!(ptr.get(0), None);
331    /// assert_eq!(ptr.get(..), Some(Pointer::root()));
332    /// ```
333    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    /// Attempts to resolve a [`R::Value`] based on the path in this [`Pointer`].
341    ///
342    /// ## Errors
343    /// Returns [`R::Error`] if an error occurs while resolving.
344    ///
345    /// The rules of such are determined by the `R`'s implementation of
346    /// [`Resolve`] but provided implementations return [`ResolveError`] if:
347    /// - The path is unreachable (e.g. a scalar is encountered prior to the end
348    ///   of the path)
349    /// - The path is not found (e.g. a key in an object or an index in an array
350    ///   does not exist)
351    /// - A [`Token`] cannot be parsed as an array [`Index`]
352    /// - An array [`Index`] is out of bounds
353    ///
354    /// [`R::Value`]: `crate::resolve::Resolve::Value`
355    /// [`R::Error`]: `crate::resolve::Resolve::Error`
356    /// [`Resolve`]: `crate::resolve::Resolve`
357    /// [`ResolveError`]: `crate::resolve::ResolveError`
358    /// [`Token`]: `crate::Token`
359    /// [`Index`]: `crate::index::Index`
360    #[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    /// Attempts to resolve a mutable [`R::Value`] based on the path in this
366    /// `Pointer`.
367    ///
368    /// ## Errors
369    /// Returns [`R::Error`] if an error occurs while
370    /// resolving.
371    ///
372    /// The rules of such are determined by the `R`'s implementation of
373    /// [`ResolveMut`] but provided implementations return [`ResolveError`] if:
374    /// - The path is unreachable (e.g. a scalar is encountered prior to the end
375    ///   of the path)
376    /// - The path is not found (e.g. a key in an object or an index in an array
377    ///   does not exist)
378    /// - A [`Token`] cannot be parsed as an array [`Index`]
379    /// - An array [`Index`] is out of bounds
380    ///
381    /// [`R::Value`]: `crate::resolve::ResolveMut::Value`
382    /// [`R::Error`]: `crate::resolve::ResolveMut::Error`
383    /// [`ResolveMut`]: `crate::resolve::ResolveMut`
384    /// [`ResolveError`]: `crate::resolve::ResolveError`
385    /// [`Token`]: `crate::Token`
386    /// [`Index`]: `crate::index::Index`
387    #[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    /// Finds the commonality between this and another `Pointer`.
396    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    /// Attempts to delete a `serde_json::Value` based upon the path in this
411    /// `Pointer`.
412    ///
413    /// The rules of deletion are determined by the `D`'s implementation of
414    /// [`Delete`]. The supplied implementations (`"json"` & `"toml"`) operate
415    /// as follows:
416    /// - If the `Pointer` can be resolved, the `Value` is deleted and returned.
417    /// - If the `Pointer` fails to resolve for any reason, `None` is returned.
418    /// - If the `Pointer` is root, `value` is replaced:
419    ///     - `"json"`: `serde_json::Value::Null`
420    ///     - `"toml"`: `toml::Value::Table::Default`
421    ///
422    ///
423    /// ## Examples
424    /// ### Deleting a resolved pointer:
425    /// ```rust
426    /// use jsonptr::{Pointer, delete::Delete};
427    /// use serde_json::json;
428    ///
429    /// let mut data = json!({ "foo": { "bar": { "baz": "qux" } } });
430    /// let ptr = Pointer::from_static("/foo/bar/baz");
431    /// assert_eq!(data.delete(&ptr), Some("qux".into()));
432    /// assert_eq!(data, json!({ "foo": { "bar": {} } }));
433    /// ```
434    /// ### Deleting a non-existent Pointer returns `None`:
435    /// ```rust
436    /// use jsonptr::{ Pointer, delete::Delete };
437    /// use serde_json::json;
438    ///
439    /// let mut data = json!({});
440    /// let ptr = Pointer::from_static("/foo/bar/baz");
441    /// assert_eq!(ptr.delete(&mut data), None);
442    /// assert_eq!(data, json!({}));
443    /// ```
444    /// ### Deleting a root pointer replaces the value with `Value::Null`:
445    /// ```rust
446    /// use jsonptr::{Pointer, delete::Delete};
447    /// use serde_json::json;
448    ///
449    /// let mut data = json!({ "foo": { "bar": "baz" } });
450    /// let ptr = Pointer::root();
451    /// assert_eq!(data.delete(&ptr), Some(json!({ "foo": { "bar": "baz" } })));
452    /// assert!(data.is_null());
453    /// ```
454    ///
455    /// [`Delete`]: crate::delete::Delete
456    #[cfg(feature = "delete")]
457    pub fn delete<D: crate::Delete>(&self, value: &mut D) -> Option<D::Value> {
458        value.delete(self)
459    }
460
461    /// Attempts to assign `src` to `dest` based on the path in this `Pointer`.
462    ///
463    /// If the path is partially available, the missing portions will be created. If the path
464    /// contains a zero index, such as `"/0"`, then an array will be created. Otherwise, objects
465    /// will be utilized to create the missing path.
466    ///
467    /// ## Example
468    /// ```rust
469    /// use jsonptr::Pointer;
470    /// use serde_json::{json, Value};
471    ///
472    /// let mut data = json!([]);
473    /// let mut ptr = Pointer::from_static("/0/foo");
474    /// let replaced = ptr.assign(&mut data, json!("bar")).unwrap();
475    /// assert_eq!(data, json!([{"foo": "bar"}]));
476    /// assert_eq!(replaced, None);
477    /// ```
478    ///
479    /// ## Errors
480    /// Returns [`Assign::Error`] if the path is invalid or if the value cannot be assigned.
481    ///
482    /// [`Assign::Error`]: crate::assign::Assign::Error
483    #[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    /// Returns [`Components`] of this JSON Pointer.
493    ///
494    /// A [`Component`](crate::Component) is either [`Token`] or the root
495    /// location of a document.
496    /// ## Example
497    /// ```
498    /// # use jsonptr::{Component, Pointer};
499    /// let ptr = Pointer::parse("/a/b").unwrap();
500    /// let mut components = ptr.components();
501    /// assert_eq!(components.next(), Some(Component::Root));
502    /// assert_eq!(components.next(), Some(Component::Token("a".into())));
503    /// assert_eq!(components.next(), Some(Component::Token("b".into())));
504    /// assert_eq!(components.next(), None);
505    /// ```
506    pub fn components(&self) -> Components<'_> {
507        self.into()
508    }
509
510    /// Creates an owned [`PointerBuf`] like `self` but with `token` appended.
511    ///
512    /// See [`PointerBuf::push_back`] for more details.
513    ///
514    /// **Note**: this method allocates. If you find yourself calling it more
515    /// than once for a given pointer, consider using [`PointerBuf::push_back`]
516    /// instead.
517    ///
518    /// ## Examples
519    /// ```
520    /// let ptr = jsonptr::Pointer::from_static("/foo");
521    /// let foobar = ptr.with_trailing_token("bar");
522    /// assert_eq!(foobar, "/foo/bar");
523    /// ```
524    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    /// Creates an owned [`PointerBuf`] like `self` but with `token` prepended.
531    ///
532    /// See [`PointerBuf::push_front`] for more details.
533    ///
534    /// **Note**: this method allocates. If you find yourself calling it more
535    /// than once for a given pointer, consider using [`PointerBuf::push_front`]
536    /// instead.
537    ///
538    /// ## Examples
539    /// ```
540    /// let ptr = jsonptr::Pointer::from_static("/bar");
541    /// let foobar = ptr.with_leading_token("foo");
542    /// assert_eq!(foobar, "/foo/bar");
543    /// ```
544    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    /// Creates an owned [`PointerBuf`] like `self` but with `other` appended to
551    /// the end.
552    ///
553    /// See [`PointerBuf::append`] for more details.
554    ///
555    /// **Note**: this method allocates. If you find yourself calling it more
556    /// than  given pointer, consider using [`PointerBuf::append`]
557    /// instead.
558    ///
559    /// ## Examples
560    /// ```
561    /// let ptr = jsonptr::Pointer::from_static("/foo");
562    /// let other = jsonptr::Pointer::from_static("/bar/baz");
563    /// assert_eq!(ptr.concat(other), "/foo/bar/baz");
564    /// ```
565    pub fn concat(&self, other: &Pointer) -> PointerBuf {
566        let mut buf = self.to_buf();
567        buf.append(other);
568        buf
569    }
570
571    /// Returns the length of `self` in encoded format.
572    ///
573    /// This length expresses the byte count of the underlying string that
574    /// represents the RFC 6901 Pointer. See also [`str::len`].
575    ///
576    /// ## Examples
577    /// ```
578    /// let mut ptr = jsonptr::PointerBuf::parse("/foo/bar").unwrap();
579    /// assert_eq!(ptr.len(), 8);
580    ///
581    /// ptr.push_back("~");
582    /// assert_eq!(ptr.len(), 11);
583    ///
584    /// ```
585    pub fn len(&self) -> usize {
586        self.0.len()
587    }
588
589    /// Returns `true` if the `Pointer` is empty (i.e. root).    
590    ///
591    /// ## Examples
592    /// ```
593    /// let mut ptr = jsonptr::PointerBuf::new();
594    /// assert!(ptr.is_empty());
595    ///
596    /// ptr.push_back("foo");
597    /// assert!(!ptr.is_empty());
598    /// ```
599    pub fn is_empty(&self) -> bool {
600        self.0.is_empty()
601    }
602
603    /// Converts a `Box<Pointer>` into a `PointerBuf` without copying or allocating.
604    pub fn into_buf(self: Box<Pointer>) -> PointerBuf {
605        let inner = Box::into_raw(self);
606        // SAFETY: we ensure the layout of `Pointer` is the same as `str`
607        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/// An owned, mutable [`Pointer`] (akin to `String`).
909///
910/// This type provides methods like [`PointerBuf::push_back`] and
911/// [`PointerBuf::replace`] that mutate the pointer in place. It also
912/// implements [`core::ops::Deref`] to [`Pointer`], meaning that all methods on
913/// [`Pointer`] slices are available on `PointerBuf` values as well.
914#[derive(Clone, Default, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
915pub struct PointerBuf(String);
916
917impl PointerBuf {
918    /// Creates a new `PointerBuf` pointing to a document root.
919    ///
920    /// This is an alias to [`Self::new`].
921    pub fn root() -> Self {
922        Self::new()
923    }
924
925    /// Creates a new `PointerBuf` pointing to a document root.
926    pub fn new() -> Self {
927        Self(String::new())
928    }
929
930    /// Create a `PointerBuf` from a string that is known to be correctly encoded.
931    ///
932    /// ## Safety
933    /// The provided string must adhere to RFC 6901.
934    pub unsafe fn new_unchecked(s: impl Into<String>) -> Self {
935        Self(s.into())
936    }
937
938    /// Attempts to parse a string into a `PointerBuf`.
939    ///
940    /// ## Errors
941    /// Returns a [`RichParseError`] if the string is not a valid JSON Pointer.
942    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    /// Creates a new `PointerBuf` from a slice of non-encoded strings.
951    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    /// Coerces to a Pointer slice.
961    pub fn as_ptr(&self) -> &Pointer {
962        self
963    }
964
965    /// Pushes a `Token` onto the front of this `Pointer`.
966    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    /// Pushes a `Token` onto the back of this `Pointer`.
972    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    /// Removes and returns the last `Token` in the `Pointer` if it exists.
978    pub fn pop_back(&mut self) -> Option<Token<'static>> {
979        if let Some(idx) = self.0.rfind('/') {
980            // SAFETY: source pointer is encoded
981            let back = unsafe { Token::from_encoded_unchecked(self.0.split_off(idx + 1)) };
982            self.0.pop(); // remove trailing `/`
983            Some(back)
984        } else {
985            None
986        }
987    }
988
989    /// Removes and returns the first `Token` in the `Pointer` if it exists.
990    pub fn pop_front(&mut self) -> Option<Token<'static>> {
991        (!self.is_root()).then(|| {
992            // if not root, must contain at least one `/`
993            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            // remove leading `/`
1000            token.remove(0);
1001            // SAFETY: source pointer is encoded
1002            unsafe { Token::from_encoded_unchecked(token) }
1003        })
1004    }
1005
1006    /// Merges two `Pointer`s by appending `other` onto `self`.
1007    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    /// Attempts to replace a `Token` by the index, returning the replaced
1018    /// `Token` if it already exists. Returns `None` otherwise.
1019    ///
1020    /// ## Errors
1021    /// A [`ReplaceError`] is returned if the index is out of bounds.
1022    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    /// Clears the `Pointer`, setting it to root (`""`).
1054    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        // SAFETY: we hold a valid pointer
1076        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        // SAFETY: we ensure that the layout of `str` is the same as `Pointer`
1084        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/// Indicates that a `Pointer` was malformed and unable to be parsed.
1170#[derive(Debug, PartialEq)]
1171pub enum ParseError {
1172    /// `Pointer` did not start with a slash (`'/'`).
1173    NoLeadingSlash,
1174
1175    /// `Pointer` contained invalid encoding (e.g. `~` not followed by `0` or
1176    /// `1`).
1177    InvalidEncoding {
1178        /// Offset of the partial pointer starting with the token that contained
1179        /// the invalid encoding
1180        offset: usize,
1181        /// The source `InvalidEncodingError`
1182        source: EncodingError,
1183    },
1184}
1185
1186impl ParseError {
1187    /// Offset of the partial pointer starting with the token that contained the
1188    /// invalid encoding
1189    pub fn offset(&self) -> usize {
1190        match self {
1191            Self::NoLeadingSlash => 0,
1192            Self::InvalidEncoding { offset, .. } => *offset,
1193        }
1194    }
1195    /// Length of the invalid encoding
1196    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    /// Returns `true` if this error is `NoLeadingSlash`
1254    pub fn is_no_leading_backslash(&self) -> bool {
1255        matches!(self, Self::NoLeadingSlash { .. })
1256    }
1257
1258    /// Returns `true` if this error is `NoLeadingSlash`
1259    pub fn is_no_leading_slash(&self) -> bool {
1260        matches!(self, Self::NoLeadingSlash { .. })
1261    }
1262
1263    /// Returns `true` if this error is `InvalidEncoding`    
1264    pub fn is_invalid_encoding(&self) -> bool {
1265        matches!(self, Self::InvalidEncoding { .. })
1266    }
1267
1268    /// Offset of the partial pointer starting with the token which caused the error.
1269    ///
1270    /// ```text
1271    /// "/foo/invalid~tilde/invalid"
1272    ///      ↑
1273    /// ```
1274    ///
1275    /// ```
1276    /// # use jsonptr::PointerBuf;
1277    /// let err = PointerBuf::parse("/foo/invalid~tilde/invalid").unwrap_err();
1278    /// assert_eq!(err.pointer_offset(), 4)
1279    /// ```
1280    pub fn pointer_offset(&self) -> usize {
1281        match *self {
1282            Self::NoLeadingSlash { .. } => 0,
1283            Self::InvalidEncoding { offset, .. } => offset,
1284        }
1285    }
1286
1287    /// Offset of the character index from within the first token of
1288    /// [`Self::pointer_offset`])
1289    ///
1290    /// ```text
1291    /// "/foo/invalid~tilde/invalid"
1292    ///              ↑
1293    ///              8
1294    /// ```
1295    /// ```
1296    /// # use jsonptr::PointerBuf;
1297    /// let err = PointerBuf::parse("/foo/invalid~tilde/invalid").unwrap_err();
1298    /// assert_eq!(err.source_offset(), 8)
1299    /// ```
1300    pub fn source_offset(&self) -> usize {
1301        match self {
1302            Self::NoLeadingSlash { .. } => 0,
1303            Self::InvalidEncoding { source, .. } => source.offset,
1304        }
1305    }
1306
1307    /// Offset of the first invalid encoding from within the pointer.
1308    /// ```text
1309    /// "/foo/invalid~tilde/invalid"
1310    ///              ↑
1311    ///             12
1312    /// ```
1313    /// ```
1314    /// use jsonptr::PointerBuf;
1315    /// let err = PointerBuf::parse("/foo/invalid~tilde/invalid").unwrap_err();
1316    /// assert_eq!(err.complete_offset(), 12)
1317    /// ```
1318    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
1333/// A rich error type that includes the original string that failed to parse.
1334pub type RichParseError = Report<ParseError>;
1335
1336/// Returned from [`PointerBuf::replace`] when the provided index is out of
1337/// bounds.
1338#[derive(Debug, PartialEq, Eq)]
1339pub struct ReplaceError {
1340    /// The index of the token that was out of bounds.
1341    pub index: usize,
1342    /// The number of tokens in the `Pointer`.
1343    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
1365/// Validates that a sequence of bytes is a valid RFC 6901 Pointer.
1366///
1367/// # Panics
1368///
1369/// Caller must ensure the sequence is non-empty, and that offset is in range.
1370const 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; // offset within the pointer of the most recent '/' separator
1376    let mut tok_offset = 0; // offset within the current token
1377
1378    let mut i = offset;
1379    while i < bytes.len() {
1380        match bytes[i] {
1381            b'/' => {
1382                ptr_offset = i;
1383                // and reset the token offset
1384                tok_offset = 0;
1385            }
1386            b'~' => {
1387                // if the character is a '~', then the next character must be '0' or '1'
1388                // otherwise the encoding is invalid and `InvalidEncodingError` is returned
1389                if i + 1 >= bytes.len() || (bytes[i + 1] != b'0' && bytes[i + 1] != b'1') {
1390                    // the pointer is not properly encoded
1391                    //
1392                    // we use the pointer offset, which points to the last
1393                    // encountered separator, as the offset of the error.
1394                    // The source `InvalidEncodingError` then uses the token
1395                    // offset.
1396                    //
1397                    // "/foo/invalid~encoding"
1398                    //      ^       ^
1399                    //      |       |
1400                    //  ptr_offset  |
1401                    //          tok_offset
1402                    //
1403                    return Err(ParseError::InvalidEncoding {
1404                        offset: ptr_offset,
1405                        source: EncodingError {
1406                            offset: tok_offset,
1407                            source: InvalidEncoding::Tilde,
1408                        },
1409                    });
1410                }
1411                // already checked the next character, so we skip it
1412                i += 1;
1413                // incrementing the pointer offset since the next byte has
1414                // already been checked
1415                tok_offset += 1;
1416            }
1417            _ => {}
1418        }
1419        i += 1;
1420        // not a separator so we increment the token offset
1421        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        // valid separator offsets split into (head, tail)
1458        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        // offsets that don't land on a separator return None
1468        assert_eq!(ptr.split_at_offset(3), None);
1469        // offset past the end returns None rather than panicking
1470        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        // positive cases
1503        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        // negative cases
1510        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        // edge case - both root
1520        let p = Pointer::root();
1521        let q = Pointer::root();
1522        assert!(p.ends_with(q));
1523    }
1524
1525    #[test]
1526    fn starts_with() {
1527        // positive cases
1528        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        // negative cases
1535        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        // edge cases: other is root
1543        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        // full tests in resolve.rs
1798        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"])); // Ensure subjectal pointer is unchanged
1879    }
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()); // Ensure the pointer remains empty
1893    }
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    // `clippy::useless_asref` is tripping here because the `as_ref` is being
1941    // called on the same type (`&Pointer`). This is just to ensure that the
1942    // `as_ref` method is implemented correctly and stays that way.
1943    #[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            // base must be the true intersection
2120            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        // couldn't inline this
2278        #[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        // if this compiles, we're good: `unwrap_or_default` exercises
2385        // `<&Pointer as Default>::default()` and must type-check with the
2386        // borrowed lifetime (regression test for #111).
2387        #[allow(clippy::unnecessary_literal_unwrap)]
2388        fn or_default(ptr: &Pointer) -> &Pointer {
2389            Some(ptr).unwrap_or_default()
2390        }
2391        // just to satisfy codecov and clippy
2392        or_default(Pointer::root());
2393    }
2394}