use std::sync::Arc; use crate::{How, IntoDetails}; pub trait Explain: Sized { type Output: Explain; #[track_caller] #[must_use] fn without_explanation(self) -> Self::Output; #[track_caller] #[must_use] fn context(self, context: impl IntoDetails) -> Self::Output; } impl Explain for How { type Output = Self; #[inline(always)] fn without_explanation(self) -> Self::Output { self } #[inline(always)] #[track_caller] fn context(mut self, context: impl IntoDetails) -> Self { self.push_context(context.into_details()); self } } /*impl Explain for E where E: std::error::Error, { type Output = How; #[inline(always)] #[track_caller] fn context(self, context: impl IntoContext) -> Self::Output { How::new(self.to_string()).context(context) } }*/ impl Explain for Result where E: std::error::Error + 'static, { type Output = Result; #[inline(always)] fn without_explanation(self) -> Self::Output { #[cold] #[track_caller] fn err_inner(e: E) -> How where E: std::error::Error + 'static, { // TODO: when specialization is stable, or at least *safe*, specialize on `E = How` and // `E: Send + Sync + 'static` and remove the `+ 'static` bound from E on this Explain // impl. match typeid_cast::cast(e) { Ok(e) => e, //Err(e) => How::new(Context(ContextInner::Elem(Detail::Error(Arc::new(e))))), Err(e) => How::new(e.to_string()), } } match self { Ok(t) => Ok(t), Err(e) => Err(err_inner(e)), } } #[inline(always)] #[track_caller] fn context(self, context: impl IntoDetails) -> Self::Output { #[cold] #[track_caller] fn into_and_context(e: E, c: C) -> How where E: std::error::Error + 'static, C: IntoDetails, { // TODO: when specialization is stable, or at least *safe*, specialize on `E = How` and // `E: Send + Sync + 'static` and remove the `+ 'static` bound from E on this Explain // impl. match typeid_cast::cast(e) { Ok(e) => e, //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; #[inline] fn without_explanation(self) -> Self::Output { How::new(self) } #[inline] #[track_caller] fn context(self, context: impl IntoDetails) -> Self::Output { self.without_explanation().context(context) } } impl Explain for Arc { type Output = How; fn without_explanation(self) -> Self::Output { How::new(self) } #[inline] #[track_caller] fn context(self, context: impl IntoDetails) -> Self::Output { self.without_explanation().context(context) } } impl Explain for Option { type Output = Result; #[inline(always)] fn without_explanation(self) -> Self::Output { match self { Some(t) => Ok(t), None => Err(How::new("called `Option::unwrap()` on a `None` value")), } } #[inline(always)] #[track_caller] fn context(self, context: impl IntoDetails) -> Self::Output { match self { Some(t) => Ok(t), None => Err(How::new(context)), } } }