Skip to content

Commit 6dedd3b

Browse files
committed
Migrate to await syntax
1 parent 10fc0b0 commit 6dedd3b

File tree

5 files changed

+71
-50
lines changed

5 files changed

+71
-50
lines changed

futures-async-macro/README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ Processes streams using a for loop.
1717
This is a reimplement of [futures-await]'s `#[async]` for loops for futures 0.3 and is an experimental implementation of [the idea listed as the next step of async/await](https://github.com/rust-lang/rfcs/blob/master/text/2394-async_await.md#for-await-and-processing-streams).
1818

1919
```rust
20-
#![feature(async_await, generators, stmt_expr_attributes, proc_macro_hygiene)]
20+
#![feature(async_await, stmt_expr_attributes, proc_macro_hygiene)]
2121
use futures::for_await;
2222
use futures::prelude::*;
2323

futures-async-macro/src/lib.rs

+66-46
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,8 @@ use proc_macro2::{Span, TokenStream as TokenStream2, TokenTree as TokenTree2};
1010
use quote::{quote, ToTokens};
1111
use syn::{
1212
fold::{self, Fold},
13-
token, ArgCaptured, Error, Expr, ExprCall, ExprForLoop, ExprMacro, ExprYield, FnArg, FnDecl,
14-
Ident, Item, ItemFn, Pat, PatIdent, ReturnType, TypeTuple,
13+
token, ArgCaptured, Error, Expr, ExprCall, ExprField, ExprForLoop, ExprMacro, ExprYield, FnArg,
14+
FnDecl, Ident, Item, ItemFn, Member, Pat, PatIdent, ReturnType, TypeTuple,
1515
};
1616

1717
#[macro_use]
@@ -210,7 +210,7 @@ pub fn async_stream_block(input: TokenStream) -> TokenStream {
210210
tokens.into()
211211
}
212212

213-
/// The scope in which `#[for_await]`, `await!` was called.
213+
/// The scope in which `#[for_await]`, `.await` was called.
214214
///
215215
/// The type of generator depends on which scope is called.
216216
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
@@ -221,7 +221,7 @@ enum Scope {
221221
Stream,
222222
/// `static move ||`, `||`
223223
///
224-
/// It cannot call `#[for_await]`, `await!` in this scope.
224+
/// It cannot call `#[for_await]`, `.await` in this scope.
225225
Closure,
226226
}
227227

@@ -241,49 +241,66 @@ impl Expand {
241241
));
242242
}
243243

244+
let ExprForLoop { label, pat, expr, body, .. } = &expr;
244245
// It needs to adjust the type yielded by the macro because generators used internally by
245246
// async fn yield `()` type, but generators used internally by `async_stream` yield
246247
// `Poll<U>` type.
247-
let yield_ = match self.0 {
248-
Future => TokenStream2::new(),
249-
Stream => quote! { ::futures::core_reexport::task::Poll::Pending },
250-
Closure => return outside_of_async_error!(expr, "#[for_await]"),
251-
};
252-
let ExprForLoop { label, pat, expr, body, .. } = expr;
253-
254-
// Basically just expand to a `poll` loop
255-
syn::parse_quote! {{
256-
let mut __pinned = #expr;
257-
#label
258-
loop {
259-
let #pat = {
260-
match ::futures::async_stream::poll_next_with_tls_context(unsafe {
261-
::futures::core_reexport::pin::Pin::new_unchecked(&mut __pinned)
262-
})
263-
{
264-
::futures::core_reexport::task::Poll::Ready(e) => {
265-
match e {
248+
match self.0 {
249+
Future => {
250+
// Basically just expand to a `poll` loop
251+
syn::parse_quote! {{
252+
let mut __pinned = #expr;
253+
let mut __pinned = unsafe {
254+
::futures::core_reexport::pin::Pin::new_unchecked(&mut __pinned)
255+
};
256+
#label
257+
loop {
258+
let #pat = {
259+
match ::futures::stream::StreamExt::next(&mut __pinned).await {
266260
::futures::core_reexport::option::Option::Some(e) => e,
267261
::futures::core_reexport::option::Option::None => break,
268262
}
269-
}
270-
::futures::core_reexport::task::Poll::Pending => {
271-
yield #yield_;
272-
continue
273-
}
263+
};
264+
265+
#body
274266
}
275-
};
267+
}}
268+
}
269+
Stream => {
270+
// Basically just expand to a `poll` loop
271+
syn::parse_quote! {{
272+
let mut __pinned = #expr;
273+
#label
274+
loop {
275+
let #pat = {
276+
match ::futures::async_stream::poll_next_with_tls_context(unsafe {
277+
::futures::core_reexport::pin::Pin::new_unchecked(&mut __pinned)
278+
})
279+
{
280+
::futures::core_reexport::task::Poll::Ready(e) => {
281+
match e {
282+
::futures::core_reexport::option::Option::Some(e) => e,
283+
::futures::core_reexport::option::Option::None => break,
284+
}
285+
}
286+
::futures::core_reexport::task::Poll::Pending => {
287+
yield ::futures::core_reexport::task::Poll::Pending;
288+
continue
289+
}
290+
}
291+
};
276292

277-
#body
293+
#body
294+
}
295+
}}
278296
}
279-
}}
297+
Closure => return outside_of_async_error!(expr, "#[for_await]"),
298+
}
280299
}
281300

