//! When serializing or deserializing JSON goes wrong.
usecrate::io; use alloc::boxed::Box; use alloc::string::{String, ToString}; use core::fmt::{self, Debug, Display}; use core::result; use core::str::FromStr; use serde::{de, ser}; #[cfg(feature = "std")] use std::error; #[cfg(feature = "std")] use std::io::ErrorKind;
/// This type represents all possible errors that can occur when serializing or /// deserializing JSON data. pubstruct Error { /// This `Box` allows us to keep the size of `Error` as small as possible. A /// larger `Error` type was substantially slower due to all the functions /// that pass around `Result<T, Error>`.
err: Box<ErrorImpl>,
}
/// Alias for a `Result` with the error type `serde_json::Error`. pubtype Result<T> = result::Result<T, Error>;
impl Error { /// One-based line number at which the error was detected. /// /// Characters in the first line of the input (before the first newline /// character) are in line 1. pubfn line(&self) -> usize { self.err.line
}
/// One-based column number at which the error was detected. /// /// The first character in the input and any characters immediately /// following a newline character are in column 1. /// /// Note that errors may occur in column 0, for example if a read from an /// I/O stream fails immediately following a previously read newline /// character. pubfn column(&self) -> usize { self.err.column
}
/// Categorizes the cause of this error. /// /// - `Category::Io` - failure to read or write bytes on an I/O stream /// - `Category::Syntax` - input that is not syntactically valid JSON /// - `Category::Data` - input data that is semantically incorrect /// - `Category::Eof` - unexpected end of the input data pubfn classify(&self) -> Category { matchself.err.code {
ErrorCode::Message(_) => Category::Data,
ErrorCode::Io(_) => Category::Io,
ErrorCode::EofWhileParsingList
| ErrorCode::EofWhileParsingObject
| ErrorCode::EofWhileParsingString
| ErrorCode::EofWhileParsingValue => Category::Eof,
ErrorCode::ExpectedColon
| ErrorCode::ExpectedListCommaOrEnd
| ErrorCode::ExpectedObjectCommaOrEnd
| ErrorCode::ExpectedSomeIdent
| ErrorCode::ExpectedSomeValue
| ErrorCode::ExpectedDoubleQuote
| ErrorCode::InvalidEscape
| ErrorCode::InvalidNumber
| ErrorCode::NumberOutOfRange
| ErrorCode::InvalidUnicodeCodePoint
| ErrorCode::ControlCharacterWhileParsingString
| ErrorCode::KeyMustBeAString
| ErrorCode::ExpectedNumericKey
| ErrorCode::FloatKeyMustBeFinite
| ErrorCode::LoneLeadingSurrogateInHexEscape
| ErrorCode::TrailingComma
| ErrorCode::TrailingCharacters
| ErrorCode::UnexpectedEndOfHexEscape
| ErrorCode::RecursionLimitExceeded => Category::Syntax,
}
}
/// Returns true if this error was caused by a failure to read or write /// bytes on an I/O stream. pubfn is_io(&self) -> bool { self.classify() == Category::Io
}
/// Returns true if this error was caused by input that was not /// syntactically valid JSON. pubfn is_syntax(&self) -> bool { self.classify() == Category::Syntax
}
/// Returns true if this error was caused by input data that was /// semantically incorrect. /// /// For example, JSON containing a number is semantically incorrect when the /// type being deserialized into holds a String. pubfn is_data(&self) -> bool { self.classify() == Category::Data
}
/// Returns true if this error was caused by prematurely reaching the end of /// the input data. /// /// Callers that process streaming input may be interested in retrying the /// deserialization once more data is available. pubfn is_eof(&self) -> bool { self.classify() == Category::Eof
}
/// The kind reported by the underlying standard library I/O error, if this /// error was caused by a failure to read or write bytes on an I/O stream. /// /// # Example /// /// ``` /// use serde_json::Value; /// use std::io::{self, ErrorKind, Read}; /// use std::process; /// /// struct ReaderThatWillTimeOut<'a>(&'a [u8]); /// /// impl<'a> Read for ReaderThatWillTimeOut<'a> { /// fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> { /// if self.0.is_empty() { /// Err(io::Error::new(ErrorKind::TimedOut, "timed out")) /// } else { /// self.0.read(buf) /// } /// } /// } /// /// fn main() { /// let reader = ReaderThatWillTimeOut(br#" {"k": "#); /// /// let _: Value = match serde_json::from_reader(reader) { /// Ok(value) => value, /// Err(error) => { /// if error.io_error_kind() == Some(ErrorKind::TimedOut) { /// // Maybe this application needs to retry certain kinds of errors. /// /// # return; /// } else { /// eprintln!("error: {}", error); /// process::exit(1); /// } /// } /// }; /// } /// ``` #[cfg(feature = "std")] pubfn io_error_kind(&self) -> Option<ErrorKind> { iflet ErrorCode::Io(io_error) = &self.err.code {
Some(io_error.kind())
} else {
None
}
}
}
/// Categorizes the cause of a `serde_json::Error`. #[derive(Copy, Clone, PartialEq, Eq, Debug)] pubenum Category { /// The error was caused by a failure to read or write bytes on an I/O /// stream.
Io,
/// The error was caused by input that was not syntactically valid JSON.
Syntax,
/// The error was caused by input data that was semantically incorrect. /// /// For example, JSON containing a number is semantically incorrect when the /// type being deserialized into holds a String.
Data,
/// The error was caused by prematurely reaching the end of the input data. /// /// Callers that process streaming input may be interested in retrying the /// deserialization once more data is available.
Eof,
}
#[cfg(feature = "std")] #[allow(clippy::fallible_impl_from)] impl From<Error> for io::Error { /// Convert a `serde_json::Error` into an `io::Error`. /// /// JSON syntax and data errors are turned into `InvalidData` I/O errors. /// EOF errors are turned into `UnexpectedEof` I/O errors. /// /// ``` /// use std::io; /// /// enum MyError { /// Io(io::Error), /// Json(serde_json::Error), /// } /// /// impl From<serde_json::Error> for MyError { /// fn from(err: serde_json::Error) -> MyError { /// use serde_json::error::Category; /// match err.classify() { /// Category::Io => { /// MyError::Io(err.into()) /// } /// Category::Syntax | Category::Data | Category::Eof => { /// MyError::Json(err) /// } /// } /// } /// } /// ``` fn from(j: Error) -> Self { iflet ErrorCode::Io(err) = j.err.code {
err
} else { match j.classify() {
Category::Io => unreachable!(),
Category::Syntax | Category::Data => io::Error::new(ErrorKind::InvalidData, j),
Category::Eof => io::Error::new(ErrorKind::UnexpectedEof, j),
}
}
}
}
// Remove two layers of verbosity from the debug representation. Humans often // end up seeing this representation because it is what unwrap() shows. impl Debug for Error { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(
f, "Error({:?}, line: {}, column: {})", self.err.code.to_string(), self.err.line, self.err.column
)
}
}
// Parse our own error message that looks like "{} at line {} column {}" to work // around erased-serde round-tripping the error through de::Error::custom. fn make_error(mut msg: String) -> Error { let (line, column) = parse_line_col(&mut msg).unwrap_or((0, 0));
Error {
err: Box::new(ErrorImpl {
code: ErrorCode::Message(msg.into_boxed_str()),
line,
column,
}),
}
}
fn parse_line_col(msg: &mut String) -> Option<(usize, usize)> { let start_of_suffix = match msg.rfind(" at line ") {
Some(index) => index,
None => return None,
};
// Find start and end of line number. let start_of_line = start_of_suffix + " at line ".len(); letmut end_of_line = start_of_line; while starts_with_digit(&msg[end_of_line..]) {
end_of_line += 1;
}
if !msg[end_of_line..].starts_with(" column ") { return None;
}
// Find start and end of column number. let start_of_column = end_of_line + " column ".len(); letmut end_of_column = start_of_column; while starts_with_digit(&msg[end_of_column..]) {
end_of_column += 1;
}
if end_of_column < msg.len() { return None;
}
// Parse numbers. let line = match usize::from_str(&msg[start_of_line..end_of_line]) {
Ok(line) => line,
Err(_) => return None,
}; let column = match usize::from_str(&msg[start_of_column..end_of_column]) {
Ok(column) => column,
Err(_) => return None,
};
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.