use core::result;
use std::{
error,
fmt::{self, Debug, Display},
io,
};
use serde::{de, ser};
pub struct Error {
err: Box<ErrorImpl>,
}
struct ErrorImpl {
code: ErrorCode,
input: Option<u8>,
pos: Option<usize>,
}
pub type Result<T> = result::Result<T, Error>;
impl Error {
pub fn position(&self) -> Option<usize> {
self.err.pos
}
pub fn classify(&self) -> Category {
match self.err.code {
ErrorCode::Io(_) => Category::Io,
ErrorCode::Message(_) | ErrorCode::InvalidUnicodeCodePoint => Category::Data,
ErrorCode::EofWhileParsingElementType | ErrorCode::EofWhileParsingKey | ErrorCode::EofWhileParsingValue => Category::Eof,
}
}
pub fn is_io(&self) -> bool {
self.classify() == Category::Io
}
pub fn is_data(&self) -> bool {
self.classify() == Category::Data
}
pub fn is_eof(&self) -> bool {
self.classify() == Category::Eof
}
pub(crate) fn io(e: io::Error, pos: Option<usize>) -> Self {
Self {
err: Box::new(ErrorImpl {
code: ErrorCode::Io(e),
input: None,
pos,
}),
}
}
pub(crate) fn data(code: ErrorCode, input: Option<u8>, pos: Option<usize>) -> Self {
Self {
err: Box::new(ErrorImpl { code, input, pos }),
}
}
}
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub enum Category {
Io,
Data,
Eof,
}
impl From<io::Error> for Error {
fn from(e: io::Error) -> Self {
Error::io(e, None)
}
}
impl From<Error> for io::Error {
fn from(e: Error) -> Self {
match e.classify() {
Category::Io => {
if let ErrorCode::Io(e) = e.err.code {
e
} else {
unreachable!()
}
},
Category::Data => io::Error::new(io::ErrorKind::InvalidData, e),
Category::Eof => io::Error::new(io::ErrorKind::UnexpectedEof, e),
}
}
}
pub(crate) enum ErrorCode {
Io(io::Error),
Message(String),
EofWhileParsingElementType,
EofWhileParsingKey,
EofWhileParsingValue,
InvalidUnicodeCodePoint,
}
impl Display for ErrorCode {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match *self {
ErrorCode::Io(ref err) => Display::fmt(err, f),
ErrorCode::Message(ref msg) => f.write_str(msg),
ErrorCode::EofWhileParsingElementType => f.write_str("EOF while parsing element type"),
ErrorCode::EofWhileParsingKey => f.write_str("EOF while parsing key"),
ErrorCode::EofWhileParsingValue => f.write_str("EOF while parsing value"),
ErrorCode::InvalidUnicodeCodePoint => f.write_str("invalid unicode code point"),
}
}
}
impl error::Error for Error {
fn source(&self) -> Option<&(dyn error::Error + 'static)> {
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 {
Display::fmt(&self.code, f)?;
if let Some(input) = self.input {
f.write_fmt(format_args!(" 0x{input:x}"))?;
}
if let Some(pos) = self.pos {
f.write_fmt(format_args!(" at position {pos}"))?;
}
Ok(())
}
}
impl Debug for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "Error({:?})", self.err.to_string())
}
}
impl de::Error for Error {
fn custom<T: Display>(msg: T) -> Self {
make_error(msg.to_string(), None)
}
}
impl ser::Error for Error {
fn custom<T: Display>(msg: T) -> Self {
make_error(msg.to_string(), None)
}
}
fn make_error(msg: String, pos: Option<usize>) -> Error {
let input = None;
let code = ErrorCode::Message(msg);
Error {
err: Box::new(ErrorImpl { code, input, pos }),
}
}