1
use core::convert::Infallible;
2
use core::fmt::Display;
3

            
4
/// A JSON parsing error with location information.
5
34
#[derive(Debug, PartialEq)]
6
pub struct Error<DelegateError = Infallible> {
7
    pub(crate) offset: usize,
8
    pub(crate) kind: ErrorKind<DelegateError>,
9
}
10

            
11
impl<DelegateError> Error<DelegateError> {
12
    /// Returns the kind of the error.
13
    #[must_use]
14
49
    pub const fn kind(&self) -> &ErrorKind<DelegateError> {
15
49
        &self.kind
16
49
    }
17

            
18
    /// Returns the offset of the error, which is the byte position nearest to
19
    /// where the error occurred.
20
    #[must_use]
21
33
    pub const fn offset(&self) -> usize {
22
33
        self.offset
23
33
    }
24
}
25

            
26
#[cfg(feature = "std")]
27
impl<DelegateError> std::error::Error for Error<DelegateError> where
28
    DelegateError: std::fmt::Debug + Display
29
{
30
}
31

            
32
impl<DelegateError> Display for Error<DelegateError>
33
where
34
    DelegateError: Display,
35
{
36
25
    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
37
25
        write!(f, "error at {}: {}", self.offset, self.kind)
38
25
    }
39
}
40

            
41
impl Error<Infallible> {
42
    #[must_use]
43
1810
    pub(crate) fn into_fallable<DelegateError>(self) -> Error<DelegateError> {
44
1810
        Error {
45
1810
            offset: self.offset,
46
1810
            kind: self.kind.into_fallable(),
47
1810
        }
48
1810
    }
49
}
50

            
51
impl Error<ErrorKind> {
52
    #[must_use]
53
418
    pub(crate) fn into_infallable(self) -> Error {
54
418
        Error {
55
418
            offset: self.offset,
56
418
            kind: self.kind.into_infallable(),
57
418
        }
58
418
    }
59
}
60

            
61
/// An error from parsing JSON.
62
67
#[derive(Debug, Eq, PartialEq, Clone)]
63
#[non_exhaustive]
64
pub enum ErrorKind<DelegateError = Infallible> {
65
    /// An invalid UTF-8 sequence was encountered.
66
    Utf8,
67
    /// An end-of-file was encountered when it wasn't expected.
68
    UnexpectedEof,
69
    /// While parsing an object, something was encountered that was not a valid object key.
70
    ExpectedObjectKey,
71
    /// While parsing an object, a colon was expected after an object's key.
72
    ExpectedColon,
73
    /// A [`Value`][crate::Value] was expected.
74
    ExpectedValue,
75
    /// While parsing an object, either the end of an object (`}`) or a comma
76
    /// was expected.
77
    ExpectedCommaOrEndOfObject,
78
    /// While parsing an array, either the end of an array (`]`) or a comma was
79
    /// expected.
80
    ExpectedCommaOrEndOfArray,
81
    /// When parsing an object or an array, a trailing comma was detected. The
82
    /// JSON specification disallows trailing commas.
83
    IllegalTrailingComma,
84
    /// An unexpected character was encountered while parsing a
85
    /// [`Value`][crate::Value].
86
    Unexpected(u8),
87
    /// The source being parsed contained additional non-whitespace data after a
88
    /// [`Value`][crate::Value] was parsed.
89
    TrailingNonWhitespace,
90
    /// A non-string was encountered for an object key. The JSON standard
91
    /// requires all keys to be strings.
92
    ObjectKeysMustBeStrings,
93
    /// An exponent was expected on a floating point number.
94
    ExpectedExponent,
95
    /// At least one decimal digit was expected on a floating point number.
96
    ExpectedDecimalDigit,
97
    /// At least one integer digit was expected on a floating point number.
98
    ExpectedDigit,
99
    /// An invalid hexadecimal character was encountered in a unicode escape
100
    /// sequence in a string.
101
    InvalidHexadecimal,
102
    /// An invalid character was escaped.
103
    InvalidEscape,
104
    /// An object is missing its end (`}`).
105
    UnclosedObject,
106
    /// An array is missing its end (`]`).
107
    UnclosedArray,
108
    /// A string is missing its end (`"`).
109
    UnclosedString,
110
    /// A string was expected, but another type was found.
111
    ExpectedString,
112
    /// A number was expected, but another type was found.
113
    ExpectedNumber,
114
    /// The JSON being parsed has more depth than the parser was configured to
115
    /// allow.
116
    RecursionLimitReached,
117
    /// A value that wasn't an object or array was contained in a JSON payload.
118
    ///
119
    /// This error is only returned when the `allow_all_types_at_root`
120
    /// configuration is set to `false`.
121
    PayloadsShouldBeObjectOrArray,
122
    /// A [`GenericDocument`](crate::doc::GenericDocument) being parsed was too
123
    /// large to fit in the collection provided.
124
    PaylodTooLarge,
125
    /// An error was returned from a
126
    /// [`ParseDelegate`](crate::parser::ParseDelegate).
127
    ErrorFromDelegate(DelegateError),
128
}
129

            
130
impl ErrorKind<Infallible> {
131
1834
    fn into_fallable<DelegateError>(self) -> ErrorKind<DelegateError> {
132
1834
        match self {
133
142
            ErrorKind::Utf8 => ErrorKind::Utf8,
134
389
            ErrorKind::UnexpectedEof => ErrorKind::UnexpectedEof,
135
1
            ErrorKind::ExpectedObjectKey => ErrorKind::ExpectedObjectKey,
136
14
            ErrorKind::ExpectedColon => ErrorKind::ExpectedColon,
137
1
            ErrorKind::ExpectedValue => ErrorKind::ExpectedValue,
138
1
            ErrorKind::ExpectedCommaOrEndOfObject => ErrorKind::ExpectedCommaOrEndOfObject,
139
1
            ErrorKind::ExpectedCommaOrEndOfArray => ErrorKind::ExpectedCommaOrEndOfArray,
140
1
            ErrorKind::IllegalTrailingComma => ErrorKind::IllegalTrailingComma,
141
718
            ErrorKind::Unexpected(ch) => ErrorKind::Unexpected(ch),
142
1
            ErrorKind::TrailingNonWhitespace => ErrorKind::TrailingNonWhitespace,
143
1
            ErrorKind::ObjectKeysMustBeStrings => ErrorKind::ObjectKeysMustBeStrings,
144
191
            ErrorKind::ExpectedExponent => ErrorKind::ExpectedExponent,
145
45
            ErrorKind::ExpectedDecimalDigit => ErrorKind::ExpectedDecimalDigit,
146
39
            ErrorKind::ExpectedDigit => ErrorKind::ExpectedDigit,
147
44
            ErrorKind::InvalidHexadecimal => ErrorKind::InvalidHexadecimal,
148
194
            ErrorKind::InvalidEscape => ErrorKind::InvalidEscape,
149
1
            ErrorKind::UnclosedObject => ErrorKind::UnclosedObject,
150
1
            ErrorKind::UnclosedArray => ErrorKind::UnclosedArray,
151
44
            ErrorKind::UnclosedString => ErrorKind::UnclosedString,
152
1
            ErrorKind::ExpectedString => ErrorKind::ExpectedString,
153
1
            ErrorKind::ExpectedNumber => ErrorKind::ExpectedNumber,
154
1
            ErrorKind::RecursionLimitReached => ErrorKind::RecursionLimitReached,
155
1
            ErrorKind::PayloadsShouldBeObjectOrArray => ErrorKind::PayloadsShouldBeObjectOrArray,
156
1
            ErrorKind::PaylodTooLarge => ErrorKind::PaylodTooLarge,
157
            ErrorKind::ErrorFromDelegate(_) => unreachable!("infallible"),
158
        }
159
1834
    }
160
}
161

            
162
impl ErrorKind<ErrorKind> {
163
443
    fn into_infallable(self) -> ErrorKind {
164
443
        match self {
165
1
            ErrorKind::Utf8 => ErrorKind::Utf8,
166
1
            ErrorKind::UnexpectedEof => ErrorKind::UnexpectedEof,
167
1
            ErrorKind::ExpectedObjectKey => ErrorKind::ExpectedObjectKey,
168
25
            ErrorKind::ExpectedColon => ErrorKind::ExpectedColon,
169
1
            ErrorKind::ExpectedValue => ErrorKind::ExpectedValue,
170
13
            ErrorKind::ExpectedCommaOrEndOfObject => ErrorKind::ExpectedCommaOrEndOfObject,
171
25
            ErrorKind::ExpectedCommaOrEndOfArray => ErrorKind::ExpectedCommaOrEndOfArray,
172
25
            ErrorKind::IllegalTrailingComma => ErrorKind::IllegalTrailingComma,
173
145
            ErrorKind::Unexpected(ch) => ErrorKind::Unexpected(ch),
174
37
            ErrorKind::TrailingNonWhitespace => ErrorKind::TrailingNonWhitespace,
175
1
            ErrorKind::ObjectKeysMustBeStrings => ErrorKind::ObjectKeysMustBeStrings,
176
37
            ErrorKind::ExpectedExponent => ErrorKind::ExpectedExponent,
177
1
            ErrorKind::ExpectedDecimalDigit => ErrorKind::ExpectedDecimalDigit,
178
1
            ErrorKind::ExpectedDigit => ErrorKind::ExpectedDigit,
179
1
            ErrorKind::InvalidHexadecimal => ErrorKind::InvalidHexadecimal,
180
49
            ErrorKind::InvalidEscape => ErrorKind::InvalidEscape,
181
13
            ErrorKind::UnclosedObject => ErrorKind::UnclosedObject,
182
13
            ErrorKind::UnclosedArray => ErrorKind::UnclosedArray,
183
1
            ErrorKind::UnclosedString => ErrorKind::UnclosedString,
184
1
            ErrorKind::ExpectedString => ErrorKind::ExpectedString,
185
1
            ErrorKind::ExpectedNumber => ErrorKind::ExpectedNumber,
186
13
            ErrorKind::RecursionLimitReached => ErrorKind::RecursionLimitReached,
187
17
            ErrorKind::PayloadsShouldBeObjectOrArray => ErrorKind::PayloadsShouldBeObjectOrArray,
188
1
            ErrorKind::PaylodTooLarge => ErrorKind::PaylodTooLarge,
189
19
            ErrorKind::ErrorFromDelegate(kind) => kind,
190
        }
191
443
    }
192
}
193

            
194
1
#[test]
195
1
fn into_fallable_test() {
196
24
    for kind in [
197
1
        ErrorKind::Utf8,
198
1
        ErrorKind::UnexpectedEof,
199
1
        ErrorKind::ExpectedObjectKey,
200
1
        ErrorKind::ExpectedColon,
201
1
        ErrorKind::ExpectedValue,
202
1
        ErrorKind::ExpectedCommaOrEndOfObject,
203
1
        ErrorKind::ExpectedCommaOrEndOfArray,
204
1
        ErrorKind::IllegalTrailingComma,
205
1
        ErrorKind::Unexpected(b'/'),
206
1
        ErrorKind::TrailingNonWhitespace,
207
1
        ErrorKind::ObjectKeysMustBeStrings,
208
1
        ErrorKind::ExpectedExponent,
209
1
        ErrorKind::ExpectedDecimalDigit,
210
1
        ErrorKind::ExpectedDigit,
211
1
        ErrorKind::InvalidHexadecimal,
212
1
        ErrorKind::InvalidEscape,
213
1
        ErrorKind::UnclosedObject,
214
1
        ErrorKind::UnclosedArray,
215
1
        ErrorKind::UnclosedString,
216
1
        ErrorKind::ExpectedString,
217
1
        ErrorKind::ExpectedNumber,
218
1
        ErrorKind::RecursionLimitReached,
219
1
        ErrorKind::PayloadsShouldBeObjectOrArray,
220
1
        ErrorKind::PaylodTooLarge,
221
    ] {
222
24
        match (kind.clone(), kind.into_fallable::<u8>()) {
223
            (ErrorKind::Utf8, ErrorKind::Utf8)
224
            | (ErrorKind::UnexpectedEof, ErrorKind::UnexpectedEof)
225
            | (ErrorKind::ExpectedObjectKey, ErrorKind::ExpectedObjectKey)
226
            | (ErrorKind::ExpectedColon, ErrorKind::ExpectedColon)
227
            | (ErrorKind::ExpectedValue, ErrorKind::ExpectedValue)
228
            | (ErrorKind::ExpectedCommaOrEndOfObject, ErrorKind::ExpectedCommaOrEndOfObject)
229
            | (ErrorKind::ExpectedCommaOrEndOfArray, ErrorKind::ExpectedCommaOrEndOfArray)
230
            | (ErrorKind::IllegalTrailingComma, ErrorKind::IllegalTrailingComma)
231
            | (ErrorKind::TrailingNonWhitespace, ErrorKind::TrailingNonWhitespace)
232
            | (ErrorKind::ObjectKeysMustBeStrings, ErrorKind::ObjectKeysMustBeStrings)
233
            | (ErrorKind::ExpectedExponent, ErrorKind::ExpectedExponent)
234
            | (ErrorKind::ExpectedDecimalDigit, ErrorKind::ExpectedDecimalDigit)
235
            | (ErrorKind::ExpectedDigit, ErrorKind::ExpectedDigit)
236
            | (ErrorKind::InvalidHexadecimal, ErrorKind::InvalidHexadecimal)
237
            | (ErrorKind::InvalidEscape, ErrorKind::InvalidEscape)
238
            | (ErrorKind::UnclosedObject, ErrorKind::UnclosedObject)
239
            | (ErrorKind::UnclosedArray, ErrorKind::UnclosedArray)
240
            | (ErrorKind::UnclosedString, ErrorKind::UnclosedString)
241
            | (ErrorKind::ExpectedString, ErrorKind::ExpectedString)
242
            | (ErrorKind::ExpectedNumber, ErrorKind::ExpectedNumber)
243
            | (ErrorKind::RecursionLimitReached, ErrorKind::RecursionLimitReached)
244
            | (ErrorKind::PaylodTooLarge, ErrorKind::PaylodTooLarge)
245
            | (
246
                ErrorKind::PayloadsShouldBeObjectOrArray,
247
                ErrorKind::PayloadsShouldBeObjectOrArray,
248
23
            ) => {}
249
1
            (ErrorKind::Unexpected(before), ErrorKind::Unexpected(after)) => {
250
1
                assert_eq!(before, after);
251
            }
252
            _ => unreachable!(),
253
        }
254
    }
255
1
}
256

            
257
1
#[test]
258
1
fn into_infallable_test() {
259
25
    for kind in [
260
1
        ErrorKind::Utf8,
261
1
        ErrorKind::UnexpectedEof,
262
1
        ErrorKind::ExpectedObjectKey,
263
1
        ErrorKind::ExpectedColon,
264
1
        ErrorKind::ExpectedValue,
265
1
        ErrorKind::ExpectedCommaOrEndOfObject,
266
1
        ErrorKind::ExpectedCommaOrEndOfArray,
267
1
        ErrorKind::IllegalTrailingComma,
268
1
        ErrorKind::Unexpected(b'/'),
269
1
        ErrorKind::TrailingNonWhitespace,
270
1
        ErrorKind::ObjectKeysMustBeStrings,
271
1
        ErrorKind::ExpectedExponent,
272
1
        ErrorKind::ExpectedDecimalDigit,
273
1
        ErrorKind::ExpectedDigit,
274
1
        ErrorKind::InvalidHexadecimal,
275
1
        ErrorKind::InvalidEscape,
276
1
        ErrorKind::UnclosedObject,
277
1
        ErrorKind::UnclosedArray,
278
1
        ErrorKind::UnclosedString,
279
1
        ErrorKind::ExpectedString,
280
1
        ErrorKind::ExpectedNumber,
281
1
        ErrorKind::RecursionLimitReached,
282
1
        ErrorKind::PayloadsShouldBeObjectOrArray,
283
1
        ErrorKind::PaylodTooLarge,
284
1
        ErrorKind::ErrorFromDelegate(ErrorKind::ExpectedColon),
285
    ] {
286
25
        match (kind.clone(), kind.into_infallable()) {
287
            (ErrorKind::Utf8, ErrorKind::Utf8)
288
            | (ErrorKind::UnexpectedEof, ErrorKind::UnexpectedEof)
289
            | (ErrorKind::ExpectedObjectKey, ErrorKind::ExpectedObjectKey)
290
            | (ErrorKind::ExpectedColon, ErrorKind::ExpectedColon)
291
            | (ErrorKind::ExpectedValue, ErrorKind::ExpectedValue)
292
            | (ErrorKind::ExpectedCommaOrEndOfObject, ErrorKind::ExpectedCommaOrEndOfObject)
293
            | (ErrorKind::ExpectedCommaOrEndOfArray, ErrorKind::ExpectedCommaOrEndOfArray)
294
            | (ErrorKind::IllegalTrailingComma, ErrorKind::IllegalTrailingComma)
295
            | (ErrorKind::TrailingNonWhitespace, ErrorKind::TrailingNonWhitespace)
296
            | (ErrorKind::ObjectKeysMustBeStrings, ErrorKind::ObjectKeysMustBeStrings)
297
            | (ErrorKind::ExpectedExponent, ErrorKind::ExpectedExponent)
298
            | (ErrorKind::ExpectedDecimalDigit, ErrorKind::ExpectedDecimalDigit)
299
            | (ErrorKind::ExpectedDigit, ErrorKind::ExpectedDigit)
300
            | (ErrorKind::InvalidHexadecimal, ErrorKind::InvalidHexadecimal)
301
            | (ErrorKind::InvalidEscape, ErrorKind::InvalidEscape)
302
            | (ErrorKind::UnclosedObject, ErrorKind::UnclosedObject)
303
            | (ErrorKind::UnclosedArray, ErrorKind::UnclosedArray)
304
            | (ErrorKind::UnclosedString, ErrorKind::UnclosedString)
305
            | (ErrorKind::ExpectedString, ErrorKind::ExpectedString)
306
            | (ErrorKind::ExpectedNumber, ErrorKind::ExpectedNumber)
307
            | (ErrorKind::RecursionLimitReached, ErrorKind::RecursionLimitReached)
308
            | (ErrorKind::PaylodTooLarge, ErrorKind::PaylodTooLarge)
309
            | (
310
                ErrorKind::PayloadsShouldBeObjectOrArray,
311
                ErrorKind::PayloadsShouldBeObjectOrArray,
312
23
            ) => {}
313
1
            (ErrorKind::Unexpected(before), ErrorKind::Unexpected(after)) => {
314
1
                assert_eq!(before, after);
315
            }
316
1
            (ErrorKind::ErrorFromDelegate(before), after) => {
317
1
                assert_eq!(before, after);
318
            }
319
            _ => unreachable!(),
320
        }
321
    }
322
1
}
323

            
324
#[cfg(feature = "std")]
325
impl<DelegateError> std::error::Error for ErrorKind<DelegateError> where
326
    DelegateError: std::fmt::Debug + Display
