]> git.proxmox.com Git - rustc.git/blame - src/vendor/serde_json/src/error.rs
New upstream version 1.23.0+dfsg1
[rustc.git] / src / vendor / serde_json / src / error.rs
CommitLineData
041b39d2
XL
1// Copyright 2017 Serde Developers
2//
3// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
4// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
5// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
6// option. This file may not be copied, modified, or distributed
7// except according to those terms.
8
7cac9316
XL
9//! When serializing or deserializing JSON goes wrong.
10
11use std::error;
12use std::fmt::{self, Debug, Display};
13use std::io;
14use std::result;
15
16use serde::de;
17use serde::ser;
18
19/// This type represents all possible errors that can occur when serializing or
20/// deserializing JSON data.
21pub struct Error {
22 /// This `Box` allows us to keep the size of `Error` as small as possible. A
23 /// larger `Error` type was substantially slower due to all the functions
24 /// that pass around `Result<T, Error>`.
25 err: Box<ErrorImpl>,
26}
27
28/// Alias for a `Result` with the error type `serde_json::Error`.
29pub type Result<T> = result::Result<T, Error>;
30
31impl Error {
32 /// One-based line number at which the error was detected.
33 ///
34 /// Characters in the first line of the input (before the first newline
35 /// character) are in line 1.
36 pub fn line(&self) -> usize {
37 self.err.line
38 }
39
40 /// One-based column number at which the error was detected.
41 ///
42 /// The first character in the input and any characters immediately
43 /// following a newline character are in column 1.
44 ///
45 /// Note that errors may occur in column 0, for example if a read from an IO
46 /// stream fails immediately following a previously read newline character.
47 pub fn column(&self) -> usize {
48 self.err.column
49 }
50
51 /// Categorizes the cause of this error.
52 ///
53 /// - `Category::Io` - failure to read or write bytes on an IO stream
54 /// - `Category::Syntax` - input that is not syntactically valid JSON
55 /// - `Category::Data` - input data that is semantically incorrect
56 /// - `Category::Eof` - unexpected end of the input data
57 pub fn classify(&self) -> Category {
58 match self.err.code {
59 ErrorCode::Message(_) => Category::Data,
60 ErrorCode::Io(_) => Category::Io,
61 ErrorCode::EofWhileParsingList |
62 ErrorCode::EofWhileParsingObject |
63 ErrorCode::EofWhileParsingString |
64 ErrorCode::EofWhileParsingValue => Category::Eof,
65 ErrorCode::ExpectedColon |
66 ErrorCode::ExpectedListCommaOrEnd |
67 ErrorCode::ExpectedObjectCommaOrEnd |
041b39d2 68 ErrorCode::ExpectedObjectOrArray |
7cac9316
XL
69 ErrorCode::ExpectedSomeIdent |
70 ErrorCode::ExpectedSomeValue |
71 ErrorCode::ExpectedSomeString |
72 ErrorCode::InvalidEscape |
73 ErrorCode::InvalidNumber |
74 ErrorCode::NumberOutOfRange |
75 ErrorCode::InvalidUnicodeCodePoint |
76 ErrorCode::KeyMustBeAString |
77 ErrorCode::LoneLeadingSurrogateInHexEscape |
abe05a73 78 ErrorCode::TrailingComma |
7cac9316
XL
79 ErrorCode::TrailingCharacters |
80 ErrorCode::UnexpectedEndOfHexEscape |
81 ErrorCode::RecursionLimitExceeded => Category::Syntax,
82 }
83 }
84
85 /// Returns true if this error was caused by a failure to read or write
86 /// bytes on an IO stream.
87 pub fn is_io(&self) -> bool {
88 self.classify() == Category::Io
89 }
90
91 /// Returns true if this error was caused by input that was not
92 /// syntactically valid JSON.
93 pub fn is_syntax(&self) -> bool {
94 self.classify() == Category::Syntax
95 }
96
97 /// Returns true if this error was caused by input data that was
98 /// semantically incorrect.
99 ///
100 /// For example, JSON containing a number is semantically incorrect when the
101 /// type being deserialized into holds a String.
102 pub fn is_data(&self) -> bool {
103 self.classify() == Category::Data
104 }
105
106 /// Returns true if this error was caused by prematurely reaching the end of
107 /// the input data.
108 ///
109 /// Callers that process streaming input may be interested in retrying the
110 /// deserialization once more data is available.
111 pub fn is_eof(&self) -> bool {
112 self.classify() == Category::Eof
113 }
114}
115
116/// Categorizes the cause of a `serde_json::Error`.
117#[derive(Copy, Clone, PartialEq, Eq, Debug)]
118pub enum Category {
119 /// The error was caused by a failure to read or write bytes on an IO
120 /// stream.
121 Io,
122
123 /// The error was caused by input that was not syntactically valid JSON.
124 Syntax,
125
126 /// The error was caused by input data that was semantically incorrect.
127 ///
128 /// For example, JSON containing a number is semantically incorrect when the
129 /// type being deserialized into holds a String.
130 Data,
131
132 /// The error was caused by prematurely reaching the end of the input data.
133 ///
134 /// Callers that process streaming input may be interested in retrying the
135 /// deserialization once more data is available.
136 Eof,
137}
138
abe05a73 139#[cfg_attr(feature = "cargo-clippy", allow(fallible_impl_from))]
041b39d2
XL
140impl From<Error> for io::Error {
141 /// Convert a `serde_json::Error` into an `io::Error`.
142 ///
143 /// JSON syntax and data errors are turned into `InvalidData` IO errors.
144 /// EOF errors are turned into `UnexpectedEof` IO errors.
145 ///
146 /// ```rust
147 /// use std::io;
148 ///
149 /// enum MyError {
150 /// Io(io::Error),
151 /// Json(serde_json::Error),
152 /// }
153 ///
154 /// impl From<serde_json::Error> for MyError {
155 /// fn from(err: serde_json::Error) -> MyError {
156 /// use serde_json::error::Category;
157 /// match err.classify() {
158 /// Category::Io => {
159 /// MyError::Io(err.into())
160 /// }
161 /// Category::Syntax | Category::Data | Category::Eof => {
162 /// MyError::Json(err)
163 /// }
164 /// }
165 /// }
166 /// }
167 /// ```
168 fn from(j: Error) -> Self {
169 if let ErrorCode::Io(err) = j.err.code {
170 err
171 } else {
172 match j.classify() {
173 Category::Io => unreachable!(),
174 Category::Syntax | Category::Data => io::Error::new(io::ErrorKind::InvalidData, j),
175 Category::Eof => io::Error::new(io::ErrorKind::UnexpectedEof, j),
176 }
177 }
178 }
179}
180
7cac9316
XL
181#[derive(Debug)]
182struct ErrorImpl {
183 code: ErrorCode,
184 line: usize,
185 column: usize,
186}
187
188// Not public API. Should be pub(crate).
189#[doc(hidden)]
190#[derive(Debug)]
191pub enum ErrorCode {
192 /// Catchall for syntax error messages
193 Message(String),
194
195 /// Some IO error occurred while serializing or deserializing.
196 Io(io::Error),
197
198 /// EOF while parsing a list.
199 EofWhileParsingList,
200
201 /// EOF while parsing an object.
202 EofWhileParsingObject,
203
204 /// EOF while parsing a string.
205 EofWhileParsingString,
206
207 /// EOF while parsing a JSON value.
208 EofWhileParsingValue,
209
210 /// Expected this character to be a `':'`.
211 ExpectedColon,
212
041b39d2 213 /// Expected this character to be either a `','` or a `']'`.
7cac9316
XL
214 ExpectedListCommaOrEnd,
215
041b39d2 216 /// Expected this character to be either a `','` or a `'}'`.
7cac9316
XL
217 ExpectedObjectCommaOrEnd,
218
041b39d2
XL
219 /// Expected this character to be either a `'{'` or a `'['`.
220 ExpectedObjectOrArray,
221
7cac9316
XL
222 /// Expected to parse either a `true`, `false`, or a `null`.
223 ExpectedSomeIdent,
224
225 /// Expected this character to start a JSON value.
226 ExpectedSomeValue,
227
228 /// Expected this character to start a JSON string.
229 ExpectedSomeString,
230
231 /// Invalid hex escape code.
232 InvalidEscape,
233
234 /// Invalid number.
235 InvalidNumber,
236
237 /// Number is bigger than the maximum value of its type.
238 NumberOutOfRange,
239
240 /// Invalid unicode code point.
241 InvalidUnicodeCodePoint,
242
243 /// Object key is not a string.
244 KeyMustBeAString,
245
246 /// Lone leading surrogate in hex escape.
247 LoneLeadingSurrogateInHexEscape,
248
abe05a73
XL
249 /// JSON has a comma after the last value in an array or map.
250 TrailingComma,
251
7cac9316
XL
252 /// JSON has non-whitespace trailing characters after the value.
253 TrailingCharacters,
254
255 /// Unexpected end of hex excape.
256 UnexpectedEndOfHexEscape,
257
258 /// Encountered nesting of JSON maps and arrays more than 128 layers deep.
259 RecursionLimitExceeded,
260}
261
262impl Error {
263 // Not public API. Should be pub(crate).
264 #[doc(hidden)]
265 pub fn syntax(code: ErrorCode, line: usize, column: usize) -> Self {
266 Error {
041b39d2
XL
267 err: Box::new(
268 ErrorImpl {
269 code: code,
270 line: line,
271 column: column,
272 },
273 ),
274 }
275 }
276
277 // Not public API. Should be pub(crate).
278 #[doc(hidden)]
279 pub fn io(error: io::Error) -> Self {
280 Error {
281 err: Box::new(
282 ErrorImpl {
283 code: ErrorCode::Io(error),
284 line: 0,
285 column: 0,
286 },
287 ),
7cac9316
XL
288 }
289 }
290
291 // Not public API. Should be pub(crate).
292 #[doc(hidden)]
293 pub fn fix_position<F>(self, f: F) -> Self
041b39d2
XL
294 where
295 F: FnOnce(ErrorCode) -> Error,
7cac9316
XL
296 {
297 if self.err.line == 0 {
298 f(self.err.code)
299 } else {
300 self
301 }
302 }
303}
304
305impl Display for ErrorCode {
306 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
307 match *self {
308 ErrorCode::Message(ref msg) => f.write_str(msg),
309 ErrorCode::Io(ref err) => Display::fmt(err, f),
041b39d2
XL
310 ErrorCode::EofWhileParsingList => f.write_str("EOF while parsing a list"),
311 ErrorCode::EofWhileParsingObject => f.write_str("EOF while parsing an object"),
312 ErrorCode::EofWhileParsingString => f.write_str("EOF while parsing a string"),
313 ErrorCode::EofWhileParsingValue => f.write_str("EOF while parsing a value"),
314 ErrorCode::ExpectedColon => f.write_str("expected `:`"),
315 ErrorCode::ExpectedListCommaOrEnd => f.write_str("expected `,` or `]`"),
316 ErrorCode::ExpectedObjectCommaOrEnd => f.write_str("expected `,` or `}`"),
317 ErrorCode::ExpectedObjectOrArray => f.write_str("expected `{` or `[`"),
318 ErrorCode::ExpectedSomeIdent => f.write_str("expected ident"),
319 ErrorCode::ExpectedSomeValue => f.write_str("expected value"),
320 ErrorCode::ExpectedSomeString => f.write_str("expected string"),
321 ErrorCode::InvalidEscape => f.write_str("invalid escape"),
322 ErrorCode::InvalidNumber => f.write_str("invalid number"),
323 ErrorCode::NumberOutOfRange => f.write_str("number out of range"),
324 ErrorCode::InvalidUnicodeCodePoint => f.write_str("invalid unicode code point"),
325 ErrorCode::KeyMustBeAString => f.write_str("key must be a string"),
7cac9316
XL
326 ErrorCode::LoneLeadingSurrogateInHexEscape => {
327 f.write_str("lone leading surrogate in hex escape")
328 }
abe05a73 329 ErrorCode::TrailingComma => f.write_str("trailing comma"),
041b39d2
XL
330 ErrorCode::TrailingCharacters => f.write_str("trailing characters"),
331 ErrorCode::UnexpectedEndOfHexEscape => f.write_str("unexpected end of hex escape"),
332 ErrorCode::RecursionLimitExceeded => f.write_str("recursion limit exceeded"),
7cac9316
XL
333 }
334 }
335}
336
337impl error::Error for Error {
338 fn description(&self) -> &str {
339 match self.err.code {
340 ErrorCode::Io(ref err) => error::Error::description(err),
341 _ => {
342 // If you want a better message, use Display::fmt or to_string().
343 "JSON error"
344 }
345 }
346 }
347
348 fn cause(&self) -> Option<&error::Error> {
349 match self.err.code {
350 ErrorCode::Io(ref err) => Some(err),
351 _ => None,
352 }
353 }
354}
355
356impl Display for Error {
357 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
358 Display::fmt(&*self.err, f)
359 }
360}
361
362impl Display for ErrorImpl {
363 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
364 if self.line == 0 {
365 Display::fmt(&self.code, f)
366 } else {
041b39d2
XL
367 write!(
368 f,
369 "{} at line {} column {}",
370 self.code,
371 self.line,
372 self.column
373 )
7cac9316
XL
374 }
375 }
376}
377
378// Remove two layers of verbosity from the debug representation. Humans often
379// end up seeing this representation because it is what unwrap() shows.
380impl Debug for Error {
381 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
382 Debug::fmt(&*self.err, f)
383 }
384}
385
7cac9316
XL
386impl de::Error for Error {
387 fn custom<T: Display>(msg: T) -> Error {
388 Error {
041b39d2
XL
389 err: Box::new(
390 ErrorImpl {
391 code: ErrorCode::Message(msg.to_string()),
392 line: 0,
393 column: 0,
394 },
395 ),
7cac9316
XL
396 }
397 }
ea8adc8c
XL
398
399 fn invalid_type(unexp: de::Unexpected, exp: &de::Expected) -> Self {
400 if let de::Unexpected::Unit = unexp {
401 Error::custom(format_args!("invalid type: null, expected {}", exp))
402 } else {
403 Error::custom(format_args!("invalid type: {}, expected {}", unexp, exp))
404 }
405 }
7cac9316
XL
406}
407
408impl ser::Error for Error {
409 fn custom<T: Display>(msg: T) -> Error {
410 Error {
041b39d2
XL
411 err: Box::new(
412 ErrorImpl {
413 code: ErrorCode::Message(msg.to_string()),
414 line: 0,
415 column: 0,
416 },
417 ),
7cac9316
XL
418 }
419 }
420}