use core::fmt;
use std::convert::Infallible;
use std::error::Error;
use std::io;
use std::num::ParseIntError;
use std::str::Utf8Error;
use std::string::FromUtf8Error;
#[derive(Debug, Clone)]
pub enum HttpErrorKind {
Unimplemented,
UnsupportedCharset,
UnsupportedContentEncoding,
ForbiddenOperation,
UnexpectedTransferEncodingSequence,
Parse,
Inner,
}
#[derive(Debug)]
pub struct HttpError {
pub source: Option<Box<dyn Error + Send + Sync>>,
pub kind: HttpErrorKind,
}
impl HttpError {
pub fn new_inner(source: Box<dyn Error + Send + Sync>) -> Self {
HttpError {
source: Some(source),
kind: HttpErrorKind::Inner,
}
}
pub fn new_kind(kind: HttpErrorKind) -> Self {
HttpError { source: None, kind }
}
pub fn is_io_error(&self) -> bool {
if !matches!(self.kind, HttpErrorKind::Inner) {
return false;
}
matches!(self.source().unwrap().downcast_ref::<io::Error>(), Some(_))
}
}
impl Error for HttpError {
fn source(&self) -> Option<&(dyn Error + 'static)> {
self.source.as_deref().map(|e| e as &(dyn Error + 'static))
}
}
impl HttpErrorKind {
pub fn into_boxed_error(self) -> Box<dyn Error + Send + Sync> {
let error: HttpError = self.into();
error.into()
}
}
impl fmt::Display for HttpErrorKind {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
HttpErrorKind::Unimplemented => write!(f, "not implemented"),
HttpErrorKind::UnsupportedCharset => write!(f, "unsupported chearset found"),
HttpErrorKind::UnsupportedContentEncoding => {
write!(f, "unsupported content-encoding value found")
}
HttpErrorKind::ForbiddenOperation => write!(f, "forbidden operation"),
HttpErrorKind::UnexpectedTransferEncodingSequence => {
write!(f, "unexpected transfer-encoding sequence found")
}
HttpErrorKind::Parse => write!(f, "unexpected value"),
HttpErrorKind::Inner => write!(f, "inner error in HttpError::source"),
}
}
}
impl fmt::Display for HttpError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self.kind {
HttpErrorKind::Inner => write!(f, "{}", self.source.as_ref().unwrap()),
_ => write!(f, "{}", self.kind),
}
}
}
impl From<HttpErrorKind> for HttpError {
fn from(kind: HttpErrorKind) -> Self {
Self::new_kind(kind)
}
}
impl From<Box<dyn Error + Send + Sync>> for HttpError {
fn from(err: Box<dyn Error + Send + Sync>) -> Self {
Self::new_inner(err)
}
}
impl From<io::Error> for HttpError {
fn from(error: io::Error) -> Self {
Self::new_inner(error.into())
}
}
impl From<ParseIntError> for HttpError {
fn from(error: ParseIntError) -> Self {
Self::new_inner(error.into())
}
}
impl From<FromUtf8Error> for HttpError {
fn from(error: FromUtf8Error) -> Self {
Self::new_inner(error.into())
}
}
impl From<Utf8Error> for HttpError {
fn from(error: Utf8Error) -> Self {
Self::new_inner(error.into())
}
}
impl From<Infallible> for HttpError {
fn from(_: Infallible) -> Self {
unreachable!()
}
}