Async closures

Impact

  • Able to create async closures that work like ordinary closures but which can await values.
  • Analogous traits to Fn, FnMut, FnOnce, etc
  • Reconcile async blocks and async closures

Design notes

Async functions need their own traits, analogous to Fn and friends:


#![allow(unused)]
fn main() {
#[repr(async_inline)]
trait AsyncFnOnce<A> {
    type Output;

    // Uh-oh! You can't encode these as `async fn` using inline async functions!
    async fn call(mut self, args: A) -> Self::Output;
}

#[repr(async_inline)]
trait AsyncFnMut: AsyncFnOnce {
    type Output;

    async fn call_mut(&mut self, args: A) -> Self::Output;
}

#[repr(async_inline)]
trait AsyncFn: AsyncFnMut {
    // Uh-oh! You can't encode these as `async fn` using inline async functions!
    async fn call(&self, args: A) -> Self::Output;
}
}

Some notes:

AsyncFnOnce is almost the same as Future/Async -- both represent, effectively, a future that can be driven exactly once. The difference is that your type can distinguish statically between the uncalled state and the persistent state after being called, if you wish, by using separate types for each. This can be useful for situations where an async fn is Send up until the point it is called, at which point it creates inner state that is not Send.

The concept of AsyncFn is more clear, but it requires storing the state externally to make sense: how else can there be multiple parallel executions.