use std::error;
use std::fmt::{self, Debug, Display};
use std::io;
use std::result;
use serde::de;
use serde::ser;
pub struct Error {
err: Box<ErrorImpl>,
}
pub type Result<T> = result::Result<T, Error>;
impl Error {
pub fn line(&self) -> usize {
self.err.line
}
pub fn column(&self) -> usize {
self.err.column
}
pub fn classify(&self) -> Category {
match self.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::ExpectedSomeString |
ErrorCode::InvalidEscape |
ErrorCode::InvalidNumber |
ErrorCode::NumberOutOfRange |
ErrorCode::InvalidUnicodeCodePoint |
ErrorCode::KeyMustBeAString |
ErrorCode::LoneLeadingSurrogateInHexEscape |
ErrorCode::TrailingCharacters |
ErrorCode::UnexpectedEndOfHexEscape |
ErrorCode::RecursionLimitExceeded => Category::Syntax,
}
}
pub fn is_io(&self) -> bool {
self.classify() == Category::Io
}
pub fn is_syntax(&self) -> bool {
self.classify() == Category::Syntax
}
pub fn is_data(&self) -> bool {
self.classify() == Category::Data
}
pub fn is_eof(&self) -> bool {
self.classify() == Category::Eof
}
}
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub enum Category {
Io,
Syntax,
Data,
Eof,
}
#[derive(Debug)]
struct ErrorImpl {
code: ErrorCode,
line: usize,
column: usize,
}
#[doc(hidden)]
#[derive(Debug)]
pub enum ErrorCode {
Message(String),
Io(io::Error),
EofWhileParsingList,
EofWhileParsingObject,
EofWhileParsingString,
EofWhileParsingValue,
ExpectedColon,
ExpectedListCommaOrEnd,
ExpectedObjectCommaOrEnd,
ExpectedSomeIdent,
ExpectedSomeValue,
ExpectedSomeString,
InvalidEscape,
InvalidNumber,
NumberOutOfRange,
InvalidUnicodeCodePoint,
KeyMustBeAString,
LoneLeadingSurrogateInHexEscape,
TrailingCharacters,
UnexpectedEndOfHexEscape,
RecursionLimitExceeded,
}
impl Error {
#[doc(hidden)]
pub fn syntax(code: ErrorCode, line: usize, column: usize) -> Self {
Error {
err: Box::new(ErrorImpl { code: code, line: line, column: column }),
}
}
#[doc(hidden)]
pub fn fix_position<F>(self, f: F) -> Self
where F: FnOnce(ErrorCode) -> Error
{
if self.err.line == 0 {
f(self.err.code)
} else {
self
}
}
}
impl Display for ErrorCode {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
ErrorCode::Message(ref msg) => f.write_str(msg),
ErrorCode::Io(ref err) => Display::fmt(err, f),
ErrorCode::EofWhileParsingList => {
f.write_str("EOF while parsing a list")
}
ErrorCode::EofWhileParsingObject => {
f.write_str("EOF while parsing an object")
}
ErrorCode::EofWhileParsingString => {
f.write_str("EOF while parsing a string")
}
ErrorCode::EofWhileParsingValue => {
f.write_str("EOF while parsing a value")
}
ErrorCode::ExpectedColon => {
f.write_str("expected `:`")
}
ErrorCode::ExpectedListCommaOrEnd => {
f.write_str("expected `,` or `]`")
}
ErrorCode::ExpectedObjectCommaOrEnd => {
f.write_str("expected `,` or `}`")
}
ErrorCode::ExpectedSomeIdent => {
f.write_str("expected ident")
}
ErrorCode::ExpectedSomeValue => {
f.write_str("expected value")
}
ErrorCode::ExpectedSomeString => {
f.write_str("expected string")
}
ErrorCode::InvalidEscape => {
f.write_str("invalid escape")
}
ErrorCode::InvalidNumber => {
f.write_str("invalid number")
}
ErrorCode::NumberOutOfRange => {
f.write_str("number out of range")
}
ErrorCode::InvalidUnicodeCodePoint => {
f.write_str("invalid unicode code point")
}
ErrorCode::KeyMustBeAString => {
f.write_str("key must be a string")
}
ErrorCode::LoneLeadingSurrogateInHexEscape => {
f.write_str("lone leading surrogate in hex escape")
}
ErrorCode::TrailingCharacters => {
f.write_str("trailing characters")
}
ErrorCode::UnexpectedEndOfHexEscape => {
f.write_str("unexpected end of hex escape")
}
ErrorCode::RecursionLimitExceeded => {
f.write_str("recursion limit exceeded")
}
}
}
}
impl error::Error for Error {
fn description(&self) -> &str {
match self.err.code {
ErrorCode::Io(ref err) => error::Error::description(err),
_ => {
"JSON error"
}
}
}
fn cause(&self) -> Option<&error::Error> {
match self.err.code {
ErrorCode::Io(ref err) => Some(err),
_ => None,
}
}
}
impl Display for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
Display::fmt(&*self.err, f)
}
}
impl Display for ErrorImpl {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
if self.line == 0 {
Display::fmt(&self.code, f)
} else {
write!(f, "{} at line {} column {}", self.code, self.line, self.column)
}
}
}
impl Debug for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
Debug::fmt(&*self.err, f)
}
}
impl From<ErrorImpl> for Error {
fn from(error: ErrorImpl) -> Error {
Error {
err: Box::new(error),
}
}
}
impl From<io::Error> for Error {
fn from(error: io::Error) -> Error {
Error {
err: Box::new(ErrorImpl { code: ErrorCode::Io(error), line: 0, column: 0 }),
}
}
}
impl From<de::value::Error> for Error {
fn from(error: de::value::Error) -> Error {
Error {
err: Box::new(ErrorImpl { code: ErrorCode::Message(error.to_string()), line: 0, column: 0 }),
}
}
}
impl de::Error for Error {
fn custom<T: Display>(msg: T) -> Error {
Error {
err: Box::new(ErrorImpl { code: ErrorCode::Message(msg.to_string()), line: 0, column: 0 }),
}
}
}
impl ser::Error for Error {
fn custom<T: Display>(msg: T) -> Error {
Error {
err: Box::new(ErrorImpl { code: ErrorCode::Message(msg.to_string()), line: 0, column: 0 }),
}
}
}