Compare commits
2 Commits
f416f66d5c
...
457328945c
Author | SHA1 | Date |
---|---|---|
Michael Pfaff | 457328945c | |
Michael Pfaff | 639e5835e4 |
|
@ -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)]
|
||||
|
@ -19,18 +20,19 @@ impl fmt::Display for Context {
|
|||
#[derive(Debug)]
|
||||
#[cfg_attr(feature = "clone-with-caveats", derive(Clone))]
|
||||
pub(crate) enum ContextInner {
|
||||
Elem(ContextElem),
|
||||
Compound(Vec<ContextElem>),
|
||||
Elem(Detail),
|
||||
Compound(Vec<Detail>),
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
#[cfg_attr(feature = "clone-with-caveats", derive(Clone))]
|
||||
pub(crate) enum ContextElem {
|
||||
pub(crate) enum Detail {
|
||||
Str(&'static str),
|
||||
String(String),
|
||||
Location(Location<'static>),
|
||||
#[cfg(feature = "backtrace")]
|
||||
Backtrace(Backtrace),
|
||||
Error(Arc<dyn std::error::Error + Send + Sync>),
|
||||
}
|
||||
|
||||
// will be replaced with std::backtrace::Backtrace if and when it is Clone
|
||||
|
@ -67,7 +69,7 @@ impl fmt::Display for ContextInner {
|
|||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for ContextElem {
|
||||
impl fmt::Display for Detail {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
Self::Str(s) => f.write_str(s),
|
||||
|
@ -86,6 +88,7 @@ impl fmt::Display for ContextElem {
|
|||
})?;
|
||||
write!(f, "{}", bt)
|
||||
},
|
||||
Self::Error(e) => e.fmt(f),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -135,14 +138,14 @@ impl IntoContext for Context {
|
|||
impl IntoContext for String {
|
||||
#[inline(always)]
|
||||
fn into_context(self) -> Context {
|
||||
Context(ContextInner::Elem(ContextElem::String(self)))
|
||||
Context(ContextInner::Elem(Detail::String(self)))
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoContext for &'static str {
|
||||
#[inline(always)]
|
||||
fn into_context(self) -> Context {
|
||||
Context(ContextInner::Elem(ContextElem::Str(self)))
|
||||
Context(ContextInner::Elem(Detail::Str(self)))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -166,7 +169,7 @@ impl<'a> IntoContext for &'a Location<'static> {
|
|||
impl IntoContext for Location<'static> {
|
||||
#[inline]
|
||||
fn into_context(self) -> Context {
|
||||
Context(ContextInner::Elem(ContextElem::Location(self)))
|
||||
Context(ContextInner::Elem(Detail::Location(self)))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
use std::panic::Location;
|
||||
use std::sync::Arc;
|
||||
|
||||
use crate::{How, IntoContext};
|
||||
use crate::{How, IntoContext, Context, ContextInner, Detail};
|
||||
#[cfg(feature = "backtrace")]
|
||||
use crate::context::Backtrace;
|
||||
|
||||
pub trait Explain {
|
||||
type Output;
|
||||
|
@ -16,9 +19,8 @@ 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());
|
||||
let loc = Detail::Location(*Location::caller());
|
||||
#[cfg(feature = "backtrace")]
|
||||
let bt = {
|
||||
use std::backtrace::BacktraceStatus::*;
|
||||
|
@ -28,7 +30,7 @@ impl Explain for How {
|
|||
Unsupported => Backtrace::Unsupported,
|
||||
status => Backtrace::Other(status, bt.to_string()),
|
||||
};
|
||||
ContextElem::Backtrace(bt)
|
||||
Detail::Backtrace(bt)
|
||||
};
|
||||
match context.0 {
|
||||
ContextInner::Elem(elem) => {
|
||||
|
@ -65,6 +67,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(Detail::Error(Arc::new(e))))),
|
||||
Err(e) => How::new(e.to_string()),
|
||||
}
|
||||
.context(c)
|
||||
|
@ -76,17 +81,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(Detail::Error(self))))
|
||||
.context(context)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Explain for Option<T> {
|
||||
type Output = Result<T, How>;
|
||||
|
||||
#[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))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
#![feature(doc_auto_cfg)]
|
||||
|
||||
mod context;
|
||||
pub(crate) use context::{ContextInner, Detail};
|
||||
pub use context::{Context, IntoContext};
|
||||
|
||||
mod report;
|
||||
|
|
Loading…
Reference in New Issue