282301
/// Expands `yield expr` in `async_stream` scope.
283302
fn expand_yield(&self, expr: ExprYield) -> ExprYield {
284-
if self.0 != Stream {
285-
return expr;
286-
}
303+
if self.0 != Stream { return expr }
287304

288305
let ExprYield { attrs, yield_token, expr } = expr;
289306
let expr = expr.map_or_else(|| quote!(()), ToTokens::into_token_stream);
@@ -293,28 +310,30 @@ impl Expand {
293310
ExprYield { attrs, yield_token, expr: Some(Box::new(expr)) }
294311
}
295312

296-
/// Expands a macro.
313+
/// Expands `async_stream_block!` macro.
297314
fn expand_macro(&mut self, mut expr: ExprMacro) -> Expr {
298-
if self.0 == Stream && expr.mac.path.is_ident("await") {
299-
return self.expand_await_macros(expr);
300-
} else if expr.mac.path.is_ident("async_stream_block") {
315+
if expr.mac.path.is_ident("async_stream_block") {
301316
let mut e: ExprCall = syn::parse(async_stream_block(expr.mac.tts.into())).unwrap();
302317
e.attrs.append(&mut expr.attrs);
303-
return Expr::Call(e);
318+
Expr::Call(e)
319+
} else {
320+
Expr::Macro(expr)
304321
}
305-
306-
Expr::Macro(expr)
307322
}
308323

309-
/// Expands `await!(expr)` in `async_stream` scope.
324+
/// Expands `expr.await` in `async_stream` scope.
310325
///
311326
/// It needs to adjust the type yielded by the macro because generators used internally by
312327
/// async fn yield `()` type, but generators used internally by `async_stream` yield
313328
/// `Poll<U>` type.
314-
fn expand_await_macros(&mut self, expr: ExprMacro) -> Expr {
315-
assert_eq!(self.0, Stream);
329+
fn expand_await(&mut self, expr: ExprField) -> Expr {
330+
if self.0 != Stream { return Expr::Field(expr) }
316331

317-
let expr = expr.mac.tts;
332+
match &expr.member {
333+
Member::Named(x) if x == "await" => {}
334+
_ => return Expr::Field(expr),
335+
}
336+
let expr = expr.base;
318337

319338
// Because macro input (`#expr`) is untrusted, use `syn::parse2` + `expr_compile_error`
320339
// instead of `syn::parse_quote!` to generate better error messages (`syn::parse_quote!`
@@ -349,8 +368,9 @@ impl Fold for Expand {
349368
}
350369

351370
let expr = match fold::fold_expr(self, expr) {
352-
Expr::ForLoop(expr) => self.expand_for_await(expr),
353371
Expr::Yield(expr) => Expr::Yield(self.expand_yield(expr)),
372+
Expr::Field(expr) => self.expand_await(expr),
373+
Expr::ForLoop(expr) => self.expand_for_await(expr),
354374
Expr::Macro(expr) => self.expand_macro(expr),
355375
expr => expr,
356376
};

futures/testcrate/ui/nested.stderr

+1
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ note: the type is part of the generator because of this `yield`
3030
|
3131
5 | #[async_stream]
3232
| ^^^^^^^^^^^^^^^
33+
= note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
3334

3435
error: aborting due to 3 previous errors
3536

futures/tests/async_stream/nested.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@ fn _stream1() -> i32 {
66
let _ = async { // impl Generator<Yield = (), Return = U>
77
#[for_await]
88
for i in stream::iter(vec![1, 2]) {
9-
await!(future::lazy(|_| i * i));
9+
future::lazy(|_| i * i).await;
1010
}
1111
};
12-
await!(future::lazy(|_| ()));
12+
future::lazy(|_| ()).await;
1313
}

futures/tests/async_stream_tests.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
#![feature(async_await, await_macro)]
1+
#![feature(async_await)]
22
#![cfg_attr(all(feature = "async-stream", feature = "nightly"), feature(generators, stmt_expr_attributes, proc_macro_hygiene))]
33

44
#[cfg(all(feature = "async-stream", feature = "nightly"))]

0 commit comments

Comments
 (0)