use std::fmt;
pub struct Error {
message: String,
source: Option<Box<dyn std::error::Error + Send + Sync + 'static>>,
}
impl Error {
pub fn new<S>(message: S) -> Self
where
S: ToString,
{
Self {
message: message.to_string(),
source: None,
}
}
pub fn wrap<E>(error: E) -> Self
where
E: std::error::Error + Send + Sync + 'static,
{
Self {
message: error.to_string(),
source: Some(Box::new(error)),
}
}
pub fn with_context<S, E>(message: S, error: E) -> Self
where
S: ToString,
E: std::error::Error + Send + Sync + 'static,
{
Self {
message: message.to_string(),
source: Some(Box::new(error)),
}
}
}
impl fmt::Debug for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self)
}
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.message)
}
}
impl std::error::Error for Error {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
self.source
.as_ref()
.map(Box::as_ref)
.map(|e| e as &(dyn std::error::Error + 'static))
}
}
macro_rules! convert_error {
($($t:ty,)*) => {$(
impl From<$t> for Error {
fn from(error: $t) -> Self {
Self::wrap(error)
}
}
)*}
}
convert_error! {
std::convert::Infallible,
std::array::TryFromSliceError,
std::char::CharTryFromError,
std::char::DecodeUtf16Error,
std::io::Error,
std::num::TryFromIntError,
std::str::Utf8Error,
std::string::FromUtf8Error,
std::string::FromUtf16Error,
}