Designator for async modifier in macro_rules

Hi, I'm trying to extend this macro_rules! example one step further by allowing optional specification of an async modifier (and other small changes, like 1 required arg - but that's not an issue for me):
https://veykril.github.io/tlborm/decl-macros/building-blocks/parsing.html

macro_rules! function_item_matcher {
    (

        $( #[$meta:meta] )*
    //  ^~~~attributes~~~~^
        $vis:vis fn $name:ident ( $( $arg_name:ident : $arg_ty:ty ),* $(,)? )
    //                          ^~~~~~~~~~~~~~~~argument list!~~~~~~~~~~~~~~^
            $( -> $ret_ty:ty )?
    //      ^~~~return type~~~^
            { $($tt:tt)* }
    //      ^~~~~body~~~~^
    ) => {
        $( #[$meta] )*
        $vis fn $name ( $( $arg_name : $arg_ty ),* ) $( -> $ret_ty )? { $($tt)* }
    }
}

But it seems to conflict with the :vis designator and I'm not sure what would be the proper designator - I guessed token tree but that led to:

$vis:vis $($a_sync:tt)? fn $name:ident ( $arg1:ident : $arg1_type:ty, $( $arg_name:ident : $arg_ty:ty ),* $(,)? ),
| ^^^^^^^^^^ not allowed after vis fragments
|
= note: allowed there are: ,, an ident or a type

Why not $(async)? as-is? That seems to compile just fine either way:

macro_rules! function_item_matcher {
    (

        $( #[$meta:meta] )*
    //  ^~~~attributes~~~~^
        $vis:vis $(async)? fn $name:ident ( $( $arg_name:ident : $arg_ty:ty ),* $(,)? )
    //                          ^~~~~~~~~~~~~~~~argument list!~~~~~~~~~~~~~~^
            $( -> $ret_ty:ty )?
    //      ^~~~return type~~~^
            { $($tt:tt)* }
    //      ^~~~~body~~~~^
    ) => {
        $( #[$meta] )*
        $vis fn $name ( $( $arg_name : $arg_ty ),* ) $( -> $ret_ty )? { $($tt)* }
    }
}

fn main() {
    function_item_matcher!(pub fn foo_sync() -> usize { 0 });
    function_item_matcher!(pub async fn foo_async() -> usize { 0 });
}
1 Like

@H2CO3 but is the resulting function that gets created async? I'm missing how the output of the macro is generating an async fn if you're still returning only $vis fn $name.... Is the presence of async accounted for by $vis?

Oh, sorry, I missed that. In this case, you can just create two matcher clauses, with and without async:

macro_rules! function_item_matcher {
    (
        $(#[$meta:meta])*
        $vis:vis async fn $name:ident ($($arg_name:ident: $arg_ty:ty),* $(,)?) $(-> $ret_ty:ty)? {
            $($tt:tt)*
        }
    ) => {
        $(#[$meta])*
        $vis async fn $name ($($arg_name: $arg_ty),*) $(-> $ret_ty)? {
            $($tt)*
        }
    };
    (
        $(#[$meta:meta])*
        $vis:vis fn $name:ident ($($arg_name:ident: $arg_ty:ty),* $(,)?) $(-> $ret_ty:ty)? {
            $($tt:tt)*
        }
    ) => {
        $(#[$meta])*
        $vis fn $name ($($arg_name: $arg_ty),*) $(-> $ret_ty)? {
            $($tt)*
        }
    };
}

I don't believe there is any way to retrieve literal identifiers in the transcriber part of the macro, and simply using $async:ident or $async:path also fails due to ambiguity.

1 Like

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.