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