how.rs/src/explain.rs

123 lines
2.8 KiB
Rust
Raw Normal View History

use std::panic::Location;
2023-06-29 11:48:51 -04:00
use std::sync::Arc;
2022-07-21 20:39:47 -04:00
2024-03-20 23:15:16 -04:00
use crate::{Detail, How, IntoContext};
2022-07-21 20:39:47 -04:00
2023-07-02 15:19:30 -04:00
pub trait Explain: Sized {
2022-07-21 20:40:44 -04:00
type Output;
2022-07-21 20:39:47 -04:00
#[track_caller]
2022-07-21 20:40:44 -04:00
#[must_use]
fn context(self, context: impl IntoContext) -> Self::Output;
2022-07-21 20:39:47 -04:00
#[inline]
2023-07-02 15:19:30 -04:00
#[track_caller]
#[must_use]
fn frame(self, context: impl IntoContext) -> Self::Output {
let mut context = context.into_context();
2023-07-01 11:41:21 -04:00
context.extra.reserve(if cfg!(feature = "extra-backtrace") {
2023-07-01 11:41:21 -04:00
2
} else {
1
});
context.extra.push(Detail::Location(*Location::caller()));
#[cfg(feature = "extra-backtrace")]
context.extra.push(Detail::backtrace());
2023-07-02 15:19:30 -04:00
self.context(context)
}
}
impl Explain for How {
type Output = Self;
#[inline(always)]
#[track_caller]
fn context(mut self, context: impl IntoContext) -> Self {
self.push_context(context.into_context());
self
}
}
2022-07-21 20:39:47 -04:00
2024-03-20 23:15:16 -04:00
/*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)
}
}*/
2022-07-21 20:40:44 -04:00
impl<T, E> Explain for Result<T, E>
where
E: std::error::Error + 'static,
2022-07-21 20:40:44 -04:00
{
type Output = Result<T, How>;
2022-07-21 20:39:47 -04:00
#[inline(always)]
2023-02-06 09:06:19 -05:00
#[track_caller]
2022-07-21 20:40:44 -04:00
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,
2023-06-29 11:48:51 -04:00
// TODO: specialize on Send + Sync at runtime or compile time (possibly via
// specialization)
2023-06-29 11:55:21 -04:00
//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)),
}
}
}
2023-06-29 11:48:51 -04:00
impl<E> Explain for Arc<E>
where
E: std::error::Error + Send + Sync + 'static,
{
type Output = How;
2023-07-02 15:19:30 -04:00
#[inline]
2023-06-29 11:48:51 -04:00
#[track_caller]
fn context(self, context: impl IntoContext) -> Self::Output {
2023-07-02 15:19:30 -04:00
How::new(self).context(context)
2023-06-29 11:48:51 -04:00
}
}
impl Explain for Arc<dyn std::error::Error + Send + Sync> {
type Output = How;
2023-07-02 15:19:30 -04:00
#[inline]
#[track_caller]
fn context(self, context: impl IntoContext) -> Self::Output {
2023-07-02 15:19:30 -04:00
How::new(self).context(context)
}
}
impl<T> Explain for Option<T> {
type Output = Result<T, How>;
#[inline(always)]
2023-02-06 09:06:19 -05:00
#[track_caller]
fn context(self, context: impl IntoContext) -> Self::Output {
match self {
Some(t) => Ok(t),
None => Err(How::new(context)),
}
2023-01-17 07:29:58 -05:00
}
}