use std::fmt;
#[derive(Debug)]
pub struct ContextError {
pub context: String,
pub source: Box<dyn std::error::Error + Send + Sync>,
}
impl fmt::Display for ContextError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}: {}", self.context, self.source)
}
}
impl std::error::Error for ContextError {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
Some(self.source.as_ref())
}
}
pub trait ErrorContext<T> {
fn context<C: Into<String>>(self, ctx: C) -> Result<T, ContextError>;
}
impl<T, E: std::error::Error + Send + Sync + 'static> ErrorContext<T> for Result<T, E> {
fn context<C: Into<String>>(self, ctx: C) -> Result<T, ContextError> {
self.map_err(|e| ContextError {
context: ctx.into(),
source: Box::new(e),
})
}
}
pub fn with_context<T, E, F, C>(result: Result<T, E>, f: F) -> Result<T, ContextError>
where
E: std::error::Error + Send + Sync + 'static,
F: FnOnce(&E) -> C,
C: Into<String>,
{
result.map_err(|e| ContextError {
context: f(&e).into(),
source: Box::new(e),
})
}