diff --git a/src/context.rs b/src/context.rs index 8ebbe38..8b6cd5b 100644 --- a/src/context.rs +++ b/src/context.rs @@ -3,6 +3,7 @@ use std::borrow::Cow; use std::backtrace::BacktraceStatus; use std::fmt; use std::panic::Location; +use std::sync::Arc; /// Provides context furthering the explanation of *how* you got to an error. #[derive(Debug)] @@ -31,6 +32,7 @@ pub(crate) enum ContextElem { Location(Location<'static>), #[cfg(feature = "backtrace")] Backtrace(Backtrace), + Error(Arc), } // will be replaced with std::backtrace::Backtrace if and when it is Clone @@ -86,6 +88,7 @@ impl fmt::Display for ContextElem { })?; write!(f, "{}", bt) }, + Self::Error(e) => e.fmt(f), } } } diff --git a/src/explain.rs b/src/explain.rs index 5714d72..46ff974 100644 --- a/src/explain.rs +++ b/src/explain.rs @@ -1,6 +1,8 @@ use std::panic::Location; +use std::sync::Arc; use crate::{How, IntoContext}; +use crate::context::*; pub trait Explain { type Output; @@ -16,7 +18,6 @@ impl Explain for How { #[track_caller] #[inline] fn context(mut self, context: impl IntoContext) -> Self { - use crate::context::*; let mut context = context.into_context(); let loc = ContextElem::Location(*Location::caller()); #[cfg(feature = "backtrace")] @@ -65,6 +66,9 @@ where { match typeid_cast::cast(e) { Ok(e) => e, + // TODO: specialize on Send + Sync at runtime or compile time (possibly via + // specialization) + //Err(e) => How::new(Context(ContextInner::Elem(ContextElem::Error(Arc::new(e))))), Err(e) => How::new(e.to_string()), } .context(c) @@ -76,17 +80,28 @@ where } } +impl Explain for Arc +where + E: std::error::Error + Send + Sync + 'static, +{ + type Output = How; + + #[track_caller] + fn context(self, context: impl IntoContext) -> Self::Output { + How::new(Context(ContextInner::Elem(ContextElem::Error(self)))) + .context(context) + } +} + impl Explain for Option { type Output = Result; #[inline(always)] #[track_caller] fn context(self, context: impl IntoContext) -> Self::Output { - // TODO: maybe add a feature for the extra "Option::None" context match self { Some(t) => Ok(t), None => Err(How::new(context)), } - //self.into_result_how().map_err(#[inline(never)] move |e| e.context(context)) } }