327
{
328
}
329

            
330
impl<DelegateError> Display for ErrorKind<DelegateError>
331
where
332
    DelegateError: Display,
333
{
334
25
    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
335
25
        match self {
336
1
            ErrorKind::Utf8 => f.write_str("invalid utf-8"),
337
1
            ErrorKind::UnexpectedEof => f.write_str("unexpected end of file"),
338
1
            ErrorKind::ExpectedObjectKey => f.write_str("expected object key"),
339
1
            ErrorKind::ExpectedColon => f.write_str("expected colon (':')"),
340
1
            ErrorKind::ExpectedValue => f.write_str("expected value"),
341
1
            ErrorKind::ExpectedCommaOrEndOfObject => f.write_str("expected comma or end of object"),
342
1
            ErrorKind::ExpectedCommaOrEndOfArray => f.write_str("expected comma or end of array"),
343
1
            ErrorKind::IllegalTrailingComma => f.write_str("trailing commas are not allowed"),
344
1
            ErrorKind::Unexpected(ch) => write!(f, "unexpected character: '{ch}'"),
345
            ErrorKind::TrailingNonWhitespace => {
346
1
                f.write_str("trailing non-whitespace data was encountered")
347
            }
348
1
            ErrorKind::ObjectKeysMustBeStrings => f.write_str("object keys must be strings"),
349
            ErrorKind::ExpectedExponent => {
350
1
                f.write_str("expected exponent sign or digit for number literal")
351
            }
352
            ErrorKind::ExpectedDecimalDigit => {
353
1
                f.write_str("expected decimal digit for number literal")
354
            }
355
1
            ErrorKind::ExpectedDigit => f.write_str("expected decimal digit for number literal"),
356
            ErrorKind::InvalidHexadecimal => {
357
1
                f.write_str("invalid hexadecimal in unicode escape sequence")
358
            }
359
1
            ErrorKind::InvalidEscape => f.write_str("invalid escaped character"),
360
1
            ErrorKind::UnclosedObject => f.write_str("expected end of object ('}}')"),
361
1
            ErrorKind::UnclosedArray => f.write_str("expected end of array (']')"),
362
1
            ErrorKind::UnclosedString => f.write_str("expected end of string ('\"')"),
363
1
            ErrorKind::ExpectedString => f.write_str("expected a string"),
364
1
            ErrorKind::ExpectedNumber => f.write_str("expected a number"),
365
1
            ErrorKind::RecursionLimitReached => f.write_str("the recursion limit has been reached"),
366
            ErrorKind::PayloadsShouldBeObjectOrArray => {
367
1
                f.write_str("JSON only allows objects or arrays at the root")
368
            }
369
            ErrorKind::PaylodTooLarge => {
370
1
                f.write_str("the payload is too large to be parsed into the destination structure")
371
            }
372
1
            ErrorKind::ErrorFromDelegate(err) => write!(f, "error from delegate: {err}"),
373
        }
374
25
    }
