pub use paste::paste;
#[macro_export]
macro_rules! define_error {
( $name:ident
{ $($suberrors:tt)* }
) => {
$crate::define_error_with_tracer![
@tracer( $crate::DefaultTracer ),
@attr[ derive(Debug) ],
@name( $name ),
@suberrors{ $($suberrors)* }
];
};
( #[doc = $doc:literal] $( #[$attr:meta] )*
$name:ident
{ $($suberrors:tt)* }
) => {
$crate::define_error_with_tracer![
@tracer( $crate::DefaultTracer ),
@doc( $doc ),
@attr[ $( $attr ),* ],
@name( $name ),
@suberrors{ $($suberrors)* }
];
};
( $( #[$attr:meta] )*
$name:ident
{ $($suberrors:tt)* }
) => {
$crate::define_error_with_tracer![
@tracer( $crate::DefaultTracer ),
@attr[ $( $attr ),* ],
@name( $name ),
@suberrors{ $($suberrors)* }
];
};
( @with_tracer[ $tracer:ty ]
$name:ident,
{ $($suberrors:tt)* }
) => {
$crate::define_error_with_tracer![
@tracer( $tracer ),
@attr[ derive(Debug) ],
@name( $name ),
@suberrors{ $($suberrors)* }
];
};
( @with_tracer[ $tracer:ty ]
$( #[$attr:meta] )*
$name:ident,
@suberrors{ $($suberrors:tt)* }
) => {
$crate::define_error_with_tracer![
@tracer( $tracer ),
@attr[ $( $attr ),* ],
@name( $name ),
@suberrors{ $($suberrors)* }
];
};
}
#[macro_export]
#[doc(hidden)]
macro_rules! define_error_with_tracer {
( @tracer( $tracer:ty ),
$( @doc($doc:literal), )?
@attr[ $( $attr:meta ),* ],
@name($name:ident),
@suberrors{ $($suberrors:tt)* } $(,)?
) => {
$crate::macros::paste![
$crate::define_main_error!(
@tracer( $tracer ),
$( @doc( $doc ), )?
@name( $name )
);
$crate::define_error_detail!(
@attr[ $( $attr ),* ] ,
@name( $name ),
@suberrors{ $($suberrors)* });
$crate::define_suberrors! {
@tracer($tracer),
@attr[ $( $attr ),* ],
@name($name),
{ $( $suberrors )* }
}
];
};
}
#[macro_export]
#[doc(hidden)]
macro_rules! define_main_error {
( @tracer( $tracer:ty ),
$( @doc( $doc:literal ), )?
@name( $name:ident ) $(,)?
) => {
$crate::macros::paste![
$crate::define_main_error_struct!(
@tracer( $tracer ),
$( @doc($doc), )?
@name( $name )
);
impl $crate::ErrorSource<$tracer> for $name {
type Source = Self;
type Detail = [< $name Detail >];
fn error_details($name(detail, trace): Self) -> ([< $name Detail >], Option<$tracer>) {
(detail, Some(trace))
}
}
impl ::core::fmt::Debug for $name
where
$tracer: ::core::fmt::Debug,
{
fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
::core::fmt::Debug::fmt(self.trace(), f)
}
}
impl ::core::fmt::Display for $name
where
$tracer: ::core::fmt::Debug,
{
fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>)
-> ::core::fmt::Result
{
::core::fmt::Debug::fmt(self.trace(), f)
}
}
$crate::define_std_err_impl!(
@tracer( $tracer ),
@name( $name )
);
impl $name {
pub fn detail(&self) -> &[< $name Detail >] {
&self.0
}
pub fn into_detail(self) -> [< $name Detail >] {
self.0
}
pub fn trace(&self) -> &$tracer {
&self.1
}
pub fn into_trace(self) -> $tracer {
self.1
}
pub fn add_trace<E: ::core::fmt::Display>(self, message: &E) -> Self
where
$tracer: $crate::ErrorMessageTracer,
{
let detail = self.0;
let trace = $crate::ErrorMessageTracer::add_message(self.1, message);
$name(detail, trace)
}
pub fn trace_from<E, Cont>(source: E::Source, cont: Cont) -> Self
where
E: $crate::ErrorSource<$tracer>,
$tracer: $crate::ErrorMessageTracer,
Cont: FnOnce(E::Detail) -> [< $name Detail >],
{
let (detail1, m_trace1) = E::error_details(source);
let detail2 = cont(detail1);
match m_trace1 {
Some(trace1) => {
let trace2 = $crate::ErrorMessageTracer::add_message(trace1, &detail2);
$name(detail2, trace2)
}
None => {
let trace2 = $crate::ErrorMessageTracer::new_message(&detail2);
$name(detail2, trace2)
}
}
}
}
];
}
}
#[cfg(feature = "std")]
#[macro_export]
#[doc(hidden)]
macro_rules! define_std_err_impl {
( @tracer( $tracer:ty ),
@name( $name:ident ) $(,)?
) => {
$crate::macros::paste![
impl $crate::StdError for $name
where
[< $name Detail >]: ::core::fmt::Display,
$tracer: ::core::fmt::Debug + ::core::fmt::Display,
$tracer: $crate::ErrorMessageTracer,
{
fn source(&self) -> ::core::option::Option<&(dyn $crate::StdError + 'static)> {
$crate::ErrorMessageTracer::as_error(self.trace())
}
}
];
}
}
#[cfg(not(feature = "std"))]
#[macro_export]
#[doc(hidden)]
macro_rules! define_std_err_impl {
( @tracer( $tracer:ty ),
@name( $name:ident ) $(,)?
) => {};
}
#[macro_export]
#[doc(hidden)]
macro_rules! define_main_error_struct {
( @tracer( $tracer:ty ),
$( @doc( $doc:literal ), )?
@name( $name:ident ) $(,)?
) => {
$crate::macros::paste![
$( #[doc = $doc] )?
pub struct $name (pub [< $name Detail >], pub $tracer);
];
}
}
#[macro_export]
#[doc(hidden)]
macro_rules! with_suberrors {
( @cont($cont:path),
@ctx[ $($args:tt)* ],
@suberrors{
$(
$( #[$sub_attr:meta] )*
$suberror:ident
$( { $( $arg_name:ident : $arg_type:ty ),* $(,)? } )?
$( [ $source:ty ] )?
| $formatter_arg:pat | $formatter:expr
),* $(,)?
} $(,)?
) => {
$cont!( @ctx[ $( $args )* ], @suberrors{ $( $suberror ),* } );
}
}
#[macro_export]
#[doc(hidden)]
macro_rules! define_error_detail {
( @attr[ $( $attr:meta ),* ],
@name( $name:ident ),
@suberrors{ $($suberrors:tt)* } $(,)?
) => {
$crate::with_suberrors!(
@cont($crate::define_error_detail_enum),
@ctx[
@attr[ $( $attr ),* ],
@name($name)
],
@suberrors{ $( $suberrors )* }
);
$crate::with_suberrors!(
@cont($crate::define_error_detail_display),
@ctx[
@name($name)
],
@suberrors{ $( $suberrors )* }
);
}
}
#[macro_export]
#[doc(hidden)]
macro_rules! define_error_detail_enum {
( @ctx[
@attr[ $( $attr:meta ),* ],
@name($name:ident)
],
@suberrors{ $( $suberror:ident ),* } $(,)?
) => {
$crate::macros::paste! [
$( #[$attr] )*
pub enum [< $name Detail >] {
$(
$suberror (
[< $suberror Subdetail >]
)
),*
}
];
}
}
#[macro_export]
#[doc(hidden)]
macro_rules! define_error_detail_display {
( @ctx[
@name( $name:ident )
],
@suberrors{ $( $suberror:ident ),* } $(,)?
) => {
$crate::macros::paste! [
impl ::core::fmt::Display for [< $name Detail >] {
fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>)
-> ::core::fmt::Result
{
match self {
$(
Self::$suberror( suberror ) => {
::core::write!( f, "{}", suberror )
}
),*
}
}
}
];
}
}
#[macro_export]
#[doc(hidden)]
macro_rules! define_suberrors {
( @tracer($tracer:ty),
@attr[ $( $attr:meta ),* ],
@name($name:ident),
{} $(,)?
) => { };
( @tracer($tracer:ty),
@attr[ $( $attr:meta ),* ],
@name($name:ident),
{
$( #[$sub_attr:meta] )*
$suberror:ident
$( { $( $arg_name:ident : $arg_type:ty ),* $(,)? } )?
$( [ $source:ty ] )?
| $formatter_arg:pat | $formatter:expr
$( , $($tail:tt)* )?
}
) => {
$crate::macros::paste![
$crate::define_suberror! {
@tracer( $tracer ),
@attr[ $( $attr ),* ],
@sub_attr[ $( $sub_attr ),* ],
@name( $name ),
@suberror( $suberror ),
@args( $( $( $arg_name : $arg_type ),* )? )
$( @source[ $source ] )?
}
impl ::core::fmt::Display for [< $suberror Subdetail >] {
fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
use ::core::format_args;
let $formatter_arg = self;
::core::write!(f, "{}", $formatter)
}
}
impl $name {
$crate::define_error_constructor! {
@tracer( $tracer ),
@name( $name ),
@suberror( $suberror ),
@args( $( $( $arg_name : $arg_type ),* )? )
$( @source[ $source ] )?
}
}
];
$crate::define_suberrors! {
@tracer($tracer),
@attr[ $( $attr ),* ],
@name($name),
{ $( $( $tail )* )? }
}
};
}
#[macro_export]
#[doc(hidden)]
macro_rules! define_suberror {
( @tracer( $tracer:ty ),
@attr[ $( $attr:meta ),* ],
@sub_attr[ $( $sub_attr:meta ),* ],
@name( $name:ident ),
@suberror( $suberror:ident ),
@args( $( $arg_name:ident: $arg_type:ty ),* )
@source[ Self ]
) => {
$crate::macros::paste! [
$( #[ $attr ] )*
$( #[ $sub_attr ] )*
pub struct [< $suberror Subdetail >] {
$( pub $arg_name: $arg_type, )*
pub source: $crate::alloc::boxed::Box< [< $name Detail >] >
}
];
};
( @tracer( $tracer:ty ),
@attr[ $( $attr:meta ),* ],
@sub_attr[ $( $sub_attr:meta ),* ],
@name( $name:ident ),
@suberror( $suberror:ident ),
@args( $( $arg_name:ident: $arg_type:ty ),* )
$( @source[ $source:ty ] )?
) => {
$crate::macros::paste! [
$( #[ $attr ] )*
$( #[ $sub_attr ] )*
pub struct [< $suberror Subdetail >] {
$( pub $arg_name: $arg_type, )*
$( pub source: $crate::AsErrorDetail<$source, $tracer> )?
}
];
};
}
#[macro_export]
#[doc(hidden)]
macro_rules! define_error_constructor {
( @tracer( $tracer:ty ),
@name( $name:ident ),
@suberror( $suberror:ident ),
@args( $( $arg_name:ident: $arg_type:ty ),* ) $(,)?
) => {
$crate::macros::paste! [
pub fn [< $suberror:snake >](
$( $arg_name: $arg_type, )*
) -> $name
{
let detail = [< $name Detail >]::$suberror([< $suberror Subdetail >] {
$( $arg_name, )*
});
let trace = < $tracer as $crate::ErrorMessageTracer >::new_message(&detail);
$name(detail, trace)
}
];
};
( @tracer( $tracer:ty ),
@name( $name:ident ),
@suberror( $suberror:ident ),
@args( $( $arg_name:ident: $arg_type:ty ),* )
@source[ Self ]
) => {
$crate::macros::paste! [
pub fn [< $suberror:snake >](
$( $arg_name: $arg_type, )*
source: $name
) -> $name
{
let detail = [< $name Detail >]::$suberror([< $suberror Subdetail >] {
$( $arg_name, )*
source: Box::new(source.0),
});
let trace = source.1.add_message(&detail);
$name(detail, trace)
}
];
};
( @tracer( $tracer:ty ),
@name( $name:ident ),
@suberror( $suberror:ident ),
@args( $( $arg_name:ident: $arg_type:ty ),* )
@source[ $source:ty ]
) => {
$crate::macros::paste! [
pub fn [< $suberror:snake >](
$( $arg_name: $arg_type, )*
source: $crate::AsErrorSource< $source, $tracer >
) -> $name
{
$name::trace_from::<$source, _>(source,
| source_detail | {
[< $name Detail >]::$suberror([< $suberror Subdetail >] {
$( $arg_name, )*
source: source_detail,
})
})
}
];
};
}