Nested async block/fn

Hi!

There's a really useful crate for logging: GitHub - elichai/log-derive: A procedural macro for auto logging output of functions

What it does is it takes a fn and places its body into a closure and then logs closure value in case of an error:

#[logfn(INFO)]
fn wrapped_function() -> Result<(), String> {
    if other() {
        return Ok()
    } else {
        return Err("some error".to_string())
    }

    something_else()?;
    
    Ok(())
}

it expands (roughly) to

fn wrapped_function() -> Result<(), String> {
    let result = (||{
        if other() {
            return Ok()
        } else {
            return Err("some error".to_string())
        }

        something_else()?;
    
        Ok(())
    })();

    if let Err(e) = result {
        error!("{}", e);
    }

    result
}

The problem is that it does not work well with async/await because async closures are not stable. How would you wrap this function to allow the same functionality but with support for async?

I thought about creating another fn on the same level as orginal but it does not work for traits. If I put generated fn into the original then I get problems with self i.e. you cannot define method inside the method.

Any thoughts how to accomplish this?

Can you put an async block inside the closure?

async fn wrapped_function() -> Result<(), String> {
    let result = (||{
        async {
            if other() {
                return Ok()
            } else {
                return Err("some error".to_string())
            }

            something_else()?;
    
            Ok(())
        }
    })().await;

    if let Err(e) = result {
        error!("{}", e);
    }

    result
}

You don't even need the closure. An async block introduces its own function scope.

async fn wrapped_function() -> Result<(), String> {
    let result = async move {
        if other() {
            return Ok()
        } else {
            return Err("some error".to_string())
        }

        something_else()?;

        Ok(())
    }.await;

    if let Err(e) = result {
        error!("{}", e);
    }

    result
}
3 Likes

Wow! Thanks @alice :grinning:

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.