Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Using #[async_recursion] inside a declarative macro #29

Closed
HectorMRC opened this issue Aug 24, 2023 · 2 comments · Fixed by #30
Closed

Using #[async_recursion] inside a declarative macro #29

HectorMRC opened this issue Aug 24, 2023 · 2 comments · Fixed by #30

Comments

@HectorMRC
Copy link

I am trying to implement a declarative macro that, given a type, implements a recursive asynchronous function that takes that type as parameter. However, it seems unfeasible when the given type is a reference, since the type may not live as long as the 'async_recursion lifetime.

A minimal example of the declarative macros is something as following:

macro_rules! help_please {
    ($param:ty) => {
        #[async_recursion]
        async fn recursive_fn<F>(param: $param, f: &F)
        where
            F: Fn($param) + Sync + Send,
        {
            f(param);
        }
    };
}

And then, if I use it like in the example down below, it does not compile and tells me to add explicit lifetime 'async_recursion to the type of 'param': &'async_recursion usize. What cannot be done since the lifetime `async_recursion does not exist at that level.

macros_async::help_please!(&usize);

I am aware that my approach may be weird or absolutely wrong; however, I would like to know if there is any way to tell async_recursion which is the lifetime that should be taken as `async_recursion. Can this situation be resolved somehow? Thanks in advance!

@dcchut
Copy link
Owner

dcchut commented Aug 24, 2023

Looks like a bug in this library: &usize when parsed by a macro_rules macro ends up from syn as a "None delimited group", which isn't how syn parses that type if you were to write it yourself. I'll have a look at a fix.

In the mean time you should be able to get something working by breaking up the macro into a few cases:

macro_rules! help_please {
    (& $param:ty) => {
        #[async_recursion]
        async fn recursive_fn<F>(param: &$param, f: &F)
        where
            F: Fn(&$param) + Sync + Send,
        {
            f(param);
        }
    };
    (&mut $param:ty) => {
        #[async_recursion]
        async fn recursive_fn<F>(param: &mut $param, f: &F)
        where
            F: Fn(&mut $param) + Sync + Send,
        {
            f(param);
        }
    };
    ($param:ty) => {
        #[async_recursion]
        async fn recursive_fn<F>(param: $param, f: &F)
        where
            F: Fn($param) + Sync + Send,
        {
            f(param);
        }
    };
}

@HectorMRC
Copy link
Author

Thank you a lot @dcchut !

Breaking up the macro works fine, but it does not solve what I was trying to avoid: code repetition 😅. Besides, in my case, this workaround does not differ from implementing the methods directly.

For now, I am keeping them as independent methods. If at any moment this issue gets resolved, I will return to my previous approach.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants