jsonptr/
error.rs

1use alloc::{
2    format,
3    string::{FromUtf8Error, String, ToString},
4    vec::Vec,
5};
6
7use crate::{Pointer, Token};
8use core::{
9    // error::Error as StdError,
10    fmt::{Debug, Display, Formatter},
11    num::ParseIntError,
12};
13
14/// An enum representing possible errors that can occur when resolving or
15/// mutating by a JSON Pointer.
16#[derive(Debug, PartialEq, Eq, Clone)]
17pub enum Error {
18    /// Indicates an error occurred while parsing a `usize` (`ParseError`) or the
19    /// parsed value was out of bounds for the targeted array.
20    Index(IndexError),
21    /// Represents an error that occurs when attempting to resolve a `Pointer` that
22    /// encounters a leaf node (i.e. a scalar / null value) which is not the root
23    /// of the `Pointer`.
24    Unresolvable(UnresolvableError),
25    /// Indicates that a Pointer was not found in the data.
26    NotFound(NotFoundError),
27    // /// Indicates that a Pointer was malformed.
28    // MalformedPointer(MalformedPointerError),
29}
30
31impl Error {
32    /// Returns `true` if the error is `Error::IndexError`.
33    pub fn is_index(&self) -> bool {
34        matches!(self, Error::Index(_))
35    }
36    /// Returns `true` if the error is `Error::UnresolvableError`.
37    pub fn is_unresolvable(&self) -> bool {
38        matches!(self, Error::Unresolvable(_))
39    }
40    /// Returns `true` if the error is `Error::NotFoundError`.
41    pub fn is_not_found(&self) -> bool {
42        matches!(self, Error::NotFound(_))
43    }
44    // /// Returns `true` if the error is `Error::MalformedPointerError`.
45    // pub fn is_malformed_pointer(&self) -> bool {
46    //     matches!(self, Error::MalformedPointer(_))
47    // }
48}
49// impl From<MalformedPointerError> for Error {
50//     fn from(err: MalformedPointerError) -> Self {
51//         Error::MalformedPointer(err)
52//     }
53// }
54impl From<IndexError> for Error {
55    fn from(err: IndexError) -> Self {
56        Error::Index(err)
57    }
58}
59impl From<NotFoundError> for Error {
60    fn from(err: NotFoundError) -> Self {
61        Error::NotFound(err)
62    }
63}
64
65impl From<OutOfBoundsError> for Error {
66    fn from(err: OutOfBoundsError) -> Self {
67        Error::Index(IndexError::from(err))
68    }
69}
70
71impl From<UnresolvableError> for Error {
72    fn from(err: UnresolvableError) -> Self {
73        Error::Unresolvable(err)
74    }
75}
76
77impl Display for Error {
78    fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
79        match self {
80            Error::Index(err) => Display::fmt(err, f),
81            Error::Unresolvable(err) => Display::fmt(err, f),
82            Error::NotFound(err) => Display::fmt(err, f),
83            // Error::MalformedPointer(err) => Display::fmt(err, f),
84        }
85    }
86}
87
88#[cfg(feature = "std")]
89impl std::error::Error for Error {}
90
91/// Represents an error that occurs when attempting to resolve a `Pointer` that
92/// encounters a leaf node (i.e. a scalar / null value) which is not the root
93/// of the `Pointer`.
94///
95/// ## Example
96/// ```rust
97/// use serde_json::json;
98/// use jsonptr::{Pointer, ResolveMut, Resolve, UnresolvableError};
99/// let mut data = json!({ "foo": "bar" });
100/// let ptr = Pointer::try_from("/foo/unreachable").unwrap();
101/// let err = data.resolve_mut(&ptr).unwrap_err();
102/// assert_eq!(err, UnresolvableError::new(ptr.clone()).into());
103/// ```
104#[derive(Clone, PartialEq, Eq, Debug)]
105pub struct UnresolvableError {
106    /// The unresolved `Pointer`.
107    pub pointer: Pointer,
108    /// The leaf node, if applicable, which was expected to be either an
109    /// `Object` or an `Array`.
110    pub leaf: Option<Token>,
111}
112
113#[cfg(feature = "std")]
114impl std::error::Error for UnresolvableError {}
115
116impl UnresolvableError {
117    /// Creates a new `UnresolvableError` with the given `Pointer`.
118    pub fn new(pointer: Pointer) -> Self {
119        let leaf = if pointer.count() >= 2 {
120            Some(pointer.get(pointer.count() - 2).unwrap())
121        } else {
122            None
123        };
124        Self { pointer, leaf }
125    }
126}
127
128impl Display for UnresolvableError {
129    fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
130        write!(
131            f,
132            "can not resolve \"{}\" due to {} being a scalar value",
133            self.pointer,
134            self.leaf
135                .as_deref()
136                .map_or_else(|| "the root value".to_string(), |l| format!("\"{l}\""))
137        )
138    }
139}
140
141/// Indicates an error occurred while parsing a `usize` (`ParseError`) or the
142/// parsed value was out of bounds for the targeted array.
143#[derive(PartialEq, Eq, Clone)]
144pub enum IndexError {
145    /// Represents an that an error occurred when parsing an index.
146    Parse(ParseError),
147    /// Indicates that the Pointer contains an index of an array that is out of
148    /// bounds.
149    OutOfBounds(OutOfBoundsError),
150}
151impl Display for IndexError {
152    fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
153        match self {
154            IndexError::Parse(err) => Display::fmt(&err, f),
155            IndexError::OutOfBounds(err) => Display::fmt(&err, f),
156        }
157    }
158}
159impl Debug for IndexError {
160    fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
161        Display::fmt(self, f)
162    }
163}
164#[cfg(feature = "std")]
165impl std::error::Error for IndexError {}
166
167impl From<OutOfBoundsError> for IndexError {
168    fn from(err: OutOfBoundsError) -> Self {
169        IndexError::OutOfBounds(err)
170    }
171}
172
173/// ParseError represents an that an error occurred when parsing an index.
174#[derive(PartialEq, Eq, Clone)]
175pub struct ParseError {
176    /// The source `ParseIntError`
177    pub source: ParseIntError,
178    /// The `Token` which was unable to be parsed as an index.
179    pub token: Token,
180}
181
182impl Display for ParseError {
183    fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
184        write!(f, "{}", self.source)
185    }
186}
187impl Debug for ParseError {
188    fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
189        f.debug_struct("ParseError")
190            .field("source", &self.source)
191            .field("token", &self.token)
192            .finish()
193    }
194}
195#[cfg(feature = "std")]
196impl std::error::Error for ParseError {
197    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
198        Some(&self.source)
199    }
200}
201
202/// Indicates that the `Pointer` contains an index of an array that is out of
203/// bounds.
204#[derive(Debug, PartialEq, Eq, Clone)]
205pub struct OutOfBoundsError {
206    /// The length of the array.
207    pub len: usize,
208    /// The index of the array that was out of bounds.
209    pub index: usize,
210    /// The `Token` which was out of bounds.
211    pub token: Token,
212}
213#[cfg(feature = "std")]
214impl std::error::Error for OutOfBoundsError {}
215
216impl Display for OutOfBoundsError {
217    fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
218        write!(f, "index {} out of bounds", self.index)
219    }
220}
221
222/// Pointer was not in UTF-8 format.
223#[derive(Clone, PartialEq, Eq, Debug)]
224pub struct NotUtf8Error {
225    /// Underlying `std::str::Utf8Error`.
226    pub source: FromUtf8Error,
227    /// Byte slice that was not in UTF-8 format.
228    pub path: Vec<u8>,
229}
230
231impl core::fmt::Display for NotUtf8Error {
232    fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
233        write!(f, "not utf8: {}", self.source)
234    }
235}
236#[cfg(feature = "std")]
237impl std::error::Error for NotUtf8Error {}
238
239/// Indicates that a Pointer was malformed.
240#[derive(Debug, PartialEq, Eq, Clone)]
241pub enum MalformedPointerError {
242    /// Indicates that the Pointer was malformed because it did not contain a
243    /// leading slash (`'/'`).
244    NoLeadingSlash(String),
245    /// Indicates that the Pointer was malformed because it contained invalid
246    /// encoding.
247    InvalidEncoding(String),
248    /// NonUTF8
249    NotUtf8(NotUtf8Error),
250}
251impl From<NotUtf8Error> for MalformedPointerError {
252    fn from(err: NotUtf8Error) -> Self {
253        MalformedPointerError::NotUtf8(err)
254    }
255}
256
257impl From<FromUtf8Error> for MalformedPointerError {
258    fn from(err: FromUtf8Error) -> Self {
259        MalformedPointerError::NotUtf8(NotUtf8Error {
260            source: err,
261            path: Vec::new(),
262        })
263    }
264}
265impl Display for MalformedPointerError {
266    fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
267        match self {
268            MalformedPointerError::NoLeadingSlash(s) => {
269                write!(
270                    f,
271                    "json pointer \"{s}\" is malformed due to missing starting slash",
272                )
273            }
274            MalformedPointerError::InvalidEncoding(s) => {
275                write!(f, "json pointer \"{s}\" is improperly encoded")
276            }
277            MalformedPointerError::NotUtf8(err) => {
278                write!(f, "json pointer is not UTF-8: {}", err.source)
279            }
280        }
281    }
282}
283
284#[cfg(feature = "std")]
285impl std::error::Error for MalformedPointerError {}
286
287/// NotFoundError indicates that a Pointer was not found in the data.
288#[derive(Debug, PartialEq, Eq, Clone)]
289pub struct NotFoundError {
290    /// The `Pointer` which could not be resolved.
291    pub pointer: Pointer,
292}
293impl NotFoundError {
294    /// Creates a new `NotFoundError` with the given `Pointer`.
295    pub fn new(pointer: Pointer) -> Self {
296        NotFoundError { pointer }
297    }
298}
299impl Display for NotFoundError {
300    fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
301        write!(
302            f,
303            "the resource at json pointer \"{}\" was not found",
304            self.pointer
305        )
306    }
307}
308#[cfg(feature = "std")]
309impl std::error::Error for NotFoundError {}
310
311/// Returned from `Pointer::replace_token` when the provided index is out of
312/// bounds.
313#[derive(Debug, PartialEq, Eq, Clone)]
314pub struct ReplaceTokenError {
315    /// The index of the token that was out of bounds.
316    pub index: usize,
317    /// The number of tokens in the `Pointer`.
318    pub count: usize,
319    /// The subject `Pointer`.
320    pub pointer: Pointer,
321}
322#[cfg(feature = "std")]
323impl std::error::Error for ReplaceTokenError {}
324
325impl Display for ReplaceTokenError {
326    fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
327        write!(
328            f,
329            "index {} is out of bounds ({}) for the pointer {}",
330            self.index, self.count, self.pointer
331        )
332    }
333}