use alloc::boxed::Box;
use core::convert::Infallible;
use core::fmt::{self, Debug, Display};
use http::StatusCode;
#[derive(Debug)]
pub struct Error {
inner: eyre::Report,
status: StatusCode,
}
impl Error {
pub fn msg(msg: impl Display + Send + Sync + Debug + 'static) -> Self {
Self {
inner: eyre::Report::msg(msg),
status: StatusCode::INTERNAL_SERVER_ERROR,
}
}
pub fn new(e: impl Into<eyre::Report>) -> Self {
Self {
inner: e.into(),
status: StatusCode::INTERNAL_SERVER_ERROR,
}
}
pub fn into_inner(self) -> eyre::Report {
self.inner
}
pub fn into_boxed_http_error(self) -> BoxHttpError {
struct Wrapper(Error);
impl Debug for Wrapper {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
Debug::fmt(&self.0, f)
}
}
impl Display for Wrapper {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
Display::fmt(&self.0, f)
}
}
impl core::error::Error for Wrapper {
fn source(&self) -> Option<&(dyn core::error::Error + 'static)> {
self.0.inner.source()
}
}
impl HttpError for Wrapper {
fn status(&self) -> StatusCode {
self.0.status
}
}
Box::new(Wrapper(self))
}
pub fn set_status(mut self, status: StatusCode) -> Self {
self.status = status;
self
}
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.inner)
}
}
pub trait HttpError: core::error::Error + Send + Sync + 'static {
fn status(&self) -> StatusCode {
StatusCode::INTERNAL_SERVER_ERROR
}
}
pub type Result<T, E = Error> = core::result::Result<T, E>;
pub trait ResultExt<T> {
fn status(self, status: StatusCode) -> Result<T, Error>;
}
impl<T, E> ResultExt<T> for core::result::Result<T, E>
where
E: Into<eyre::Report>,
{
fn status(self, status: StatusCode) -> Result<T, Error> {
self.map_err(|e| Error::new(e).set_status(status))
}
}
impl<T> ResultExt<T> for core::option::Option<T> {
fn status(self, status: StatusCode) -> Result<T, Error> {
self.ok_or_else(|| Error::msg("None value").set_status(status))
}
}
pub type BoxHttpError = Box<dyn HttpError>;
impl<E> From<E> for Error
where
E: Into<eyre::Report>,
{
fn from(e: E) -> Self {
Error::new(e)
}
}
impl core::error::Error for BoxHttpError {}
impl HttpError for BoxHttpError {
fn status(&self) -> StatusCode {
(**self).status()
}
}
impl HttpError for Infallible {
fn status(&self) -> StatusCode {
unreachable!("Infallible can never be instantiated")
}
}