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