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>;
enum ErrorImpl {
Syntax(ErrorCode, usize, usize),
Io(io::Error),
}
#[doc(hidden)]
#[derive(Clone, PartialEq, Debug)]
pub enum ErrorCode {
Message(String),
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, col: usize) -> Self {
Error {
err: Box::new(ErrorImpl::Syntax(code, line, col)),
}
}
#[doc(hidden)]
pub fn fix_position<F>(self, f: F) -> Self
where F: FnOnce(ErrorCode) -> Error
{
if let ErrorImpl::Syntax(code, 0, 0) = *self.err {
f(code)
} else {
self
}
}
}
impl Display for ErrorCode {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
ErrorCode::Message(ref msg) => write!(f, "{}", msg),
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 {
ErrorImpl::Syntax(..) => {
"JSON error"
}
ErrorImpl::Io(ref error) => error::Error::description(error),
}
}
fn cause(&self) -> Option<&error::Error> {
match *self.err {
ErrorImpl::Io(ref error) => Some(error),
_ => None,
}
}
}
impl Display for Error {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
match *self.err {
ErrorImpl::Syntax(ref code, line, col) => {
if line == 0 && col == 0 {
write!(fmt, "{}", code)
} else {
write!(fmt, "{} at line {} column {}", code, line, col)
}
}
ErrorImpl::Io(ref error) => fmt::Display::fmt(error, fmt),
}
}
}
impl Debug for Error {
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
match *self.err {
ErrorImpl::Syntax(ref code, ref line, ref col) => {
formatter.debug_tuple("Syntax")
.field(code)
.field(line)
.field(col)
.finish()
}
ErrorImpl::Io(ref io) => {
formatter.debug_tuple("Io")
.field(io)
.finish()
}
}
}
}
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::Io(error)),
}
}
}
impl From<de::value::Error> for Error {
fn from(error: de::value::Error) -> Error {
Error {
err: Box::new(ErrorImpl::Syntax(ErrorCode::Message(error.to_string()), 0, 0)),
}
}
}
impl de::Error for Error {
fn custom<T: Display>(msg: T) -> Error {
Error {
err: Box::new(ErrorImpl::Syntax(ErrorCode::Message(msg.to_string()), 0, 0)),
}
}
}
impl ser::Error for Error {
fn custom<T: Display>(msg: T) -> Error {
Error {
err: Box::new(ErrorImpl::Syntax(ErrorCode::Message(msg.to_string()), 0, 0)),
}
}
}