macro_rules! async_closure {
    (
        { $( $field:ident : $t:ty  = $init:expr ),* $(,)? };
        async | $( $args:ident  : $a:ty ),* $(,)? | -> $out:ty
        $e:block
    ) => { ... };
}
Expand description

Generate a value that is of unnamed closure type implemented with AsyncFn.

Syntax

Consisted of two parts:

  1. a block {}; in which multiple assignments field_name: field_type = field_value are seperated by ,
  2. an async closure async |arg1: arg1_type, ...| -> return_type { /* any async code here */ }

Fields or arguments can be empty, i.e.

  • empty fields: {};
  • empty arguments: async | | -> return_type { /* async code and captured variables */ }
    (note it’s | | instead of ||, and the return_type is a must anyway)

Details:

componentrule / usagetrick / caveat
field_nameused as unnamed struct’s fields and variable names in async coderebind when mutation is required
field_typeowned types or referenced typesonly 'static or 'a lifetime allowed
field_valueany value expression as the initial states / captured variables
arg_nameused as variable names in async code (_ is not an ident thus disallowed)rebind when mutation is required
arg_typeowned types or referenced types (normally no need to annotate lifetimes )'a is disallowed; but '_ is allowed
return_typea must (even when () is returned)

Also note: arg_types and return_type must correspond to its AsyncFn* generic types, i.e.

#![feature(async_fn_in_trait)]
#![allow(incomplete_features)]
use async_closure::async_closure;

// correspond to `capture_lifetimes::AsyncFn<'env, (), usize>`
// note that the concept of arguments is represented by a tuple
async_closure!({}; async | | -> usize { 0 }); 

// `for<'any> capture_lifetimes::AsyncFn<'env, (&'any str,), usize>`
// note that single argument is represented by `(type,)` where the comma is important
async_closure!({}; async |_s: &str| -> usize { 0 }); 

// `for<'any> capture_lifetimes::AsyncFn<'env, (&'any str, &'any mut Vec<u8>), ()>`
async_closure!({}; async |_s: &str, _buf: &mut Vec<u8>| -> () {}); 

// etc.

Examples

#![feature(async_fn_in_trait)]
#![allow(incomplete_features)]
use async_closure::async_closure as cb;

let mut v = vec![];

// zero arguments
cb!({
    v: &'a mut Vec<u8> = &mut v,
}; async | | -> usize {
    // to show the type; you don't have to do this
    let v: &&mut Vec<u8> = v; // you can never obtain &mut via `AsyncFn`
    v.len()
});

// one argument and returns unit type
cb!({
    v: &'a [u8] = &v,
}; async |_s: &mut [u8]| -> () { }); // `_` is not an ident, thus not allowed

// two arguments and returning referenced captured data with lifetime 'a
use std::borrow::Cow;
cb!(
    { v: &'a [u8] = &v };
    async |arg1: &mut [u8], arg2: Cow<'_, str>| -> &'a [u8] { v }
);

// three arguments and rebinds the variables
cb!({ v: &'a [u8] = &v };
    async |arg1: &mut [u8], arg2: Cow<'_, str>, vec: Vec<u8>| -> () {
    let mut vec = vec; // rebinding
    vec.extend_from_slice(v); // v: &&[u8]
    vec.extend_from_slice(*v);
});
cb!({ v: Vec<u8> = v };
    async |arg1: &mut [u8], arg2: Cow<'_, str>, vec: Vec<u8>| -> () {
    let _: &Vec<u8> = v;
});