154 lines
3.8 KiB
Rust
154 lines
3.8 KiB
Rust
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<E> 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<T, E> Explain for Result<T, E>
|
|
where
|
|
E: std::error::Error + 'static,
|
|
{
|
|
type Output = Result<T, How>;
|
|
|
|
#[inline(always)]
|
|
fn without_explanation(self) -> Self::Output {
|
|
#[cold]
|
|
#[track_caller]
|
|
fn err_inner<E>(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, C>(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<E> Explain for Arc<E>
|
|
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<dyn std::error::Error + Send + Sync> {
|
|
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<T> Explain for Option<T> {
|
|
type Output = Result<T, How>;
|
|
|
|
#[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)),
|
|
}
|
|
}
|
|
}
|