#[allow(
unused_macros,
reason = "every instantiation is feature-gated (anyhow-boundary, compat-eyre); the macro is unused when both are off"
)]
macro_rules! compat_wrapper {
(
$(#[$mod_attr:meta])*
module: $module:ident,
newtype: $newtype:ident,
wrapped: $wrapped:path,
from: $from:ident,
into: $into:ident,
$(#[$into_attr:meta])*
outbound: $outbound:path,
struct_doc: $struct_doc:literal,
) => {
$(#[$mod_attr])*
pub mod $module {
use std::fmt;
#[doc = $struct_doc]
#[derive(Debug)]
pub struct $newtype($wrapped);
impl fmt::Display for $newtype {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Display::fmt(&self.0, f)
}
}
impl std::error::Error for $newtype {
}
impl $newtype {
#[must_use]
pub fn inner(&self) -> &$wrapped {
&self.0
}
}
#[track_caller]
pub fn $from(e: $wrapped) -> crate::Fault<$newtype> {
crate::Fault::new($newtype(e))
}
$(#[$into_attr])*
pub fn $into<E: std::error::Error + Send + Sync + 'static>(
f: crate::Fault<E>,
) -> $outbound {
<$outbound>::new(f)
}
}
};
}
#[cfg(feature = "anyhow-boundary")]
compat_wrapper! {
module: anyhow_boundary,
newtype: AnyhowError,
wrapped: anyhow::Error,
from: from_anyhow,
into: into_anyhow,
#[must_use]
outbound: anyhow::Error,
struct_doc:
"Wraps [`anyhow::Error`], preserving its message chain.\n\n\
anyhow erases its sources into its own representation, so the \
wrapped error exposes NO `Error::source()` — the chain survives \
through formatting only: `Display` prints the top message, \
alternate `Display` (`{:#}`) prints the cause chain, and `Debug` \
(`{:?}`) prints the chain plus backtrace when captured.",
}
#[cfg(feature = "compat-eyre")]
compat_wrapper! {
module: eyre_boundary,
newtype: EyreError,
wrapped: eyre::Report,
from: from_eyre,
into: into_eyre,
outbound: eyre::Report,
struct_doc:
"Wraps [`eyre::Report`], preserving its message chain.\n\n\
eyre erases its sources into its own representation, so the wrapped \
error exposes NO `Error::source()` — the chain survives through \
formatting only: `Display` prints the top message, alternate \
`Display` (`{:#}`) prints the cause chain one per line, and `Debug` \
(`{:?}`) prints the chain plus backtrace when captured. \
[`eyre::Report::chain`] exists but yields `&dyn Error` WITHOUT \
`Send + Sync`, so it cannot be lifted into `Error::source()` — \
identical to the anyhow boundary.",
}
#[cfg(feature = "compat-error-stack")]
pub mod error_stack_boundary {
use std::fmt;
#[derive(Debug)]
pub struct ErrorStackReport<C: error_stack::Context>(error_stack::Report<C>);
impl<C: error_stack::Context> fmt::Display for ErrorStackReport<C> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Display::fmt(&self.0, f)
}
}
impl<C: error_stack::Context> std::error::Error for ErrorStackReport<C> {
}
impl<C: error_stack::Context> ErrorStackReport<C> {
#[must_use]
pub fn inner(&self) -> &error_stack::Report<C> {
&self.0
}
}
#[track_caller]
pub fn from_error_stack<C: error_stack::Context>(
r: error_stack::Report<C>,
) -> crate::Fault<ErrorStackReport<C>> {
crate::Fault::new(ErrorStackReport(r))
}
pub fn into_error_stack<E: std::error::Error + Send + Sync + 'static>(
f: crate::Fault<E>,
) -> error_stack::Report<crate::Fault<E>> {
error_stack::Report::new(f)
}
}