how.rs/src/explain.rs

93 lines
2.5 KiB
Rust

use std::panic::Location;
use crate::{How, IntoContext};
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 {
use crate::context::*;
let mut context = context.into_context();
let loc = ContextElem::Location(*Location::caller());
#[cfg(feature = "backtrace")]
let bt = {
use std::backtrace::BacktraceStatus::*;
let bt = std::backtrace::Backtrace::capture();
let bt = match bt.status() {
Disabled => Backtrace::Disabled,
Unsupported => Backtrace::Unsupported,
status => Backtrace::Other(status, bt.to_string()),
};
ContextElem::Backtrace(bt)
};
match context.0 {
ContextInner::Elem(elem) => {
#[cfg(not(feature = "backtrace"))]
let vec = vec![elem, loc];
#[cfg(feature = "backtrace")]
let vec = vec![elem, loc, bt];
context.0 = ContextInner::Compound(vec);
}
ContextInner::Compound(ref mut vec) => {
vec.insert(1, loc);
}
}
self.push_context(context);
self
}
}
impl<T, E> Explain for Result<T, E>
where
E: std::error::Error + 'static,
{
type Output = Result<T, How>;
#[inline(always)]
#[track_caller]
fn context(self, context: impl IntoContext) -> Self::Output {
#[cold]
#[track_caller]
fn into_and_context<E, C>(e: E, c: C) -> How
where
E: std::error::Error + 'static,
C: IntoContext,
{
match typeid_cast::cast(e) {
Ok(e) => 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<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))
}
}