Gate await keyword for Rust 1.34.0

I am currently in the process of adding async/await support to the oauth2 crate. Now the question came up how to keep this downwards compatible for Rust 1.34 .
I have feature gated the use of futures-0.3 but run in the following issue when attempting to compile using Rust 1.34. How can I continue to support Rust 1.34, assuming the user continues to use futures 0.1 and no async await?

cargo +1.34.0 check                                            
Checking oauth2 v3.0.0-alpha.5
error[E0721]: `await` is a keyword in the 2018 edition
  --> src/reqwest.rs:96:10
   |
96 |         .await
   |          ^^^^^ help: you can use a raw identifier to stay compatible: `r#await`

You are using features that are only available in Rust 1.39. Thus your entire crate will only be compatible with Rust 1.39 and up.

To support older versions of Rust, your code cannot use features that don't exist in those versions. For futures, that means liberal usage of the futures combinators instead of await and returning impl Future instead of async fn.

#[cfg(not(feature = "fancy"))]
use futures::FutureExt;
use std::future::Future;

fn inner() -> impl Future<Output = i32> {
    futures::future::ready(42)
}

#[cfg(not(feature = "fancy"))]
pub fn example()  -> impl Future<Output = i32> {
    inner().map(|v| v + 1)
}

#[cfg(feature = "fancy")]
pub async fn example() -> i32 {
    let v = inner().await;
    v + 1
}
% cargo +beta build --features=fancy
   Compiling aa v0.1.0 (/private/tmp/aa)
    Finished dev [unoptimized + debuginfo] target(s) in 0.11s
% cargo build
   Compiling aa v0.1.0 (/private/tmp/aa)
    Finished dev [unoptimized + debuginfo] target(s) in 0.24s

Since you have to duplicate your entire logic, it doesn't seem worth it to me. Either release a version that only supports Rust 1.39+ and use async / await internally or write the compatible code and use the uglier internals.

Note that you may have to pull any code with .await into a separate module and #[cfg] the entire module to "hide" the keyword usage from older rustcs.

Still, I agree that you should either use async.await internally and require the appropriate toolchain version, or don't and allow older toolchains. Downstream can still use async.await even if you don't internally.

3 Likes