Support nested details, add with_backtrace method to IntoContext, impl IntoContext for Detail

This commit is contained in:
Michael Pfaff 2023-07-02 12:07:00 -04:00
parent 184b334a09
commit 71385c9e19
Signed by: michael
GPG Key ID: CF402C4A012AA9D4
2 changed files with 31 additions and 10 deletions

View File

@ -4,7 +4,8 @@ fn main0() -> Result<()> {
Err(How::new( Err(How::new(
"The engine broke down" "The engine broke down"
.with("Remember: you aren't good with cars") .with("Remember: you aren't good with cars")
.with("Suggestion: call a tow truck"), .with("Suggestion: call a tow truck")
.with("Foo".with("Bar").with("Baz")),
) )
.context( .context(
"While driving down a road" "While driving down a road"

View File

@ -69,6 +69,7 @@ pub enum Detail {
#[cfg(feature = "backtrace")] #[cfg(feature = "backtrace")]
Backtrace(PrivateBacktrace), Backtrace(PrivateBacktrace),
Error(PrivateError), Error(PrivateError),
Context(Box<Context>),
} }
impl Detail { impl Detail {
@ -137,6 +138,7 @@ impl fmt::Display for Detail {
write!(f, "{}", bt) write!(f, "{}", bt)
}, },
Self::Error(PrivateError(e)) => e.fmt(f), Self::Error(PrivateError(e)) => e.fmt(f),
Self::Context(c) => c.fmt(f),
} }
} }
} }
@ -154,6 +156,15 @@ pub trait IntoContext: Sized {
fn with_caller(self) -> Context { fn with_caller(self) -> Context {
self.with(Location::caller()) self.with(Location::caller())
} }
#[inline(always)]
#[track_caller]
fn with_backtrace(self) -> Context {
#[cfg(feature = "backtrace")]
return self.with(Detail::backtrace());
#[cfg(not(feature = "backtrace"))]
self.into_context()
}
} }
impl IntoContext for Context { impl IntoContext for Context {
@ -166,10 +177,12 @@ impl IntoContext for Context {
#[track_caller] #[track_caller]
#[inline] #[inline]
fn with(mut self, other: impl IntoContext) -> Self { fn with(mut self, other: impl IntoContext) -> Self {
let mut other = other.into_context(); let other = other.into_context();
self.extra.reserve(1 + other.extra.len()); if other.extra.is_empty() {
self.extra.push(other.detail); self.extra.push(other.detail);
self.extra.append(&mut other.extra); } else {
self.extra.push(Detail::Context(other.into()));
}
self self
} }
} }
@ -177,14 +190,14 @@ impl IntoContext for Context {
impl IntoContext for String { impl IntoContext for String {
#[inline(always)] #[inline(always)]
fn into_context(self) -> Context { fn into_context(self) -> Context {
Context::new(Detail::String(self)) Detail::String(self).into_context()
} }
} }
impl IntoContext for &'static str { impl IntoContext for &'static str {
#[inline(always)] #[inline(always)]
fn into_context(self) -> Context { fn into_context(self) -> Context {
Context::new(Detail::Str(self)) Detail::Str(self).into_context()
} }
} }
@ -208,7 +221,7 @@ impl<'a> IntoContext for &'a Location<'static> {
impl IntoContext for Location<'static> { impl IntoContext for Location<'static> {
#[inline] #[inline]
fn into_context(self) -> Context { fn into_context(self) -> Context {
Context::new(Detail::Location(self)) Detail::Location(self).into_context()
} }
} }
@ -218,14 +231,21 @@ where
{ {
#[inline] #[inline]
fn into_context(self) -> Context { fn into_context(self) -> Context {
Context::new(Detail::Error(PrivateError(self))) Detail::Error(PrivateError(self)).into_context()
} }
} }
impl IntoContext for Arc<dyn std::error::Error + Send + Sync> { impl IntoContext for Arc<dyn std::error::Error + Send + Sync> {
#[inline] #[inline]
fn into_context(self) -> Context { fn into_context(self) -> Context {
Context::new(Detail::Error(PrivateError(self))) Detail::Error(PrivateError(self)).into_context()
}
}
impl IntoContext for Detail {
#[inline(always)]
fn into_context(self) -> Context {
Context::new(self)
} }
} }