375
}
376

            
377
1
#[test]
378
#[cfg(feature = "alloc")]
379
1
fn display_tests() {
380
    use alloc::string::ToString;
381
    // This test only ensures that display doesn't panic. It does not validate
382
    // that the messages are actually good.
383
25
    for kind in [
384
1
        ErrorKind::Utf8,
385
1
        ErrorKind::UnexpectedEof,
386
1
        ErrorKind::ExpectedObjectKey,
387
1
        ErrorKind::ExpectedColon,
388
1
        ErrorKind::ExpectedValue,
389
1
        ErrorKind::ExpectedCommaOrEndOfObject,
390
1
        ErrorKind::ExpectedCommaOrEndOfArray,
391
1
        ErrorKind::IllegalTrailingComma,
392
1
        ErrorKind::Unexpected(b'/'),
393
1
        ErrorKind::TrailingNonWhitespace,
394
1
        ErrorKind::ObjectKeysMustBeStrings,
395
1
        ErrorKind::ExpectedExponent,
396
1
        ErrorKind::ExpectedDecimalDigit,
397
1
        ErrorKind::ExpectedDigit,
398
1
        ErrorKind::InvalidHexadecimal,
399
1
        ErrorKind::InvalidEscape,
400
1
        ErrorKind::UnclosedObject,
401
1
        ErrorKind::UnclosedArray,
402
1
        ErrorKind::UnclosedString,
403
1
        ErrorKind::ExpectedString,
404
1
        ErrorKind::ExpectedNumber,
405
1
        ErrorKind::RecursionLimitReached,
406
1
        ErrorKind::PayloadsShouldBeObjectOrArray,
407
1
        ErrorKind::PaylodTooLarge,
408
1
        ErrorKind::ErrorFromDelegate("oops"),
409
25
    ] {
410
25
        Error { kind, offset: 0 }.to_string();
411
25
    }
412
1
}