Attribute Macro async_fn::bare_future[][src]

#[bare_future]
Expand description

One of the main macros of the crate.

#[async_fn::bare_future] allows to express the actual Future return type of an async fn.

Implementation-wise, and thus, semantic-wise, what this macro does is very simple: it removes the async from the async fn, and wraps the function body within an async move { … } block (except for the statements inside the before_async! eager prelude).

The point of doing this is to reduce the rightwards drift that an explicit async move block requires.

Example / unsugaring

use ::async_fn::prelude::*;

async fn foo(/* … */) { /* … */ }
async fn bar(/* … */) -> i32 {
    // …
}

struct Foo {
    // …
}

impl Foo {
    #[bare_future]
    async fn thread_safe_async_method(&self) -> impl Fut<'_, i32> + Send {
        foo(/* … */).await;
        bar(/* … */).await
    }
}
/// The above is sugar for:
impl Foo {
    fn thread_safe_async_method(&self) -> impl Fut<'_, i32> + Send {
        async move {
            foo(/* … */).await;
            bar(/* … */).await
        }
    }
}

The advantages of using #[bare_future] over an async move body are thus slim, but non-negligible:

  • The function is still marked as / appears as async fn, which makes it easier to grep for;
  • The extra rightward drift in the async move { … } body is avoided.

Extra features and benefits

1 — The 'args lifetime

⚠️ Not implemented yet. ⚠️

A [bare_future] async fn function will feature a magical 'args lifetime (parameter) which will represent the “intersection” of the lifetimes / spans of usability of each function parameter. This makes it so:

#[bare_future]
async fn fname(/* args… */) -> impl Fut<'args, RetTy>
/// Has the same semantics as:
async fn fname(/* args… */) -> RetTy

2 — The before_async! eager prelude

  • This is for an opposite goal to that of using 'args, mainly, when wanting to yield a 'static + Future.

See before_async! for more info.