Add an Error element

This commit is contained in:
Michael Pfaff 2023-06-29 11:48:51 -04:00
parent f416f66d5c
commit 639e5835e4
Signed by: michael
GPG Key ID: CF402C4A012AA9D4
2 changed files with 21 additions and 3 deletions

View File

@ -3,6 +3,7 @@ use std::borrow::Cow;
use std::backtrace::BacktraceStatus; use std::backtrace::BacktraceStatus;
use std::fmt; use std::fmt;
use std::panic::Location; use std::panic::Location;
use std::sync::Arc;
/// Provides context furthering the explanation of *how* you got to an error. /// Provides context furthering the explanation of *how* you got to an error.
#[derive(Debug)] #[derive(Debug)]
@ -31,6 +32,7 @@ pub(crate) enum ContextElem {
Location(Location<'static>), Location(Location<'static>),
#[cfg(feature = "backtrace")] #[cfg(feature = "backtrace")]
Backtrace(Backtrace), Backtrace(Backtrace),
Error(Arc<dyn std::error::Error + Send + Sync>),
} }
// will be replaced with std::backtrace::Backtrace if and when it is Clone // 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) write!(f, "{}", bt)
}, },
Self::Error(e) => e.fmt(f),
} }
} }
} }

View File

@ -1,6 +1,8 @@
use std::panic::Location; use std::panic::Location;
use std::sync::Arc;
use crate::{How, IntoContext}; use crate::{How, IntoContext};
use crate::context::*;
pub trait Explain { pub trait Explain {
type Output; type Output;
@ -16,7 +18,6 @@ impl Explain for How {
#[track_caller] #[track_caller]
#[inline] #[inline]
fn context(mut self, context: impl IntoContext) -> Self { fn context(mut self, context: impl IntoContext) -> Self {
use crate::context::*;
let mut context = context.into_context(); let mut context = context.into_context();
let loc = ContextElem::Location(*Location::caller()); let loc = ContextElem::Location(*Location::caller());
#[cfg(feature = "backtrace")] #[cfg(feature = "backtrace")]
@ -65,6 +66,9 @@ where
{ {
match typeid_cast::cast(e) { match typeid_cast::cast(e) {
Ok(e) => 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()), Err(e) => How::new(e.to_string()),
} }
.context(c) .context(c)
@ -76,17 +80,28 @@ where
} }
} }
impl<E> Explain for Arc<E>
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<T> Explain for Option<T> { impl<T> Explain for Option<T> {
type Output = Result<T, How>; type Output = Result<T, How>;
#[inline(always)] #[inline(always)]
#[track_caller] #[track_caller]
fn context(self, context: impl IntoContext) -> Self::Output { fn context(self, context: impl IntoContext) -> Self::Output {
// TODO: maybe add a feature for the extra "Option::None" context
match self { match self {
Some(t) => Ok(t), Some(t) => Ok(t),
None => Err(How::new(context)), None => Err(How::new(context)),
} }
//self.into_result_how().map_err(#[inline(never)] move |e| e.context(context))
} }
} }