use std::error::Error;
use std::fmt;
use std::fmt::{Debug, Display, Formatter};
pub struct ErrorMessage {
pub(crate) message: String,
#[cfg(feature = "send")]
pub(crate) cause: Option<Box<dyn Error + Send>>,
#[cfg(not(feature = "send"))]
pub(crate) cause: Option<Box<dyn Error>>,
}
impl ErrorMessage {
pub fn new(message: impl ToString) -> ErrorMessage {
ErrorMessage { message: message.to_string(), cause: None }
}
pub fn err<T>(message: impl ToString) -> Result<T, ErrorMessage> {
Err(ErrorMessage { message: message.to_string(), cause: None })
}
#[cfg(not(feature = "send"))]
pub fn with_context<E: Error + 'static>(message: impl ToString, cause: E) -> ErrorMessage {
ErrorMessage { message: message.to_string(), cause: Some(Box::new(cause)) }
}
#[cfg(feature = "send")]
pub fn with_context<E: Error + Send + 'static>(message: impl ToString, cause: E) -> ErrorMessage {
ErrorMessage { message: message.to_string(), cause: Some(Box::new(cause)) }
}
}
impl Error for ErrorMessage {}
impl Display for ErrorMessage {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
f.write_str(&self.message)?;
if let Some(cause) = &self.cause {
fmt_cause(cause, f)?;
}
Ok(())
}
}
#[cfg(not(feature = "pretty_debug_errors"))]
impl Debug for ErrorMessage {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
let mut s = f.debug_struct("ErrorMessage");
s.field("message", &self.message);
if let Some(cause) = &self.cause {
if let Some(cause) = cause.downcast_ref::<ErrorMessage>() {
s.field("cause", cause);
} else {
s.field("cause", &Some(cause));
}
} else {
s.field("cause", &None::<ErrorMessage>);
}
s.finish()
}
}
#[cfg(feature = "pretty_debug_errors")]
impl Debug for ErrorMessage {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
Display::fmt(self, f)
}
}
#[allow(clippy::borrowed_box)]
#[cfg(feature = "send")]
fn fmt_cause(error: &Box<dyn Error + Send>, f: &mut Formatter) -> fmt::Result {
f.write_str("\n caused by: ")?;
if let Some(cause) = error.downcast_ref::<ErrorMessage>() {
f.write_str(&cause.message)?;
if let Some(cause) = &cause.cause {
fmt_cause(cause, f)?;
}
} else {
Debug::fmt(error, f)?;
}
Ok(())
}
#[allow(clippy::borrowed_box)]
#[cfg(not(feature = "send"))]
fn fmt_cause(error: &Box<dyn Error>, f: &mut Formatter) -> fmt::Result {
f.write_str("\n caused by: ")?;
if let Some(cause) = error.downcast_ref::<ErrorMessage>() {
f.write_str(&cause.message)?;
if let Some(cause) = &cause.cause {
fmt_cause(cause, f)?;
}
} else {
Debug::fmt(error, f)?;
}
Ok(())
}