implicit-await 0.1.0

Implicitly await calls returning Future impls
Documentation
# implicit-await - implicit `Future` awaiting for Rust

## Usage

A **nightly** Rust compiler is required until the [async_await](https://github.com/rust-lang/rust/issues/50547) feature is stabilized.

Add this to your `Cargo.toml`:

```toml
[dependencies]
implicit-await = "0.1"
```

Now you can use `#[implicit_await]`:

```rust
use implicit_await::implicit_await;

#[implicit_await]
async fn foo() {
    // Any functions returning a future (`async fn` or `fn -> impl Future`) will be automatically awaited.
}
```

## Description

Rust's async/await feature uses the postfix `.await` operator to explicitly request suspension points within `async` functions. The discussion around the syntax of the `.await` operator has been long and contentious, driven by the desire to interoperate smoothly with Rust's existing postfix `?` operator (among other concerns).

When I was reading about the various syntax proposals from which `.await` finally emerged the leader, it occurred to me that the problems would be greatly simplified by making the wrapping/unwrapping behavior of `async` functions internally consistent. In standard Rust, `async` functions implicitly wrap their return values in a `Future`, but the *inputs* to `async` functions - the child `Futures` that determine the shape of the compiler-generated state machine - are explicitly unwrapped via `.await`. If instead `async` functions handled both wrapping and unwrapping implicitly, then there would be no need for the `.await` operator, bypassing the syntax concerns about the operator.

This library provides a procedural macro `#[implicit_await]` which transforms `async` functions to implicitly unwrap child `Future`s.

|                                   | Standard Rust                 | #[implicit_await]    |
|-----------------------------------|-------------------------------|----------------------|
| Outputs (function results) are... | implicitly wrapped            | implicitly wrapped   |
| Inputs (child futures) are...     | explicitly unwrapped (.await) | implicitly unwrapped |

## Example

See the [sum](implicit-await/examples/sum.rs) example for a full working demo of the following.

Suppose you have the following three functions, which range from fully synchronous to fully asynchronous.

```rust
type IntResult = Result<u32, ()>;

// Fully synchronous
fn num_sync(num: u32) -> IntResult {
    Ok(num)
}

// Half-and-half
fn num_fut(num: u32) -> impl Future<Output = IntResult> {
    ready(Ok(num))
}

// Fully asynchronous
async fn num_async(num: u32) -> IntResult {
    Ok(num)
}
```

In standard Rust, calls to synchronous and asynchronous functions are distinguished by the need to postfix the `.await` operator.

```rust
async fn sum() -> IntResult {
    // No .await - a synchronous function.
    let one: u32 = num_sync(1)?;
    // .await - asynchronous function.
    let two: u32 = num_fut(2).await?;
    // .await - asynchronous function.
    let three: u32 = num_async(3).await?;
    // Note that the return value is implicitly wrapped.
    Ok(one + two + three)
}
```

With `implicit-await`, synchronous and asynchronous functions behave equivalently due to the implicit awaiting behavior. This allows the `?` operator to work as expected without any additional syntax.

```rust
#[implicit_await]
async fn sum() -> IntResult {
    // Synchronous function.
    let one: u32 = num_sync(1)?;
    // A `fn -> impl Future` is implicitly awaited.
    let two: u32 = num_fut(2)?;
    // An `async fn` is implicitly awaited.
    let three: u32 = num_async(3)?;
    Ok(one + two + three)
}
```

`implicit-await` makes calls to asynchronous functions behave identically to calls to synchronous functions from the point of view of program control flow. The intuitive rule that *functions complete before they return*, which Rust programmers naturally learn from calling synchronous functions, also applies to asynchronous function calls. However, sometimes you have use-cases where you want explicit control over suspension points. The `defer!` macro allows you to *defer* awaits so that you can start multiple asynchronous processes in parallel. A common example of this use case is making multiple network requests at the same time, then waiting for all of them to complete.

```rust
use implicit_await::defer;

#[implicit_await]
async fn sum() -> IntResult {
    // Start three futures in parallel without implicitly awaiting.
    let (one, two, three) = defer!{ (
        num_fut(1),
        num_async(2),
        num_async(3)
    ) };
    // This `join` call is implicitly awaited because the defer! block ended.
    let (one, two) = futures::future::join(one, two);
    // If you have a bare `Future`, you're free to .await it if you want.
    let three = three.await?;
    Ok(one? + two? + three);
}
```

## What's the catch?

In a nutshell: ``error[E0599]: no method named `as_future` found for type `your::type::here` in the current scope``

The catch is that Rust doesn't support negative or mutually exclusive trait bounds. Because of this, I needed to make a choice whether to support `Future` types seamlessly and `!Future` types painfully, or `!Future` types seamlessly and `Future` types painfully. I chose the former. This means that types which do not implement `Future` need to be manually supported.

| You're calling sync functions that return... | Then you need to...                                                                                                                                                                                                                                               |
|----------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| Types from `std`                             | Do nothing ("std" is a default feature)                                                                                                                                                                                                                           |
| Types from a third-party crate               |  Check the features list to see whether implicit-await already supports that crate, and if so enable the feature. Otherwise submit an issue requesting support for that crate's types be added.   Rockstars can include a PR to add support along with the issue! |
| Types from your own crate                    |  Use the as_future! macro to add support in your own code. OR submit a PR to implicit-await to support your crate behind a feature flag.

## Features

* `std` (*default-feature*) - Enable support for Rust's standard library types. Disable this feature for `no-std` support.

## TODOs

* Fix bug in the as_future! macro which makes multi-generic invocations not work.
* Go through all of `std` adding types
* Come up with a list of other crates to add support for, and do so.

## Dependencies

I strive to limit dependencies where possible. The direct dependencies of the `implicit-await` project are `proc-macro2`, `quote`, and `syn`, all used to implement the `#[implicit_await]` procedural macro. `unicode-xid` is brought in as a transitive dependency.

```
implicit-await v0.1.0
└── implicit-await-macro v0.1.0
    ├── proc-macro2 v0.4.30
    │   └── unicode-xid v0.1.0
    ├── quote v0.6.12
    │   └── proc-macro2 v0.4.30 (*)
    └── syn v0.15.34
        ├── proc-macro2 v0.4.30 (*)
        ├── quote v0.6.12 (*)
        └── unicode-xid v0.1.0 (*)
```

## Acknowledgements

Apparently futures in Kotlin work similarly to this.