use std::fmt::{self, Debug, Display};
use std::{error, io, result};
use serde::{de, ser};
use lexpr::parse;
pub use lexpr::parse::error::Location;
pub struct Error(Box<ErrorImpl>);
pub type Result<T> = result::Result<T, Error>;
enum ErrorImpl {
Message(String, Option<Location>),
Io(io::Error),
Parse(parse::Error),
}
impl Error {
pub fn location(&self) -> Option<Location> {
match &*self.0 {
ErrorImpl::Message(_, loc) => *loc,
ErrorImpl::Parse(e) => e.location(),
ErrorImpl::Io(_) => None,
}
}
pub fn classify(&self) -> Category {
match &*self.0 {
ErrorImpl::Message(_, _) => Category::Data,
ErrorImpl::Io(_) => Category::Io,
ErrorImpl::Parse(e) => match e.classify() {
parse::error::Category::Syntax => Category::Syntax,
parse::error::Category::Io => Category::Io,
parse::error::Category::Eof => Category::Eof,
},
}
}
}
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub enum Category {
Io,
Syntax,
Data,
Eof,
}
impl From<Error> for io::Error {
fn from(l: Error) -> Self {
if let ErrorImpl::Io(err) = *l.0 {
err
} else {
match l.classify() {
Category::Io => unreachable!(),
Category::Syntax | Category::Data => io::Error::new(io::ErrorKind::InvalidData, l),
Category::Eof => io::Error::new(io::ErrorKind::UnexpectedEof, l),
}
}
}
}
impl error::Error for Error {
fn source(&self) -> Option<&(dyn error::Error + 'static)> {
match &*self.0 {
ErrorImpl::Io(e) => Some(e),
ErrorImpl::Parse(e) => Some(e),
_ => None,
}
}
}
impl Display for Error {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match &*self.0 {
ErrorImpl::Message(msg, _) => Display::fmt(msg, f),
ErrorImpl::Io(e) => Display::fmt(e, f),
ErrorImpl::Parse(e) => Display::fmt(e, f),
}
}
}
impl Debug for Error {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
match &*self.0 {
ErrorImpl::Message(msg, loc) => formatter
.debug_tuple("Message")
.field(msg)
.field(loc)
.finish(),
ErrorImpl::Io(e) => formatter.debug_tuple("Io").field(e).finish(),
ErrorImpl::Parse(e) => formatter.debug_tuple("Parse").field(e).finish(),
}
}
}
impl de::Error for Error {
fn custom<T: Display>(msg: T) -> Error {
Error(Box::new(ErrorImpl::Message(msg.to_string(), None)))
}
fn invalid_type(unexp: de::Unexpected<'_>, exp: &dyn de::Expected) -> Self {
if let de::Unexpected::Unit = unexp {
Error::custom(format_args!("invalid type: null, expected {}", exp))
} else {
Error::custom(format_args!("invalid type: {}, expected {}", unexp, exp))
}
}
}
impl ser::Error for Error {
fn custom<T: Display>(msg: T) -> Error {
Error(Box::new(ErrorImpl::Message(msg.to_string(), None)))
}
}
impl From<io::Error> for Error {
fn from(e: io::Error) -> Self {
Error(Box::new(ErrorImpl::Io(e)))
}
}
impl From<parse::Error> for Error {
fn from(e: parse::Error) -> Self {
Error(Box::new(ErrorImpl::Parse(e)))
}
}