Currently the only(?) way to detect the presence of an optional or repeated keyword is by abusing the vis macro fragment, since it may be empty.
For example, a macro that optionally adds an unsafe modifier to the generated fn item:
macro_rules! my_closure_like_macro {
{
$($is_unsafe:vis unsafe)? |
$($arg0_name:ident: $arg0_ty:ty $(, $argn_name:ident: $argn_ty:ty)*)?
| $(-> $ret_ty:ty)? $body:expr
} => {
// actually produce a fn item instead of a normal closure :)
{
$($is_unsafe unsafe)? fn anon(
$($arg0_name: $arg0_ty $(, $argn_name: $argn_ty)*)?
) $(-> $ret_ty)? {
$body
}
anon
}
};
}
static MY_FFI_VTABLE: VTbl = VTbl {
add_u64xn: my_closure_like_macro! {
unsafe |ptr: *const u64, n: usize| -> u64 {
// ... stuff here ...
}
},
};
One way to fix this issue is by adding an empty macro fragment specifier. $fragment:empty does not consume any tokens but can be used to expand repetitions of a capture group.
macro_rules! my_closure_like_macro {
{
$(unsafe $is_unsafe:empty)? |
$($arg0_name:ident: $arg0_ty:ty $(, $argn_name:ident: $argn_ty:ty)*)?
| $(-> $ret_ty:ty)? $body:expr
} => {
// ... no changes ...
};
}
Another way to fix this is with explicit repetitions via named capture groups.
macro_rules! my_closure_like_macro {
{
$is_unsafe:(unsafe)? |
$($arg0_name:ident: $arg0_ty:ty $(, $argn_name:ident: $argn_ty:ty)*)?
| $(-> $ret_ty:ty)? $body:expr
} => {
// explicit expansion for all repetitions without having to use a capture
$is_unsafe:(unsafe)? /* ... the rest is the same */
};
}
This would also make other things easier, like counting the number of expressions passed into a macro:
macro_rules! my_vec {
[ $items:($item:expr),* $(,)? ] => {
{
let mut my_vec = MyVec::with_capacity(0 $items:(+ 1)*); // no "ignore!"
$(my_vec.push($item);)*
my_vec
}
};
}