I'm trying to write a macro that lists a number of struct fields, but conditionally only creates initializer code from some fields in the list. Specifically, that might look something like this:
#[test]
fn test() {
#[derive(PartialEq, Debug)]
struct Foo {
bar: usize,
}
let a = Foo {
bar: 0,
};
let b = test!(Foo {
bar: 0,
#[nope] baz: 0,
});
assert_eq!(a, b);
}
Foo
has no field baz
, and the #[nope]
should tell the macro to just do nothing for that field; the real macro would use baz
in one but not another location, and there are also other "attributes" that need to be handled.
This is the base-line macro that accepts the invocation, but doesn't ignore baz
:
macro_rules! test {
(
$struct:ty {
$($(#[$modifier:ident])? $field:ident: $value:expr,)*
}
) => {
{
// don't mind this syntax workaround
type X = $struct;
X {
$($field: $value,)*
}
}
};
}
Now the trick I know to have different rules for different repetitions is to delegate each repetition to a helper rule. Here's the same macro splitting the regular and nope variations:
macro_rules! test {
(
$struct:ty {
$($(#[$modifier:ident])? $field:ident: $value:expr,)*
}
) => {
{
type X = $struct;
X {
$($field: test!(@field $(#[$modifier])? $field: $value),)*
}
}
};
(
@field $field:ident: $value:expr
) => {
$value
};
(
@field #[nope] $field:ident: $value:expr
) => {
$value
};
}
But that doesn't help here because I only delegate $value
, not $field: $value,
. But I can't delegate the whole thing because syntactically that's not one token tree(?) that a macro could produce/not produce.
Is there a way, using this or another trick, to achieve this? Preferably avoiding procedural macros, if possible.