I'm working on an error macro to make it easier to generate errors in my code. I always want to capture a backtrace using the Backtrace crate. The problem I'm having is that I want to support enum
options that both have and do not have a type: ErrOp1
and ErrOp1(String)
. This is easy enough; however, when it comes time to write the Display
impl, I need a way to write code conditionally on if there is a type or not.
Here's the basic sketch of my macro (the From impls are remove for brevity):
macro_rules! my_error {
( $err_name:ident $( $err_op:ident $( ($err_type:ty) )? $(,)? )+ ) => {
use backtrace::Backtrace;
pub enum $err_name {
$( $err_op { $(err: $err_type,)? bt: Backtrace }, )+
}
impl std::error::Error for $err_name {}
impl std::fmt::Display for $err_name {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
$(
Self::$err_op {$(err: ,)? bt } => {
$( write!(f, "{} from\n", err)?; )?
write!(f, "{:?}", bt)
}
)?
}
}
}
};
}
The problem is with the two lines: Self::$err_op {$(err: ,)? bt } => {
and $( write!(f, "{} from\n", err)?; )?
. They both rely on if $err_type
exists or not, but I have no place to use this variable in the code.
I was able to make the second one work by creating a NOOP macro: macro_rules! no_op { ($i:ty) => {} }
and applying it before the write!
: $( no_op!($err_type); write!(f, "{} from\n", err)?; )?
However, I cannot seem to find a way to use my same trick with the enum
field. Is there a way to do this?