The item
fragment can match functions, but if the first argument of the function is a variant of self
, i.e. if it is a method, it is not recognized as an item
:
macro_rules! test {
( $fn:item ) => {}
}
// Ok
test! {
fn foo() -> bool {
true
}
}
// Not ok
test! {
fn foo(self) -> bool {
true
}
}
fn main() {}
How to match a method?
A function that takes self
is not an item, because it can't exist at the top level without an impl
block to give a type to self
.
The surrounding impl
block is an item though.
To match the function, you'd have to break it down, perhaps like this:
macro_rules! test {
( fn $fn:ident ( self ) -> $ret:ty $body:block ) => {};
}
But you have to use the macro inside the impl
block:
impl Foo {
test! {
fn foo(self) -> bool {
true
}
}
}
You'll have to also handle quite a few permutations of possible kinds of function here though, which could end up getting quite repetitive:
// enables the ? operator for optional parts
#![feature(macro_at_most_once_rep)]
macro_rules! test {
( fn $fn:ident ( $($name:ident : $type:ty),* ) $( -> $ret:ty )?
$body:block
) => {};
( fn $fn:ident ( self $(, $name:ident : $type:ty)* ) $( -> $ret:ty )?
$body:block
) => {};
( fn $fn:ident ( &self $(, $name:ident : $type:ty)* ) $( -> $ret:ty )?
$body:block
) => {};
( fn $fn:ident ( &mut self $(, $name:ident : $type:ty)* ) $( -> $ret:ty )?
$body:block
) => {};
}
And these don't even consider lifetime or type parameters.
Getting code reuse, by delegating these cases to another macro, might be tricky because you don't have the type of self
inside the macro, so you might not be able to get rid of the repetition, unfortunately.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With