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 &'static Pointer {
40    fn default() -> Self {
41        Pointer::root()
42    }
43}
44impl core::fmt::Display for Pointer {
45    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
46        self.0.fmt(f)
47    }
48}
49impl Pointer {
50    /// 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 index if the character at the index 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 indices 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(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(3), None);
231    /// ```
232    pub fn split_at(&self, offset: usize) -> Option<(&Self, &Self)> {
233        if self.0.as_bytes().get(offset).copied() != Some(b'/') {
234            return None;
235        }
236        let (head, tail) = self.0.split_at(offset);
237        // 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` into the parent path and the last `Token`.
242    pub fn split_back(&self) -> Option<(&Self, Token)> {
243        self.0.rsplit_once('/').map(|(front, back)| {
244            (
245                // SAFETY: we split at a token boundary, so front is a valid pointer
246                unsafe { Self::new_unchecked(front) },
247                // SAFETY: source token is encoded
248                unsafe { Token::from_encoded_unchecked(back) },
249            )
250        })
251    }
252
253    /// A pointer to the parent of the current path.
254    pub fn parent(&self) -> Option<&Self> {
255        // SAFETY: we split at a token boundary, so front is a valid pointer
256        self.0
257            .rsplit_once('/')
258            .map(|(front, _)| unsafe { Self::new_unchecked(front) })
259    }
260
261    /// Returns the pointer stripped of the given suffix.
262    pub fn strip_suffix<'a>(&'a self, suffix: &Self) -> Option<&'a Self> {
263        self.0
264            .strip_suffix(&suffix.0)
265            // SAFETY: the suffix is a valid pointer, so removing it from the
266            // back of another pointer will preserve token boundaries
267            .map(|s| unsafe { Self::new_unchecked(s) })
268    }
269
270    /// Returns the pointer stripped of the given prefix.
271    pub fn strip_prefix<'a>(&'a self, prefix: &Self) -> Option<&'a Self> {
272        self.0
273            .strip_prefix(&prefix.0)
274            // SAFETY: the suffix is a valid pointer, so removing it from the
275            // front of another pointer will preserve token boundaries
276            .map(|s| unsafe { Self::new_unchecked(s) })
277    }
278
279    /// Returns whether `self` has a suffix of `other`.
280    ///
281    /// Note that `Pointer::root` is only a valid suffix of itself.
282    pub fn ends_with(&self, other: &Self) -> bool {
283        (self.is_root() && other.is_root())
284            || (!other.is_root() && self.as_str().ends_with(&other.0))
285    }
286
287    /// Returns whether `self` has a prefix of `other.`
288    ///
289    /// Note that `Pointer::root` is a valid prefix of any `Pointer` (including
290    /// itself).
291    pub fn starts_with(&self, other: &Self) -> bool {
292        self.as_str().starts_with(&other.0)
293            // ensure we end at a token boundary
294            && (other.len() == self.len() || self.0.as_bytes()[other.len()] == b'/')
295    }
296
297    /// Attempts to get a `Token` by the index. Returns `None` if the index is
298    /// out of bounds.
299    ///
300    /// ## Example
301    /// ```rust
302    /// use jsonptr::{Pointer, Token};
303    ///
304    /// let ptr = Pointer::from_static("/foo/bar/qux");
305    /// assert_eq!(ptr.get(0), Some("foo".into()));
306    /// assert_eq!(ptr.get(1), Some("bar".into()));
307    /// assert_eq!(ptr.get(3), None);
308    /// assert_eq!(ptr.get(..), Some(Pointer::from_static("/foo/bar/qux")));
309    /// assert_eq!(ptr.get(..1), Some(Pointer::from_static("/foo")));
310    /// assert_eq!(ptr.get(1..3), Some(Pointer::from_static("/bar/qux")));
311    /// assert_eq!(ptr.get(1..=2), Some(Pointer::from_static("/bar/qux")));
312    ///
313    /// let ptr = Pointer::root();
314    /// assert_eq!(ptr.get(0), None);
315    /// assert_eq!(ptr.get(..), Some(Pointer::root()));
316    /// ```
317    pub fn get<'p, I>(&'p self, index: I) -> Option<I::Output>
318    where
319        I: PointerIndex<'p>,
320    {
321        index.get(self)
322    }
323
324    /// Attempts to resolve a [`R::Value`] based on the path in this [`Pointer`].
325    ///
326    /// ## Errors
327    /// Returns [`R::Error`] if an error occurs while resolving.
328    ///
329    /// The rules of such are determined by the `R`'s implementation of
330    /// [`Resolve`] but provided implementations return [`ResolveError`] if:
331    /// - The path is unreachable (e.g. a scalar is encountered prior to the end
332    ///   of the path)
333    /// - The path is not found (e.g. a key in an object or an index in an array
334    ///   does not exist)
335    /// - A [`Token`] cannot be parsed as an array [`Index`]
336    /// - An array [`Index`] is out of bounds
337    ///
338    /// [`R::Value`]: `crate::resolve::Resolve::Value`
339    /// [`R::Error`]: `crate::resolve::Resolve::Error`
340    /// [`Resolve`]: `crate::resolve::Resolve`
341    /// [`ResolveError`]: `crate::resolve::ResolveError`
342    /// [`Token`]: `crate::Token`
343    /// [`Index`]: `crate::index::Index`
344    #[cfg(feature = "resolve")]
345    pub fn resolve<'v, R: crate::Resolve>(&self, value: &'v R) -> Result<&'v R::Value, R::Error> {
346        value.resolve(self)
347    }
348
349    /// Attempts to resolve a mutable [`R::Value`] based on the path in this
350    /// `Pointer`.
351    ///
352    /// ## Errors
353    /// Returns [`R::Error`] if an error occurs while
354    /// resolving.
355    ///
356    /// The rules of such are determined by the `R`'s implementation of
357    /// [`ResolveMut`] but provided implementations return [`ResolveError`] if:
358    /// - The path is unreachable (e.g. a scalar is encountered prior to the end
359    ///   of the path)
360    /// - The path is not found (e.g. a key in an object or an index in an array
361    ///   does not exist)
362    /// - A [`Token`] cannot be parsed as an array [`Index`]
363    /// - An array [`Index`] is out of bounds
364    ///
365    /// [`R::Value`]: `crate::resolve::ResolveMut::Value`
366    /// [`R::Error`]: `crate::resolve::ResolveMut::Error`
367    /// [`ResolveMut`]: `crate::resolve::ResolveMut`
368    /// [`ResolveError`]: `crate::resolve::ResolveError`
369    /// [`Token`]: `crate::Token`
370    /// [`Index`]: `crate::index::Index`
371
372    #[cfg(feature = "resolve")]
373    pub fn resolve_mut<'v, R: crate::ResolveMut>(
374        &self,
375        value: &'v mut R,
376    ) -> Result<&'v mut R::Value, R::Error> {
377        value.resolve_mut(self)
378    }
379
380    /// Finds the commonality between this and another `Pointer`.
381    pub fn intersection<'a>(&'a self, other: &Self) -> &'a Self {
382        if self.is_root() || other.is_root() {
383            return Self::root();
384        }
385        let mut idx = 0;
386        for (a, b) in self.tokens().zip(other.tokens()) {
387            if a != b {
388                break;
389            }
390            idx += a.encoded().len() + 1;
391        }
392        self.split_at(idx).map_or(self, |(head, _)| head)
393    }
394
395    /// Attempts to delete a `serde_json::Value` based upon the path in this
396    /// `Pointer`.
397    ///
398    /// The rules of deletion are determined by the `D`'s implementation of
399    /// [`Delete`]. The supplied implementations (`"json"` & `"toml"`) operate
400    /// as follows:
401    /// - If the `Pointer` can be resolved, the `Value` is deleted and returned.
402    /// - If the `Pointer` fails to resolve for any reason, `Ok(None)` is returned.
403    /// - If the `Pointer` is root, `value` is replaced:
404    ///     - `"json"`: `serde_json::Value::Null`
405    ///     - `"toml"`: `toml::Value::Table::Default`
406    ///
407    ///
408    /// ## Examples
409    /// ### Deleting a resolved pointer:
410    /// ```rust
411    /// use jsonptr::{Pointer, delete::Delete};
412    /// use serde_json::json;
413    ///
414    /// let mut data = json!({ "foo": { "bar": { "baz": "qux" } } });
415    /// let ptr = Pointer::from_static("/foo/bar/baz");
416    /// assert_eq!(data.delete(&ptr), Some("qux".into()));
417    /// assert_eq!(data, json!({ "foo": { "bar": {} } }));
418    /// ```
419    /// ### Deleting a non-existent Pointer returns `None`:
420    /// ```rust
421    /// use jsonptr::{ Pointer, delete::Delete };
422    /// use serde_json::json;
423    ///
424    /// let mut data = json!({});
425    /// let ptr = Pointer::from_static("/foo/bar/baz");
426    /// assert_eq!(ptr.delete(&mut data), None);
427    /// assert_eq!(data, json!({}));
428    /// ```
429    /// ### Deleting a root pointer replaces the value with `Value::Null`:
430    /// ```rust
431    /// use jsonptr::{Pointer, delete::Delete};
432    /// use serde_json::json;
433    ///
434    /// let mut data = json!({ "foo": { "bar": "baz" } });
435    /// let ptr = Pointer::root();
436    /// assert_eq!(data.delete(&ptr), Some(json!({ "foo": { "bar": "baz" } })));
437    /// assert!(data.is_null());
438    /// ```
439    ///
440    /// [`Delete`]: crate::delete::Delete
441    #[cfg(feature = "delete")]
442    pub fn delete<D: crate::Delete>(&self, value: &mut D) -> Option<D::Value> {
443        value.delete(self)
444    }
445
446    /// Attempts to assign `src` to `dest` based on the path in this `Pointer`.
447    ///
448    /// If the path is partially available, the missing portions will be created. If the path
449    /// contains a zero index, such as `"/0"`, then an array will be created. Otherwise, objects
450    /// will be utilized to create the missing path.
451    ///
452    /// ## Example
453    /// ```rust
454    /// use jsonptr::Pointer;
455    /// use serde_json::{json, Value};
456    ///
457    /// let mut data = json!([]);
458    /// let mut ptr = Pointer::from_static("/0/foo");
459    /// let replaced = ptr.assign(&mut data, json!("bar")).unwrap();
460    /// assert_eq!(data, json!([{"foo": "bar"}]));
461    /// assert_eq!(replaced, None);
462    /// ```
463    ///
464    /// ## Errors
465    /// Returns [`Assign::Error`] if the path is invalid or if the value cannot be assigned.
466    ///
467    /// [`Assign::Error`]: crate::assign::Assign::Error
468    #[cfg(feature = "assign")]
469    pub fn assign<D, V>(&self, dest: &mut D, src: V) -> Result<Option<D::Value>, D::Error>
470    where
471        D: crate::Assign,
472        V: Into<D::Value>,
473    {
474        dest.assign(self, src)
475    }
476
477    /// Returns [`Components`] of this JSON Pointer.
478    ///
479    /// A [`Component`](crate::Component) is either [`Token`] or the root
480    /// location of a document.
481    /// ## Example
482    /// ```
483    /// # use jsonptr::{Component, Pointer};
484    /// let ptr = Pointer::parse("/a/b").unwrap();
485    /// let mut components = ptr.components();
486    /// assert_eq!(components.next(), Some(Component::Root));
487    /// assert_eq!(components.next(), Some(Component::Token("a".into())));
488    /// assert_eq!(components.next(), Some(Component::Token("b".into())));
489    /// assert_eq!(components.next(), None);
490    /// ```
491    pub fn components(&self) -> Components {
492        self.into()
493    }
494
495    /// Creates an owned [`PointerBuf`] like `self` but with `token` appended.
496    ///
497    /// See [`PointerBuf::push_back`] for more details.
498    ///
499    /// **Note**: this method allocates. If you find yourself calling it more
500    /// than once for a given pointer, consider using [`PointerBuf::push_back`]
501    /// instead.
502    ///
503    /// ## Examples
504    /// ```
505    /// let ptr = jsonptr::Pointer::from_static("/foo");
506    /// let foobar = ptr.with_trailing_token("bar");
507    /// assert_eq!(foobar, "/foo/bar");
508    /// ```
509    pub fn with_trailing_token<'t>(&self, token: impl Into<Token<'t>>) -> PointerBuf {
510        let mut buf = self.to_buf();
511        buf.push_back(token.into());
512        buf
513    }
514
515    /// Creates an owned [`PointerBuf`] like `self` but with `token` prepended.
516    ///
517    /// See [`PointerBuf::push_front`] for more details.
518    ///
519    /// **Note**: this method allocates. If you find yourself calling it more
520    /// than once for a given pointer, consider using [`PointerBuf::push_front`]
521    /// instead.
522    ///
523    /// ## Examples
524    /// ```
525    /// let ptr = jsonptr::Pointer::from_static("/bar");
526    /// let foobar = ptr.with_leading_token("foo");
527    /// assert_eq!(foobar, "/foo/bar");
528    /// ```
529    pub fn with_leading_token<'t>(&self, token: impl Into<Token<'t>>) -> PointerBuf {
530        let mut buf = self.to_buf();
531        buf.push_front(token);
532        buf
533    }
534
535    /// Creates an owned [`PointerBuf`] like `self` but with `other` appended to
536    /// the end.
537    ///
538    /// See [`PointerBuf::append`] for more details.
539    ///
540    /// **Note**: this method allocates. If you find yourself calling it more
541    /// than  given pointer, consider using [`PointerBuf::append`]
542    /// instead.
543    ///
544    /// ## Examples
545    /// ```
546    /// let ptr = jsonptr::Pointer::from_static("/foo");
547    /// let other = jsonptr::Pointer::from_static("/bar/baz");
548    /// assert_eq!(ptr.concat(other), "/foo/bar/baz");
549    /// ```
550    pub fn concat(&self, other: &Pointer) -> PointerBuf {
551        let mut buf = self.to_buf();
552        buf.append(other);
553        buf
554    }
555
556    //  Returns the length of `self` in encoded format.
557    ///
558    /// This length expresses the byte count of the underlying string that
559    /// represents the RFC 6091 Pointer. See also [`std::str::len`].
560    ///
561    /// ## Examples
562    /// ```
563    /// let mut ptr = jsonptr::PointerBuf::parse("/foo/bar").unwrap();
564    /// assert_eq!(ptr.len(), 8);
565    ///
566    /// ptr.push_back("~");
567    /// assert_eq!(ptr.len(), 11);
568    ///
569    /// ```
570    pub fn len(&self) -> usize {
571        self.0.len()
572    }
573
574    /// Returns `true` if the `Pointer` is empty (i.e. root).    
575    ///
576    /// ## Examples
577    /// ```
578    /// let mut ptr = jsonptr::PointerBuf::new();
579    /// assert!(ptr.is_empty());
580    ///
581    /// ptr.push_back("foo");
582    /// assert!(!ptr.is_empty());
583    /// ```
584    pub fn is_empty(&self) -> bool {
585        self.0.is_empty()
586    }
587
588    /// Converts a `Box<Pointer>` into a `PointerBuf` without copying or allocating.
589    pub fn into_buf(self: Box<Pointer>) -> PointerBuf {
590        let inner = Box::into_raw(self);
591        // SAFETY: we ensure the layout of `Pointer` is the same as `str`
592        let inner = unsafe { Box::<str>::from_raw(inner as *mut str) };
593        PointerBuf(inner.into_string())
594    }
595}
596
597#[cfg(feature = "serde")]
598impl serde::Serialize for Pointer {
599    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
600    where
601        S: serde::Serializer,
602    {
603        <str>::serialize(&self.0, serializer)
604    }
605}
606
607#[cfg(feature = "serde")]
608impl<'de: 'p, 'p> serde::Deserialize<'de> for &'p Pointer {
609    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
610    where
611        D: serde::Deserializer<'de>,
612    {
613        use serde::de::{Error, Visitor};
614
615        struct PointerVisitor;
616
617        impl<'a> Visitor<'a> for PointerVisitor {
618            type Value = &'a Pointer;
619
620            fn expecting(&self, formatter: &mut core::fmt::Formatter) -> core::fmt::Result {
621                formatter.write_str("a borrowed Pointer")
622            }
623
624            fn visit_borrowed_str<E>(self, v: &'a str) -> Result<Self::Value, E>
625            where
626                E: Error,
627            {
628                Pointer::parse(v).map_err(|err| {
629                    Error::custom(format!("failed to parse json pointer\n\ncaused by:\n{err}"))
630                })
631            }
632        }
633
634        deserializer.deserialize_str(PointerVisitor)
635    }
636}
637
638macro_rules! impl_source_code {
639    ($($ty:ty),+) => {
640        $(
641            #[cfg(feature = "miette")]
642            impl miette::SourceCode for $ty {
643                fn read_span<'a>(
644                    &'a self,
645                    span: &miette::SourceSpan,
646                    context_lines_before: usize,
647                    context_lines_after: usize,
648                ) -> Result<Box<dyn miette::SpanContents<'a> + 'a>, miette::MietteError> {
649                    miette::SourceCode::read_span(
650                        self.0.as_bytes(),
651                        span,
652                        context_lines_before,
653                        context_lines_after,
654                    )
655                }
656            }
657        )*
658    };
659}
660
661impl_source_code!(Pointer, &Pointer, PointerBuf);
662
663impl<'p> From<&'p Pointer> for Cow<'p, Pointer> {
664    fn from(value: &'p Pointer) -> Self {
665        Cow::Borrowed(value)
666    }
667}
668
669impl ToOwned for Pointer {
670    type Owned = PointerBuf;
671
672    fn to_owned(&self) -> Self::Owned {
673        self.to_buf()
674    }
675}
676
677impl PartialEq<&str> for Pointer {
678    fn eq(&self, other: &&str) -> bool {
679        &&self.0 == other
680    }
681}
682impl<'p> PartialEq<String> for &'p Pointer {
683    fn eq(&self, other: &String) -> bool {
684        self.0.eq(other)
685    }
686}
687impl PartialEq<str> for Pointer {
688    fn eq(&self, other: &str) -> bool {
689        &self.0 == other
690    }
691}
692
693impl PartialEq<Pointer> for &str {
694    fn eq(&self, other: &Pointer) -> bool {
695        *self == (&other.0)
696    }
697}
698
699impl PartialEq<Pointer> for String {
700    fn eq(&self, other: &Pointer) -> bool {
701        self == &other.0
702    }
703}
704
705impl PartialEq<Pointer> for str {
706    fn eq(&self, other: &Pointer) -> bool {
707        self == &other.0
708    }
709}
710
711impl PartialEq<String> for Pointer {
712    fn eq(&self, other: &String) -> bool {
713        &self.0 == other
714    }
715}
716
717impl PartialEq<PointerBuf> for Pointer {
718    fn eq(&self, other: &PointerBuf) -> bool {
719        self.0 == other.0
720    }
721}
722
723impl PartialEq<Pointer> for PointerBuf {
724    fn eq(&self, other: &Pointer) -> bool {
725        self.0 == other.0
726    }
727}
728impl PartialEq<PointerBuf> for String {
729    fn eq(&self, other: &PointerBuf) -> bool {
730        self == &other.0
731    }
732}
733impl PartialEq<String> for PointerBuf {
734    fn eq(&self, other: &String) -> bool {
735        &self.0 == other
736    }
737}
738
739impl PartialEq<PointerBuf> for str {
740    fn eq(&self, other: &PointerBuf) -> bool {
741        self == other.0
742    }
743}
744impl PartialEq<PointerBuf> for &str {
745    fn eq(&self, other: &PointerBuf) -> bool {
746        *self == other.0
747    }
748}
749
750impl AsRef<Pointer> for Pointer {
751    fn as_ref(&self) -> &Pointer {
752        self
753    }
754}
755impl AsRef<Pointer> for PointerBuf {
756    fn as_ref(&self) -> &Pointer {
757        self
758    }
759}
760
761impl PartialEq<PointerBuf> for &Pointer {
762    fn eq(&self, other: &PointerBuf) -> bool {
763        self.0 == other.0
764    }
765}
766
767impl PartialEq<&Pointer> for PointerBuf {
768    fn eq(&self, other: &&Pointer) -> bool {
769        self.0 == other.0
770    }
771}
772
773#[cfg(feature = "json")]
774impl From<&Pointer> for serde_json::Value {
775    fn from(ptr: &Pointer) -> Self {
776        ptr.to_json_value()
777    }
778}
779
780impl AsRef<str> for Pointer {
781    fn as_ref(&self) -> &str {
782        &self.0
783    }
784}
785
786impl Borrow<str> for Pointer {
787    fn borrow(&self) -> &str {
788        &self.0
789    }
790}
791
792impl AsRef<[u8]> for Pointer {
793    fn as_ref(&self) -> &[u8] {
794        self.0.as_bytes()
795    }
796}
797
798impl PartialOrd<PointerBuf> for Pointer {
799    fn partial_cmp(&self, other: &PointerBuf) -> Option<Ordering> {
800        self.0.partial_cmp(other.0.as_str())
801    }
802}
803
804impl PartialOrd<Pointer> for PointerBuf {
805    fn partial_cmp(&self, other: &Pointer) -> Option<Ordering> {
806        self.0.as_str().partial_cmp(&other.0)
807    }
808}
809impl PartialOrd<&Pointer> for PointerBuf {
810    fn partial_cmp(&self, other: &&Pointer) -> Option<Ordering> {
811        self.0.as_str().partial_cmp(&other.0)
812    }
813}
814
815impl PartialOrd<Pointer> for String {
816    fn partial_cmp(&self, other: &Pointer) -> Option<Ordering> {
817        self.as_str().partial_cmp(&other.0)
818    }
819}
820impl PartialOrd<String> for &Pointer {
821    fn partial_cmp(&self, other: &String) -> Option<Ordering> {
822        self.0.partial_cmp(other.as_str())
823    }
824}
825
826impl PartialOrd<PointerBuf> for String {
827    fn partial_cmp(&self, other: &PointerBuf) -> Option<Ordering> {
828        self.as_str().partial_cmp(other.0.as_str())
829    }
830}
831
832impl PartialOrd<Pointer> for str {
833    fn partial_cmp(&self, other: &Pointer) -> Option<Ordering> {
834        self.partial_cmp(&other.0)
835    }
836}
837
838impl PartialOrd<PointerBuf> for str {
839    fn partial_cmp(&self, other: &PointerBuf) -> Option<Ordering> {
840        self.partial_cmp(other.0.as_str())
841    }
842}
843impl PartialOrd<PointerBuf> for &str {
844    fn partial_cmp(&self, other: &PointerBuf) -> Option<Ordering> {
845        (*self).partial_cmp(other.0.as_str())
846    }
847}
848impl PartialOrd<Pointer> for &str {
849    fn partial_cmp(&self, other: &Pointer) -> Option<Ordering> {
850        (*self).partial_cmp(&other.0)
851    }
852}
853
854impl PartialOrd<&str> for &Pointer {
855    fn partial_cmp(&self, other: &&str) -> Option<Ordering> {
856        PartialOrd::partial_cmp(&self.0[..], &other[..])
857    }
858}
859
860impl PartialOrd<String> for Pointer {
861    fn partial_cmp(&self, other: &String) -> Option<Ordering> {
862        self.0.partial_cmp(other.as_str())
863    }
864}
865
866impl PartialOrd<&str> for PointerBuf {
867    fn partial_cmp(&self, other: &&str) -> Option<Ordering> {
868        PartialOrd::partial_cmp(&self.0[..], &other[..])
869    }
870}
871
872impl<'p> PartialOrd<PointerBuf> for &'p Pointer {
873    fn partial_cmp(&self, other: &PointerBuf) -> Option<Ordering> {
874        self.0.partial_cmp(other.0.as_str())
875    }
876}
877
878impl PartialOrd<String> for PointerBuf {
879    fn partial_cmp(&self, other: &String) -> Option<Ordering> {
880        self.0.partial_cmp(other)
881    }
882}
883
884impl<'a> IntoIterator for &'a Pointer {
885    type Item = Token<'a>;
886    type IntoIter = Tokens<'a>;
887    fn into_iter(self) -> Self::IntoIter {
888        self.tokens()
889    }
890}
891
892/// An owned, mutable [`Pointer`] (akin to `String`).
893///
894/// This type provides methods like [`PointerBuf::push_back`] and
895/// [`PointerBuf::replace`] that mutate the pointer in place. It also
896/// implements [`core::ops::Deref`] to [`Pointer`], meaning that all methods on
897/// [`Pointer`] slices are available on `PointerBuf` values as well.
898#[derive(Clone, Default, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
899pub struct PointerBuf(String);
900
901impl PointerBuf {
902    /// Creates a new `PointerBuf` pointing to a document root.
903    ///
904    /// This is an alias to [`Self::new`].
905    pub fn root() -> Self {
906        Self::new()
907    }
908
909    /// Creates a new `PointerBuf` pointing to a document root.
910    pub fn new() -> Self {
911        Self(String::new())
912    }
913
914    /// Create a `PointerBuf` from a string that is known to be correctly encoded.
915    ///
916    /// ## Safety
917    /// The provided string must adhere to RFC 6901.
918    pub unsafe fn new_unchecked(s: impl Into<String>) -> Self {
919        Self(s.into())
920    }
921
922    /// Attempts to parse a string into a `PointerBuf`.
923    ///
924    /// ## Errors
925    /// Returns a [`RichParseError`] if the string is not a valid JSON Pointer.
926    pub fn parse(s: impl Into<String>) -> Result<Self, RichParseError> {
927        let s = s.into();
928        match validate(&s) {
929            Ok(_) => Ok(Self(s)),
930            Err(err) => Err(err.into_report(s)),
931        }
932    }
933
934    /// Creates a new `PointerBuf` from a slice of non-encoded strings.
935    pub fn from_tokens<'t>(tokens: impl IntoIterator<Item: Into<Token<'t>>>) -> Self {
936        let mut inner = String::new();
937        for t in tokens.into_iter().map(Into::into) {
938            inner.push('/');
939            inner.push_str(t.encoded());
940        }
941        PointerBuf(inner)
942    }
943
944    /// Coerces to a Pointer slice.
945    pub fn as_ptr(&self) -> &Pointer {
946        self
947    }
948
949    /// Pushes a `Token` onto the front of this `Pointer`.
950    pub fn push_front<'t>(&mut self, token: impl Into<Token<'t>>) {
951        self.0.insert(0, '/');
952        self.0.insert_str(1, token.into().encoded());
953    }
954
955    /// Pushes a `Token` onto the back of this `Pointer`.
956    pub fn push_back<'t>(&mut self, token: impl Into<Token<'t>>) {
957        self.0.push('/');
958        self.0.push_str(token.into().encoded());
959    }
960
961    /// Removes and returns the last `Token` in the `Pointer` if it exists.
962    pub fn pop_back(&mut self) -> Option<Token<'static>> {
963        if let Some(idx) = self.0.rfind('/') {
964            // SAFETY: source pointer is encoded
965            let back = unsafe { Token::from_encoded_unchecked(self.0.split_off(idx + 1)) };
966            self.0.pop(); // remove trailing `/`
967            Some(back)
968        } else {
969            None
970        }
971    }
972
973    /// Removes and returns the first `Token` in the `Pointer` if it exists.
974    pub fn pop_front(&mut self) -> Option<Token<'static>> {
975        (!self.is_root()).then(|| {
976            // if not root, must contain at least one `/`
977            let mut token = if let Some(idx) = self.0[1..].find('/') {
978                let token = self.0.split_off(idx + 1);
979                core::mem::replace(&mut self.0, token)
980            } else {
981                core::mem::take(&mut self.0)
982            };
983            // remove leading `/`
984            token.remove(0);
985            // SAFETY: source pointer is encoded
986            unsafe { Token::from_encoded_unchecked(token) }
987        })
988    }
989
990    /// Merges two `Pointer`s by appending `other` onto `self`.
991    pub fn append<P: AsRef<Pointer>>(&mut self, other: P) -> &PointerBuf {
992        let other = other.as_ref();
993        if self.is_root() {
994            self.0 = other.0.to_string();
995        } else if !other.is_root() {
996            self.0.push_str(&other.0);
997        }
998        self
999    }
1000
1001    /// Attempts to replace a `Token` by the index, returning the replaced
1002    /// `Token` if it already exists. Returns `None` otherwise.
1003    ///
1004    /// ## Errors
1005    /// A [`ReplaceError`] is returned if the index is out of bounds.
1006    pub fn replace<'t>(
1007        &mut self,
1008        index: usize,
1009        token: impl Into<Token<'t>>,
1010    ) -> Result<Option<Token>, ReplaceError> {
1011        if self.is_root() {
1012            return Err(ReplaceError {
1013                count: self.count(),
1014                index,
1015            });
1016        }
1017        let mut tokens = self.tokens().collect::<Vec<_>>();
1018        if index >= tokens.len() {
1019            return Err(ReplaceError {
1020                count: tokens.len(),
1021                index,
1022            });
1023        }
1024        let old = tokens.get(index).map(super::token::Token::to_owned);
1025        tokens[index] = token.into();
1026
1027        let mut buf = String::new();
1028        for token in tokens {
1029            buf.push('/');
1030            buf.push_str(token.encoded());
1031        }
1032        self.0 = buf;
1033
1034        Ok(old)
1035    }
1036
1037    /// Clears the `Pointer`, setting it to root (`""`).
1038    pub fn clear(&mut self) {
1039        self.0.clear();
1040    }
1041}
1042
1043impl FromStr for PointerBuf {
1044    type Err = ParseError;
1045    fn from_str(s: &str) -> Result<Self, Self::Err> {
1046        Self::try_from(s)
1047    }
1048}
1049
1050impl Borrow<Pointer> for PointerBuf {
1051    fn borrow(&self) -> &Pointer {
1052        self.as_ptr()
1053    }
1054}
1055
1056impl Deref for PointerBuf {
1057    type Target = Pointer;
1058    fn deref(&self) -> &Self::Target {
1059        // SAFETY: we hold a valid pointer
1060        unsafe { Pointer::new_unchecked(self.0.as_str()) }
1061    }
1062}
1063
1064impl From<PointerBuf> for Box<Pointer> {
1065    fn from(value: PointerBuf) -> Self {
1066        let s = value.0.into_boxed_str();
1067        // SAFETY: we ensure that the layout of `str` is the same as `Pointer`
1068        unsafe { Box::from_raw(Box::into_raw(s) as *mut Pointer) }
1069    }
1070}
1071
1072#[cfg(feature = "serde")]
1073impl<'de> serde::Deserialize<'de> for PointerBuf {
1074    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
1075    where
1076        D: serde::Deserializer<'de>,
1077    {
1078        use serde::de::Error;
1079        let s = String::deserialize(deserializer)?;
1080        PointerBuf::try_from(s).map_err(D::Error::custom)
1081    }
1082}
1083
1084#[cfg(feature = "serde")]
1085impl serde::Serialize for PointerBuf {
1086    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
1087    where
1088        S: serde::Serializer,
1089    {
1090        String::serialize(&self.0, serializer)
1091    }
1092}
1093
1094impl From<PointerBuf> for Cow<'static, Pointer> {
1095    fn from(value: PointerBuf) -> Self {
1096        Cow::Owned(value)
1097    }
1098}
1099
1100impl From<Token<'_>> for PointerBuf {
1101    fn from(t: Token) -> Self {
1102        PointerBuf::from_tokens([t])
1103    }
1104}
1105
1106impl TryFrom<String> for PointerBuf {
1107    type Error = ParseError;
1108    fn try_from(value: String) -> Result<Self, Self::Error> {
1109        let _ = validate(&value)?;
1110        Ok(Self(value))
1111    }
1112}
1113
1114impl From<usize> for PointerBuf {
1115    fn from(value: usize) -> Self {
1116        PointerBuf::from_tokens([value])
1117    }
1118}
1119
1120impl<'a> IntoIterator for &'a PointerBuf {
1121    type Item = Token<'a>;
1122    type IntoIter = Tokens<'a>;
1123    fn into_iter(self) -> Self::IntoIter {
1124        self.tokens()
1125    }
1126}
1127
1128impl TryFrom<&str> for PointerBuf {
1129    type Error = ParseError;
1130    fn try_from(value: &str) -> Result<Self, Self::Error> {
1131        Pointer::parse(value).map(Pointer::to_buf)
1132    }
1133}
1134
1135impl PartialEq<&str> for PointerBuf {
1136    fn eq(&self, other: &&str) -> bool {
1137        &self.0 == other
1138    }
1139}
1140
1141impl PartialEq<str> for PointerBuf {
1142    fn eq(&self, other: &str) -> bool {
1143        self.0 == other
1144    }
1145}
1146
1147impl core::fmt::Display for PointerBuf {
1148    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
1149        self.0.fmt(f)
1150    }
1151}
1152
1153/// Indicates that a [`Pointer`] was unable to be parsed due to not containing
1154/// a leading slash (`'/'`).
1155#[derive(Debug, PartialEq, Eq, Clone, Copy)]
1156pub struct NoLeadingSlash;
1157
1158impl fmt::Display for NoLeadingSlash {
1159    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1160        write!(
1161            f,
1162            "json pointer must start with a slash ('/') and is not empty"
1163        )
1164    }
1165}
1166
1167/// Indicates that a `Pointer` was malformed and unable to be parsed.
1168#[derive(Debug, PartialEq)]
1169pub enum ParseError {
1170    /// `Pointer` did not start with a slash (`'/'`).
1171    NoLeadingSlash,
1172
1173    /// `Pointer` contained invalid encoding (e.g. `~` not followed by `0` or
1174    /// `1`).
1175    InvalidEncoding {
1176        /// Offset of the partial pointer starting with the token that contained
1177        /// the invalid encoding
1178        offset: usize,
1179        /// The source `InvalidEncodingError`
1180        source: EncodingError,
1181    },
1182}
1183
1184impl ParseError {
1185    /// Offset of the partial pointer starting with the token that contained the
1186    /// invalid encoding
1187    pub fn offset(&self) -> usize {
1188        match self {
1189            Self::NoLeadingSlash => 0,
1190            Self::InvalidEncoding { offset, .. } => *offset,
1191        }
1192    }
1193    /// Length of the invalid encoding
1194    pub fn invalid_encoding_len(&self, subject: &str) -> usize {
1195        match self {
1196            Self::NoLeadingSlash => 0,
1197            Self::InvalidEncoding { offset, .. } => {
1198                if *offset < subject.len() - 1 {
1199                    2
1200                } else {
1201                    1
1202                }
1203            }
1204        }
1205    }
1206}
1207
1208impl Diagnostic for ParseError {
1209    type Subject = String;
1210
1211    fn url() -> &'static str {
1212        diagnostic_url!(struct ParseError)
1213    }
1214
1215    fn labels(&self, subject: &Self::Subject) -> Option<Box<dyn Iterator<Item = Label>>> {
1216        let offset = self.complete_offset();
1217        let len = self.invalid_encoding_len(subject);
1218        let text = match self {
1219            ParseError::NoLeadingSlash => "must start with a slash ('/')",
1220            ParseError::InvalidEncoding { .. } => "'~' must be followed by '0' or '1'",
1221        }
1222        .to_string();
1223        Some(Box::new(once(Label::new(text, offset, len))))
1224    }
1225}
1226
1227#[cfg(feature = "miette")]
1228impl miette::Diagnostic for ParseError {}
1229
1230impl fmt::Display for ParseError {
1231    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1232        match self {
1233            Self::NoLeadingSlash { .. } => {
1234                write!(
1235                    f,
1236                    "json pointer failed to parse; does not start with a slash ('/') and is not empty"
1237                )
1238            }
1239            Self::InvalidEncoding { offset, .. } => {
1240                write!(
1241                    f,
1242                    "json pointer failed to parse; the first token in the partial-pointer starting at offset {offset} is malformed"
1243                )
1244            }
1245        }
1246    }
1247}
1248
1249impl ParseError {
1250    #[deprecated(note = "renamed to `is_no_leading_slash`", since = "0.7.0")]
1251    /// Returns `true` if this error is `NoLeadingSlash`
1252    pub fn is_no_leading_backslash(&self) -> bool {
1253        matches!(self, Self::NoLeadingSlash { .. })
1254    }
1255
1256    /// Returns `true` if this error is `NoLeadingSlash`
1257    pub fn is_no_leading_slash(&self) -> bool {
1258        matches!(self, Self::NoLeadingSlash { .. })
1259    }
1260
1261    /// Returns `true` if this error is `InvalidEncoding`    
1262    pub fn is_invalid_encoding(&self) -> bool {
1263        matches!(self, Self::InvalidEncoding { .. })
1264    }
1265
1266    /// Offset of the partial pointer starting with the token which caused the error.
1267    ///
1268    /// ```text
1269    /// "/foo/invalid~tilde/invalid"
1270    ///      ↑
1271    /// ```
1272    ///
1273    /// ```
1274    /// # use jsonptr::PointerBuf;
1275    /// let err = PointerBuf::parse("/foo/invalid~tilde/invalid").unwrap_err();
1276    /// assert_eq!(err.pointer_offset(), 4)
1277    /// ```
1278    pub fn pointer_offset(&self) -> usize {
1279        match *self {
1280            Self::NoLeadingSlash { .. } => 0,
1281            Self::InvalidEncoding { offset, .. } => offset,
1282        }
1283    }
1284
1285    /// Offset of the character index from within the first token of
1286    /// [`Self::pointer_offset`])
1287    ///
1288    /// ```text
1289    /// "/foo/invalid~tilde/invalid"
1290    ///              ↑
1291    ///              8
1292    /// ```
1293    /// ```
1294    /// # use jsonptr::PointerBuf;
1295    /// let err = PointerBuf::parse("/foo/invalid~tilde/invalid").unwrap_err();
1296    /// assert_eq!(err.source_offset(), 8)
1297    /// ```
1298    pub fn source_offset(&self) -> usize {
1299        match self {
1300            Self::NoLeadingSlash { .. } => 0,
1301            Self::InvalidEncoding { source, .. } => source.offset,
1302        }
1303    }
1304
1305    /// Offset of the first invalid encoding from within the pointer.
1306    /// ```text
1307    /// "/foo/invalid~tilde/invalid"
1308    ///              ↑
1309    ///             12
1310    /// ```
1311    /// ```
1312    /// use jsonptr::PointerBuf;
1313    /// let err = PointerBuf::parse("/foo/invalid~tilde/invalid").unwrap_err();
1314    /// assert_eq!(err.complete_offset(), 12)
1315    /// ```
1316    pub fn complete_offset(&self) -> usize {
1317        self.source_offset() + self.pointer_offset()
1318    }
1319}
1320
1321#[cfg(feature = "std")]
1322impl std::error::Error for ParseError {
1323    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
1324        match self {
1325            Self::InvalidEncoding { source, .. } => Some(source),
1326            Self::NoLeadingSlash => None,
1327        }
1328    }
1329}
1330
1331/// A rich error type that includes the original string that failed to parse.
1332pub type RichParseError = Report<ParseError>;
1333
1334/// Returned from [`PointerBuf::replace`] when the provided index is out of
1335/// bounds.
1336#[derive(Debug, PartialEq, Eq)]
1337pub struct ReplaceError {
1338    /// The index of the token that was out of bounds.
1339    pub index: usize,
1340    /// The number of tokens in the `Pointer`.
1341    pub count: usize,
1342}
1343
1344impl fmt::Display for ReplaceError {
1345    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1346        write!(f, "index {} is out of bounds ({})", self.index, self.count)
1347    }
1348}
1349
1350#[cfg(feature = "std")]
1351impl std::error::Error for ReplaceError {}
1352
1353const fn validate(value: &str) -> Result<&str, ParseError> {
1354    if value.is_empty() {
1355        return Ok(value);
1356    }
1357    if let Err(err) = validate_bytes(value.as_bytes(), 0) {
1358        return Err(err);
1359    }
1360    Ok(value)
1361}
1362
1363const fn validate_bytes(bytes: &[u8], offset: usize) -> Result<(), ParseError> {
1364    if bytes[0] != b'/' && offset == 0 {
1365        return Err(ParseError::NoLeadingSlash);
1366    }
1367
1368    let mut ptr_offset = offset; // offset within the pointer of the most recent '/' separator
1369    let mut tok_offset = 0; // offset within the current token
1370
1371    let mut i = offset;
1372    while i < bytes.len() {
1373        match bytes[i] {
1374            b'/' => {
1375                ptr_offset = i;
1376                // and reset the token offset
1377                tok_offset = 0;
1378            }
1379            b'~' => {
1380                // if the character is a '~', then the next character must be '0' or '1'
1381                // otherwise the encoding is invalid and `InvalidEncodingError` is returned
1382                if i + 1 >= bytes.len() || (bytes[i + 1] != b'0' && bytes[i + 1] != b'1') {
1383                    // the pointer is not properly encoded
1384                    //
1385                    // we use the pointer offset, which points to the last
1386                    // encountered separator, as the offset of the error.
1387                    // The source `InvalidEncodingError` then uses the token
1388                    // offset.
1389                    //
1390                    // "/foo/invalid~encoding"
1391                    //      ^       ^
1392                    //      |       |
1393                    //  ptr_offset  |
1394                    //          tok_offset
1395                    //
1396                    return Err(ParseError::InvalidEncoding {
1397                        offset: ptr_offset,
1398                        source: EncodingError {
1399                            offset: tok_offset,
1400                            source: InvalidEncoding::Tilde,
1401                        },
1402                    });
1403                }
1404                // already checked the next character, so we skip it
1405                i += 1;
1406                // incrementing the pointer offset since the next byte has
1407                // already been checked
1408                tok_offset += 1;
1409            }
1410            _ => {}
1411        }
1412        i += 1;
1413        // not a separator so we increment the token offset
1414        tok_offset += 1;
1415    }
1416    Ok(())
1417}
1418
1419#[cfg(test)]
1420mod tests {
1421    use std::error::Error;
1422
1423    use super::*;
1424    use quickcheck::TestResult;
1425    use quickcheck_macros::quickcheck;
1426
1427    #[test]
1428    #[should_panic = "invalid json pointer"]
1429    fn from_const_validates() {
1430        let _ = Pointer::from_static("foo/bar");
1431    }
1432
1433    #[test]
1434    fn root_is_alias_of_new_pathbuf() {
1435        assert_eq!(PointerBuf::root(), PointerBuf::new());
1436    }
1437
1438    #[test]
1439    fn from_unchecked_pathbuf() {
1440        let s = "/foo/bar/0";
1441        assert_eq!(
1442            unsafe { PointerBuf::new_unchecked(String::from(s)) },
1443            PointerBuf::parse(s).unwrap()
1444        );
1445    }
1446
1447    #[test]
1448    fn strip_suffix() {
1449        let p = Pointer::from_static("/example/pointer/to/some/value");
1450        let stripped = p
1451            .strip_suffix(Pointer::from_static("/to/some/value"))
1452            .unwrap();
1453        assert_eq!(stripped, "/example/pointer");
1454    }
1455
1456    #[test]
1457    fn strip_prefix() {
1458        let p = Pointer::from_static("/example/pointer/to/some/value");
1459        let stripped = p
1460            .strip_prefix(Pointer::from_static("/example/pointer"))
1461            .unwrap();
1462        assert_eq!(stripped, "/to/some/value");
1463    }
1464
1465    #[test]
1466    fn ends_with() {
1467        // positive cases
1468        let p = Pointer::from_static("/foo/bar");
1469        let q = Pointer::from_static("/bar");
1470        assert!(p.ends_with(q));
1471        let q = Pointer::from_static("/foo/bar");
1472        assert!(p.ends_with(q));
1473
1474        // negative cases
1475        let q = Pointer::from_static("/barz");
1476        assert!(!p.ends_with(q));
1477        let q = Pointer::from_static("/");
1478        assert!(!p.ends_with(q));
1479        let q = Pointer::from_static("");
1480        assert!(!p.ends_with(q));
1481        let q = Pointer::from_static("/qux/foo/bar");
1482        assert!(!p.ends_with(q));
1483
1484        // edge case - both root
1485        let p = Pointer::root();
1486        let q = Pointer::root();
1487        assert!(p.ends_with(q));
1488    }
1489
1490    #[test]
1491    fn starts_with() {
1492        // positive cases
1493        let p = Pointer::from_static("/foo/bar");
1494        let q = Pointer::from_static("/foo");
1495        assert!(p.starts_with(q));
1496        let q = Pointer::from_static("/foo/bar");
1497        assert!(p.starts_with(q));
1498
1499        // negative cases
1500        let q = Pointer::from_static("/");
1501        assert!(!p.starts_with(q));
1502        let q = Pointer::from_static("/fo");
1503        assert!(!p.starts_with(q));
1504        let q = Pointer::from_static("/foo/");
1505        assert!(!p.starts_with(q));
1506
1507        // edge cases: other is root
1508        let p = Pointer::root();
1509        let q = Pointer::root();
1510        assert!(p.starts_with(q));
1511        let p = Pointer::from_static("/");
1512        assert!(p.starts_with(q));
1513        let p = Pointer::from_static("/any/thing");
1514        assert!(p.starts_with(q));
1515    }
1516
1517    #[test]
1518    fn parse() {
1519        let tests = [
1520            ("", Ok("")),
1521            ("/", Ok("/")),
1522            ("/foo", Ok("/foo")),
1523            ("/foo/bar", Ok("/foo/bar")),
1524            ("/foo/bar/baz", Ok("/foo/bar/baz")),
1525            ("/foo/bar/baz/~0", Ok("/foo/bar/baz/~0")),
1526            ("/foo/bar/baz/~1", Ok("/foo/bar/baz/~1")),
1527            ("/foo/bar/baz/~01", Ok("/foo/bar/baz/~01")),
1528            ("/foo/bar/baz/~10", Ok("/foo/bar/baz/~10")),
1529            ("/foo/bar/baz/~11", Ok("/foo/bar/baz/~11")),
1530            ("/foo/bar/baz/~1/~0", Ok("/foo/bar/baz/~1/~0")),
1531            ("missing-slash", Err(ParseError::NoLeadingSlash)),
1532            (
1533                "/~",
1534                Err(ParseError::InvalidEncoding {
1535                    offset: 0,
1536                    source: EncodingError {
1537                        offset: 1,
1538                        source: InvalidEncoding::Tilde,
1539                    },
1540                }),
1541            ),
1542            (
1543                "/~2",
1544                Err(ParseError::InvalidEncoding {
1545                    offset: 0,
1546                    source: EncodingError {
1547                        offset: 1,
1548                        source: InvalidEncoding::Tilde,
1549                    },
1550                }),
1551            ),
1552            (
1553                "/~a",
1554                Err(ParseError::InvalidEncoding {
1555                    offset: 0,
1556                    source: EncodingError {
1557                        offset: 1,
1558                        source: InvalidEncoding::Tilde,
1559                    },
1560                }),
1561            ),
1562        ];
1563        for (input, expected) in tests {
1564            let actual = Pointer::parse(input).map(Pointer::as_str);
1565            assert_eq!(actual, expected);
1566        }
1567    }
1568
1569    #[test]
1570    fn parse_error_offsets() {
1571        let err = Pointer::parse("/foo/invalid~encoding").unwrap_err();
1572        assert_eq!(err.pointer_offset(), 4);
1573        assert_eq!(err.source_offset(), 8);
1574        assert_eq!(err.complete_offset(), 12);
1575
1576        let err = Pointer::parse("invalid~encoding").unwrap_err();
1577        assert_eq!(err.pointer_offset(), 0);
1578        assert_eq!(err.source_offset(), 0);
1579
1580        let err = Pointer::parse("no-leading/slash").unwrap_err();
1581        assert!(err.source().is_none());
1582    }
1583
1584    #[test]
1585    fn pointer_buf_clear() {
1586        let mut ptr = PointerBuf::from_tokens(["foo", "bar"]);
1587        ptr.clear();
1588        assert_eq!(ptr, "");
1589    }
1590
1591    #[test]
1592    fn push_pop_back() {
1593        let mut ptr = PointerBuf::default();
1594        assert_eq!(ptr, "", "default, root pointer should equal \"\"");
1595        assert_eq!(ptr.count(), 0, "default pointer should have 0 tokens");
1596
1597        ptr.push_back("foo");
1598        assert_eq!(ptr, "/foo", "pointer should equal \"/foo\" after push_back");
1599
1600        ptr.push_back("bar");
1601        assert_eq!(ptr, "/foo/bar");
1602        ptr.push_back("/baz");
1603        assert_eq!(ptr, "/foo/bar/~1baz");
1604
1605        let mut ptr = PointerBuf::from_tokens(["foo", "bar"]);
1606        assert_eq!(ptr.pop_back(), Some("bar".into()));
1607        assert_eq!(ptr, "/foo", "pointer should equal \"/foo\" after pop_back");
1608        assert_eq!(ptr.pop_back(), Some("foo".into()));
1609        assert_eq!(ptr, "", "pointer should equal \"\" after pop_back");
1610    }
1611
1612    #[test]
1613    fn replace_token() {
1614        let mut ptr = PointerBuf::try_from("/test/token").unwrap();
1615
1616        let res = ptr.replace(0, "new");
1617        assert!(res.is_ok());
1618        assert_eq!(ptr, "/new/token");
1619
1620        let res = ptr.replace(3, "invalid");
1621
1622        assert!(res.is_err());
1623    }
1624
1625    #[test]
1626    fn push_pop_front() {
1627        let mut ptr = PointerBuf::default();
1628        assert_eq!(ptr, "");
1629        assert_eq!(ptr.count(), 0);
1630        ptr.push_front("bar");
1631        assert_eq!(ptr, "/bar");
1632        assert_eq!(ptr.count(), 1);
1633
1634        ptr.push_front("foo");
1635        assert_eq!(ptr, "/foo/bar");
1636        assert_eq!(ptr.count(), 2);
1637
1638        ptr.push_front("too");
1639        assert_eq!(ptr, "/too/foo/bar");
1640        assert_eq!(ptr.count(), 3);
1641
1642        assert_eq!(ptr.pop_front(), Some("too".into()));
1643        assert_eq!(ptr, "/foo/bar");
1644        assert_eq!(ptr.count(), 2);
1645
1646        assert_eq!(ptr.pop_back(), Some("bar".into()));
1647        assert_eq!(ptr, "/foo");
1648        assert_eq!(ptr.count(), 1);
1649        assert_eq!(ptr.pop_front(), Some("foo".into()));
1650        assert_eq!(ptr, "");
1651    }
1652
1653    #[test]
1654    fn pop_front_works_with_empty_strings() {
1655        {
1656            let mut ptr = PointerBuf::from_tokens(["bar", "", ""]);
1657
1658            assert_eq!(ptr.tokens().count(), 3);
1659            let mut token = ptr.pop_front();
1660            assert_eq!(token, Some(Token::new("bar")));
1661            assert_eq!(ptr.tokens().count(), 2);
1662            token = ptr.pop_front();
1663            assert_eq!(token, Some(Token::new("")));
1664            assert_eq!(ptr.tokens().count(), 1);
1665            token = ptr.pop_front();
1666            assert_eq!(token, Some(Token::new("")));
1667            assert_eq!(ptr.tokens().count(), 0);
1668            assert_eq!(ptr, Pointer::root());
1669        }
1670        {
1671            let mut ptr = PointerBuf::new();
1672            assert_eq!(ptr.tokens().count(), 0);
1673            ptr.push_back("");
1674            assert_eq!(ptr.tokens().count(), 1);
1675            ptr.pop_back();
1676            assert_eq!(ptr.tokens().count(), 0);
1677        }
1678        {
1679            let mut ptr = PointerBuf::new();
1680            let input = ["", "", "", "foo", "", "bar", "baz", ""];
1681            for (idx, &s) in input.iter().enumerate() {
1682                assert_eq!(ptr.tokens().count(), idx);
1683                ptr.push_back(s);
1684            }
1685            assert_eq!(ptr.tokens().count(), input.len());
1686            for (idx, s) in input.iter().enumerate() {
1687                assert_eq!(ptr.tokens().count(), 8 - idx);
1688                assert_eq!(ptr.front().unwrap().decoded(), *s);
1689                assert_eq!(ptr.pop_front().unwrap().decoded(), *s);
1690            }
1691            assert_eq!(ptr.tokens().count(), 0);
1692            assert!(ptr.front().is_none());
1693            assert!(ptr.pop_front().is_none());
1694        }
1695    }
1696
1697    #[test]
1698    fn formatting() {
1699        assert_eq!(PointerBuf::from_tokens(["foo", "bar"]), "/foo/bar");
1700        assert_eq!(
1701            PointerBuf::from_tokens(["~/foo", "~bar", "/baz"]),
1702            "/~0~1foo/~0bar/~1baz"
1703        );
1704        assert_eq!(PointerBuf::from_tokens(["field", "", "baz"]), "/field//baz");
1705        assert_eq!(PointerBuf::default(), "");
1706
1707        let ptr = PointerBuf::from_tokens(["foo", "bar", "baz"]);
1708        assert_eq!(ptr.to_string(), "/foo/bar/baz");
1709    }
1710
1711    #[test]
1712    fn last() {
1713        let ptr = Pointer::from_static("/foo/bar");
1714
1715        assert_eq!(ptr.last(), Some("bar".into()));
1716
1717        let ptr = Pointer::from_static("/foo/bar/-");
1718        assert_eq!(ptr.last(), Some("-".into()));
1719
1720        let ptr = Pointer::from_static("/-");
1721        assert_eq!(ptr.last(), Some("-".into()));
1722
1723        let ptr = Pointer::root();
1724        assert_eq!(ptr.last(), None);
1725
1726        let ptr = Pointer::from_static("/bar");
1727        assert_eq!(ptr.last(), Some("bar".into()));
1728    }
1729
1730    #[test]
1731    fn first() {
1732        let ptr = Pointer::from_static("/foo/bar");
1733        assert_eq!(ptr.first(), Some("foo".into()));
1734
1735        let ptr = Pointer::from_static("/foo/bar/-");
1736        assert_eq!(ptr.first(), Some("foo".into()));
1737
1738        let ptr = Pointer::root();
1739        assert_eq!(ptr.first(), None);
1740    }
1741
1742    #[test]
1743    fn pointerbuf_try_from() {
1744        let ptr = PointerBuf::from_tokens(["foo", "bar", "~/"]);
1745
1746        assert_eq!(PointerBuf::try_from("/foo/bar/~0~1").unwrap(), ptr);
1747        let into: PointerBuf = "/foo/bar/~0~1".try_into().unwrap();
1748        assert_eq!(ptr, into);
1749    }
1750
1751    #[test]
1752    #[cfg(all(feature = "serde", feature = "json"))]
1753    fn to_json_value() {
1754        use serde_json::Value;
1755        let ptr = Pointer::from_static("/foo/bar");
1756        assert_eq!(ptr.to_json_value(), Value::String(String::from("/foo/bar")));
1757    }
1758
1759    #[cfg(all(feature = "resolve", feature = "json"))]
1760    #[test]
1761    fn resolve() {
1762        // full tests in resolve.rs
1763        use serde_json::json;
1764        let value = json!({
1765            "foo": {
1766                "bar": {
1767                    "baz": "qux"
1768                }
1769            }
1770        });
1771        let ptr = Pointer::from_static("/foo/bar/baz");
1772        let resolved = ptr.resolve(&value).unwrap();
1773        assert_eq!(resolved, &json!("qux"));
1774    }
1775
1776    #[cfg(all(feature = "delete", feature = "json"))]
1777    #[test]
1778    fn delete() {
1779        use serde_json::json;
1780        let mut value = json!({
1781            "foo": {
1782                "bar": {
1783                    "baz": "qux"
1784                }
1785            }
1786        });
1787        let ptr = Pointer::from_static("/foo/bar/baz");
1788        let deleted = ptr.delete(&mut value).unwrap();
1789        assert_eq!(deleted, json!("qux"));
1790        assert_eq!(
1791            value,
1792            json!({
1793                "foo": {
1794                    "bar": {}
1795                }
1796            })
1797        );
1798    }
1799
1800    #[cfg(all(feature = "assign", feature = "json"))]
1801    #[test]
1802    fn assign() {
1803        use serde_json::json;
1804        let mut value = json!({});
1805        let ptr = Pointer::from_static("/foo/bar");
1806        let replaced = ptr.assign(&mut value, json!("baz")).unwrap();
1807        assert_eq!(replaced, None);
1808        assert_eq!(
1809            value,
1810            json!({
1811                "foo": {
1812                    "bar": "baz"
1813                }
1814            })
1815        );
1816    }
1817
1818    #[test]
1819    fn get() {
1820        let ptr = Pointer::from_static("/0/1/2/3/4/5/6/7/8/9");
1821        for i in 0..10 {
1822            assert_eq!(ptr.get(i).unwrap().decoded(), i.to_string());
1823        }
1824    }
1825
1826    #[test]
1827    fn replace_token_success() {
1828        let mut ptr = PointerBuf::from_tokens(["foo", "bar", "baz"]);
1829        assert!(ptr.replace(1, "qux").is_ok());
1830        assert_eq!(ptr, PointerBuf::from_tokens(["foo", "qux", "baz"]));
1831
1832        assert!(ptr.replace(0, "corge").is_ok());
1833        assert_eq!(ptr, PointerBuf::from_tokens(["corge", "qux", "baz"]));
1834
1835        assert!(ptr.replace(2, "quux").is_ok());
1836        assert_eq!(ptr, PointerBuf::from_tokens(["corge", "qux", "quux"]));
1837    }
1838
1839    #[test]
1840    fn replace_token_out_of_bounds() {
1841        let mut ptr = PointerBuf::from_tokens(["foo", "bar"]);
1842        assert!(ptr.replace(2, "baz").is_err());
1843        assert_eq!(ptr, PointerBuf::from_tokens(["foo", "bar"])); // Ensure subjectal pointer is unchanged
1844    }
1845
1846    #[test]
1847    fn replace_token_with_empty_string() {
1848        let mut ptr = PointerBuf::from_tokens(["foo", "bar", "baz"]);
1849        assert!(ptr.replace(1, "").is_ok());
1850        assert_eq!(ptr, PointerBuf::from_tokens(["foo", "", "baz"]));
1851    }
1852
1853    #[test]
1854    fn replace_token_in_empty_pointer() {
1855        let mut ptr = PointerBuf::default();
1856        assert!(ptr.replace(0, "foo").is_err());
1857        assert_eq!(ptr, PointerBuf::default()); // Ensure the pointer remains empty
1858    }
1859
1860    #[test]
1861    fn pop_back_works_with_empty_strings() {
1862        {
1863            let mut ptr = PointerBuf::new();
1864            ptr.push_back("");
1865            ptr.push_back("");
1866            ptr.push_back("bar");
1867
1868            assert_eq!(ptr.tokens().count(), 3);
1869            ptr.pop_back();
1870            assert_eq!(ptr.tokens().count(), 2);
1871            ptr.pop_back();
1872            assert_eq!(ptr.tokens().count(), 1);
1873            ptr.pop_back();
1874            assert_eq!(ptr.tokens().count(), 0);
1875            assert_eq!(ptr, PointerBuf::new());
1876        }
1877        {
1878            let mut ptr = PointerBuf::new();
1879            assert_eq!(ptr.tokens().count(), 0);
1880            ptr.push_back("");
1881            assert_eq!(ptr.tokens().count(), 1);
1882            ptr.pop_back();
1883            assert_eq!(ptr.tokens().count(), 0);
1884        }
1885        {
1886            let mut ptr = PointerBuf::new();
1887            let input = ["", "", "", "foo", "", "bar", "baz", ""];
1888            for (idx, &s) in input.iter().enumerate() {
1889                assert_eq!(ptr.tokens().count(), idx);
1890                ptr.push_back(s);
1891            }
1892            assert_eq!(ptr.tokens().count(), input.len());
1893            for (idx, s) in input.iter().enumerate().rev() {
1894                assert_eq!(ptr.tokens().count(), idx + 1);
1895                assert_eq!(ptr.back().unwrap().decoded(), *s);
1896                assert_eq!(ptr.pop_back().unwrap().decoded(), *s);
1897            }
1898            assert_eq!(ptr.tokens().count(), 0);
1899            assert!(ptr.back().is_none());
1900            assert!(ptr.pop_back().is_none());
1901        }
1902    }
1903
1904    #[test]
1905    // `clippy::useless_asref` is tripping here because the `as_ref` is being
1906    // called on the same type (`&Pointer`). This is just to ensure that the
1907    // `as_ref` method is implemented correctly and stays that way.
1908    #[allow(clippy::useless_asref)]
1909    fn pointerbuf_as_ref_returns_pointer() {
1910        let ptr_str = "/foo/bar";
1911        let ptr = Pointer::from_static(ptr_str);
1912        let ptr_buf = ptr.to_buf();
1913        assert_eq!(ptr_buf.as_ref(), ptr);
1914        let r: &Pointer = ptr.as_ref();
1915        assert_eq!(ptr, r);
1916
1917        let s: &str = ptr.as_ref();
1918        assert_eq!(s, ptr_str);
1919
1920        let b: &[u8] = ptr.as_ref();
1921        assert_eq!(b, ptr_str.as_bytes());
1922    }
1923
1924    #[test]
1925    fn from_tokens() {
1926        let ptr = PointerBuf::from_tokens(["foo", "bar", "baz"]);
1927        assert_eq!(ptr, "/foo/bar/baz");
1928    }
1929
1930    #[test]
1931    fn pointer_borrow() {
1932        let ptr = Pointer::from_static("/foo/bar");
1933        let borrowed: &str = ptr.borrow();
1934        assert_eq!(borrowed, "/foo/bar");
1935    }
1936
1937    #[test]
1938    #[cfg(feature = "json")]
1939    fn into_value() {
1940        use alloc::string::ToString;
1941        use serde_json::Value;
1942        let ptr = Pointer::from_static("/foo/bar");
1943        let value: Value = ptr.into();
1944        assert_eq!(value, Value::String("/foo/bar".to_string()));
1945    }
1946
1947    #[test]
1948    fn intersect() {
1949        let base = Pointer::from_static("/foo/bar");
1950        let a = Pointer::from_static("/foo/bar/qux");
1951        let b = Pointer::from_static("/foo/bar");
1952        assert_eq!(a.intersection(b), base);
1953
1954        let base = Pointer::from_static("");
1955        let a = Pointer::from_static("/foo");
1956        let b = Pointer::from_static("/");
1957        assert_eq!(a.intersection(b), base);
1958
1959        let base = Pointer::from_static("");
1960        let a = Pointer::from_static("/fooqux");
1961        let b = Pointer::from_static("/foobar");
1962        assert_eq!(a.intersection(b), base);
1963    }
1964
1965    #[quickcheck]
1966    fn qc_pop_and_push(mut ptr: PointerBuf) -> bool {
1967        let subjectal_ptr = ptr.clone();
1968        let mut tokens = Vec::with_capacity(ptr.count());
1969        while let Some(token) = ptr.pop_back() {
1970            tokens.push(token);
1971        }
1972        if ptr.count() != 0 || !ptr.is_root() || ptr.last().is_some() || ptr.first().is_some() {
1973            return false;
1974        }
1975        for token in tokens.drain(..) {
1976            ptr.push_front(token);
1977        }
1978        if ptr != subjectal_ptr {
1979            return false;
1980        }
1981        while let Some(token) = ptr.pop_front() {
1982            tokens.push(token);
1983        }
1984        if ptr.count() != 0 || !ptr.is_root() || ptr.last().is_some() || ptr.first().is_some() {
1985            return false;
1986        }
1987        for token in tokens {
1988            ptr.push_back(token);
1989        }
1990        ptr == subjectal_ptr
1991    }
1992
1993    #[quickcheck]
1994    fn qc_split(ptr: PointerBuf) -> bool {
1995        if let Some((head, tail)) = ptr.split_front() {
1996            {
1997                let Some(first) = ptr.first() else {
1998                    return false;
1999                };
2000                if first != head {
2001                    return false;
2002                }
2003            }
2004            {
2005                let mut copy = ptr.clone();
2006                copy.pop_front();
2007                if copy != tail {
2008                    return false;
2009                }
2010            }
2011            {
2012                let mut buf = tail.to_buf();
2013                buf.push_front(head.clone());
2014                if buf != ptr {
2015                    return false;
2016                }
2017            }
2018            {
2019                let fmt = alloc::format!("/{}{tail}", head.encoded());
2020                if Pointer::parse(&fmt).unwrap() != ptr {
2021                    return false;
2022                }
2023            }
2024        } else {
2025            return ptr.is_root()
2026                && ptr.count() == 0
2027                && ptr.last().is_none()
2028                && ptr.first().is_none();
2029        }
2030        if let Some((head, tail)) = ptr.split_back() {
2031            {
2032                let Some(last) = ptr.last() else {
2033                    return false;
2034                };
2035                if last != tail {
2036                    return false;
2037                }
2038            }
2039            {
2040                let mut copy = ptr.clone();
2041                copy.pop_back();
2042                if copy != head {
2043                    return false;
2044                }
2045            }
2046            {
2047                let mut buf = head.to_buf();
2048                buf.push_back(tail.clone());
2049                if buf != ptr {
2050                    return false;
2051                }
2052            }
2053            {
2054                let fmt = alloc::format!("{head}/{}", tail.encoded());
2055                if Pointer::parse(&fmt).unwrap() != ptr {
2056                    return false;
2057                }
2058            }
2059            if Some(head) != ptr.parent() {
2060                return false;
2061            }
2062        } else {
2063            return ptr.is_root()
2064                && ptr.count() == 0
2065                && ptr.last().is_none()
2066                && ptr.first().is_none();
2067        }
2068        true
2069    }
2070
2071    #[quickcheck]
2072    fn qc_from_tokens(tokens: Vec<String>) -> bool {
2073        let buf = PointerBuf::from_tokens(&tokens);
2074        let reconstructed: Vec<_> = buf.tokens().collect();
2075        reconstructed
2076            .into_iter()
2077            .zip(tokens)
2078            .all(|(a, b)| a.decoded() == b)
2079    }
2080
2081    #[quickcheck]
2082    fn qc_intersection(base: PointerBuf, suffix_0: PointerBuf, suffix_1: PointerBuf) -> TestResult {
2083        if suffix_0.first() == suffix_1.first() {
2084            // base must be the true intersection
2085            return TestResult::discard();
2086        }
2087        let mut a = base.clone();
2088        a.append(&suffix_0);
2089        let mut b = base.clone();
2090        b.append(&suffix_1);
2091        let isect = a.intersection(&b);
2092        TestResult::from_bool(isect == base)
2093    }
2094
2095    #[cfg(all(feature = "json", feature = "std", feature = "serde"))]
2096    #[test]
2097    fn serde() {
2098        use serde::Deserialize;
2099        let ptr = PointerBuf::from_tokens(["foo", "bar"]);
2100        let json = serde_json::to_string(&ptr).unwrap();
2101        assert_eq!(json, "\"/foo/bar\"");
2102        let deserialized: PointerBuf = serde_json::from_str(&json).unwrap();
2103        assert_eq!(deserialized, ptr);
2104
2105        let ptr = Pointer::from_static("/foo/bar");
2106        let json = serde_json::to_string(&ptr).unwrap();
2107        assert_eq!(json, "\"/foo/bar\"");
2108
2109        let mut de = serde_json::Deserializer::from_str("\"/foo/bar\"");
2110        let p = <&Pointer>::deserialize(&mut de).unwrap();
2111        assert_eq!(p, ptr);
2112        let s = serde_json::to_string(p).unwrap();
2113        assert_eq!(json, s);
2114
2115        let invalid = serde_json::from_str::<&Pointer>("\"foo/bar\"");
2116        assert!(invalid.is_err());
2117    }
2118
2119    #[test]
2120    fn to_owned() {
2121        let ptr = Pointer::from_static("/bread/crumbs");
2122        let buf = ptr.to_owned();
2123        assert_eq!(buf, "/bread/crumbs");
2124    }
2125
2126    #[test]
2127    fn concat() {
2128        let ptr = Pointer::from_static("/foo");
2129        let barbaz = Pointer::from_static("/bar/baz");
2130        assert_eq!(ptr.concat(barbaz), "/foo/bar/baz");
2131    }
2132
2133    #[test]
2134    fn with_leading_token() {
2135        let ptr = Pointer::from_static("/bar");
2136        let foobar = ptr.with_leading_token("foo");
2137        assert_eq!(foobar, "/foo/bar");
2138    }
2139
2140    #[test]
2141    fn with_trailing_token() {
2142        let ptr = Pointer::from_static("/foo");
2143        let foobar = ptr.with_trailing_token("bar");
2144        assert_eq!(foobar, "/foo/bar");
2145    }
2146
2147    #[test]
2148    fn len() {
2149        let ptr = Pointer::from_static("/foo/bar");
2150        assert_eq!(ptr.len(), 8);
2151        let mut ptr = ptr.to_buf();
2152        ptr.push_back("~");
2153        assert_eq!(ptr.len(), 11);
2154    }
2155
2156    #[test]
2157    fn is_empty() {
2158        assert!(Pointer::from_static("").is_empty());
2159        assert!(!Pointer::from_static("/").is_empty());
2160    }
2161
2162    #[test]
2163    #[allow(clippy::cmp_owned, unused_must_use)]
2164    fn partial_eq() {
2165        let ptr_string = String::from("/bread/crumbs");
2166        let ptr_str = "/bread/crumbs";
2167        let ptr = Pointer::from_static(ptr_str);
2168        let ptr_buf = ptr.to_buf();
2169        <&Pointer as PartialEq<&Pointer>>::eq(&ptr, &ptr);
2170        <Pointer as PartialEq<&str>>::eq(ptr, &ptr_str);
2171        <&Pointer as PartialEq<String>>::eq(&ptr, &ptr_string);
2172        <Pointer as PartialEq<String>>::eq(ptr, &ptr_string);
2173        <Pointer as PartialEq<PointerBuf>>::eq(ptr, &ptr_buf);
2174        <&str as PartialEq<Pointer>>::eq(&ptr_str, ptr);
2175        <String as PartialEq<Pointer>>::eq(&ptr_string, ptr);
2176        <str as PartialEq<Pointer>>::eq(ptr_str, ptr);
2177        <PointerBuf as PartialEq<str>>::eq(&ptr_buf, ptr_str);
2178        <PointerBuf as PartialEq<PointerBuf>>::eq(&ptr_buf, &ptr_buf);
2179        <PointerBuf as PartialEq<Pointer>>::eq(&ptr_buf, ptr);
2180        <Pointer as PartialEq<PointerBuf>>::eq(ptr, &ptr_buf);
2181        <PointerBuf as PartialEq<&Pointer>>::eq(&ptr_buf, &ptr);
2182        <PointerBuf as PartialEq<&str>>::eq(&ptr_buf, &ptr_str);
2183        <PointerBuf as PartialEq<String>>::eq(&ptr_buf, &ptr_string);
2184        <&Pointer as PartialEq<PointerBuf>>::eq(&ptr, &ptr_buf);
2185        <str as PartialEq<PointerBuf>>::eq(ptr_str, &ptr_buf);
2186        <&str as PartialEq<PointerBuf>>::eq(&ptr_str, &ptr_buf);
2187        <String as PartialEq<PointerBuf>>::eq(&ptr_string, &ptr_buf);
2188    }
2189
2190    #[test]
2191    fn partial_ord() {
2192        let a_str = "/foo/bar";
2193        let a_string = a_str.to_string();
2194        let a_ptr = Pointer::from_static(a_str);
2195        let a_buf = a_ptr.to_buf();
2196        let b_str = "/foo/bar";
2197        let b_string = b_str.to_string();
2198        let b_ptr = Pointer::from_static(b_str);
2199        let b_buf = b_ptr.to_buf();
2200        let c_str = "/foo/bar/baz";
2201        let c_string = c_str.to_string();
2202        let c_ptr = Pointer::from_static(c_str);
2203        let c_buf = c_ptr.to_buf();
2204
2205        assert!(<Pointer as PartialOrd<PointerBuf>>::lt(a_ptr, &c_buf));
2206        assert!(<PointerBuf as PartialOrd<Pointer>>::lt(&a_buf, c_ptr));
2207        assert!(<String as PartialOrd<Pointer>>::lt(&a_string, c_ptr));
2208        assert!(<str as PartialOrd<Pointer>>::lt(a_str, c_ptr));
2209        assert!(<str as PartialOrd<PointerBuf>>::lt(a_str, &c_buf));
2210        assert!(<&str as PartialOrd<Pointer>>::lt(&a_str, c_ptr));
2211        assert!(<&str as PartialOrd<PointerBuf>>::lt(&a_str, &c_buf));
2212        assert!(<&Pointer as PartialOrd<PointerBuf>>::lt(&a_ptr, &c_buf));
2213        assert!(<&Pointer as PartialOrd<&str>>::lt(&b_ptr, &c_str));
2214        assert!(<Pointer as PartialOrd<String>>::lt(a_ptr, &c_string));
2215        assert!(<PointerBuf as PartialOrd<&str>>::lt(&a_buf, &c_str));
2216        assert!(<PointerBuf as PartialOrd<String>>::lt(&a_buf, &c_string));
2217        assert!(a_ptr < c_buf);
2218        assert!(c_buf > a_ptr);
2219        assert!(a_buf < c_ptr);
2220        assert!(a_ptr < c_buf);
2221        assert!(a_ptr < c_ptr);
2222        assert!(a_ptr <= c_ptr);
2223        assert!(c_ptr > a_ptr);
2224        assert!(c_ptr >= a_ptr);
2225        assert!(a_ptr == b_ptr);
2226        assert!(a_ptr <= b_ptr);
2227        assert!(a_ptr >= b_ptr);
2228        assert!(a_string < c_buf);
2229        assert!(a_string <= c_buf);
2230        assert!(c_string > a_buf);
2231        assert!(c_string >= a_buf);
2232        assert!(a_string == b_buf);
2233        assert!(a_ptr < c_buf);
2234        assert!(a_ptr <= c_buf);
2235        assert!(c_ptr > a_buf);
2236        assert!(c_ptr >= a_buf);
2237        assert!(a_ptr == b_buf);
2238        assert!(a_ptr <= b_buf);
2239        assert!(a_ptr >= b_buf);
2240        assert!(a_ptr < c_buf);
2241        assert!(c_ptr > b_string);
2242        // couldn't inline this
2243        #[allow(clippy::nonminimal_bool)]
2244        let not = !(a_ptr > c_buf);
2245        assert!(not);
2246    }
2247
2248    #[test]
2249    fn intersection() {
2250        struct Test {
2251            base: &'static str,
2252            a_suffix: &'static str,
2253            b_suffix: &'static str,
2254        }
2255
2256        let tests = [
2257            Test {
2258                base: "",
2259                a_suffix: "/",
2260                b_suffix: "/a/b/c",
2261            },
2262            Test {
2263                base: "",
2264                a_suffix: "",
2265                b_suffix: "",
2266            },
2267            Test {
2268                base: "/a",
2269                a_suffix: "/",
2270                b_suffix: "/suffix",
2271            },
2272            Test {
2273                base: "/a",
2274                a_suffix: "/suffix",
2275                b_suffix: "",
2276            },
2277            Test {
2278                base: "/¦\\>‶“lv\u{eedd}\u{8a}Y\n\u{99}𘐷vT\n\u{4}Hª\\ 嗱\\Yl6Y`\"1\u{6dd}\u{17}\0\u{10}ዄ8\"Z닍6i)V;\u{6be4c}\u{b}\u{59836}`\u{1e}㑍§~05\u{1d}\u{8a}[뵔\u{437c3}j\u{f326}\";*\u{c}*U\u{1b}\u{8a}I\u{4}묁",
2279                a_suffix: "/Y\u{2064}",
2280                b_suffix: "",
2281            }
2282        ];
2283
2284        for Test {
2285            base,
2286            a_suffix,
2287            b_suffix,
2288        } in tests
2289        {
2290            let base = PointerBuf::parse(base).expect(&format!("failed to parse ${base}"));
2291            let mut a = base.clone();
2292            let mut b = base.clone();
2293            a.append(PointerBuf::parse(a_suffix).unwrap());
2294            b.append(PointerBuf::parse(b_suffix).unwrap());
2295            let intersection = a.intersection(&b);
2296            assert_eq!(intersection, base);
2297        }
2298    }
2299
2300    #[test]
2301    fn into_iter() {
2302        use core::iter::IntoIterator;
2303
2304        let ptr = PointerBuf::from_tokens(["foo", "bar", "baz"]);
2305        let tokens: Vec<Token> = ptr.into_iter().collect();
2306        let from_tokens = PointerBuf::from_tokens(tokens);
2307        assert_eq!(ptr, from_tokens);
2308
2309        let ptr = Pointer::from_static("/foo/bar/baz");
2310        let tokens: Vec<_> = ptr.into_iter().collect();
2311        assert_eq!(ptr, PointerBuf::from_tokens(tokens));
2312    }
2313
2314    #[test]
2315    fn from_str() {
2316        let p = PointerBuf::from_str("/foo/bar").unwrap();
2317        assert_eq!(p, "/foo/bar");
2318    }
2319
2320    #[test]
2321    fn from_token() {
2322        let p = PointerBuf::from(Token::new("foo"));
2323        assert_eq!(p, "/foo");
2324    }
2325
2326    #[test]
2327    fn from_usize() {
2328        let p = PointerBuf::from(0);
2329        assert_eq!(p, "/0");
2330    }
2331
2332    #[test]
2333    fn borrow() {
2334        let ptr = PointerBuf::from_tokens(["foo", "bar"]);
2335        let borrowed: &Pointer = ptr.borrow();
2336        assert_eq!(borrowed, "/foo/bar");
2337    }
2338
2339    #[test]
2340    fn from_box_to_buf() {
2341        let subjectal = PointerBuf::parse("/foo/bar/0").unwrap();
2342        let boxed: Box<Pointer> = subjectal.clone().into();
2343        let unboxed = boxed.into_buf();
2344        assert_eq!(subjectal, unboxed);
2345    }
2346
2347    #[test]
2348    #[cfg(feature = "miette")]
2349    fn quick_miette_spike() {
2350        let err = PointerBuf::parse("hello-world").unwrap_err();
2351        println!("{:?}", miette::Report::from(err));
2352    }
2353}