use std::panic::Location; use std::sync::Arc; use crate::{How, IntoContext, Context, Detail}; use crate::context::PrivateError; pub trait Explain { type Output; #[track_caller] #[must_use] fn context(self, context: impl IntoContext) -> Self::Output; } impl Explain for How { type Output = Self; #[track_caller] #[inline] fn context(mut self, context: impl IntoContext) -> Self { let mut context = context.into_context(); context.extra.reserve(if cfg!(feature = "extra-backtrace") { 2 } else { 1 }); context.extra.push(Detail::Location(*Location::caller())); #[cfg(feature = "extra-backtrace")] context.extra.push(Detail::backtrace()); self.push_context(context); self } } impl Explain for Result where E: std::error::Error + 'static, { type Output = Result; #[inline(always)] #[track_caller] fn context(self, context: impl IntoContext) -> Self::Output { #[cold] #[track_caller] fn into_and_context(e: E, c: C) -> How where E: std::error::Error + 'static, C: IntoContext, { 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(Detail::Error(Arc::new(e))))), Err(e) => How::new(e.to_string()), } .context(c) } match self { Ok(t) => Ok(t), Err(e) => Err(into_and_context(e, context)), } } } 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::new(Detail::Error(PrivateError(self)))) .context(context) } } impl Explain for Option { type Output = Result; #[inline(always)] #[track_caller] fn context(self, context: impl IntoContext) -> Self::Output { match self { Some(t) => Ok(t), None => Err(How::new(context)), } } }