diff options
author | Joel Galenson <jgalenson@google.com> | 2021-05-19 15:24:01 -0700 |
---|---|---|
committer | Joel Galenson <jgalenson@google.com> | 2021-05-19 15:24:01 -0700 |
commit | b266ecd6f4900b7fb2155e3d70e7422a589dc4b3 (patch) | |
tree | ed3bef133f9eb60fe9198597b0ea91adb2c40bfb /src | |
parent | 1fbf099cfb309b9d6f353f3a6f33e005d03bbe60 (diff) | |
download | futures-macro-b266ecd6f4900b7fb2155e3d70e7422a589dc4b3.tar.gz |
Upgrade rust/crates/futures-macro to 0.3.15
Test: make
Change-Id: I545461552c040bb57aab52e2ee9947f05a929f5f
Diffstat (limited to 'src')
-rw-r--r-- | src/executor.rs | 55 | ||||
-rw-r--r-- | src/join.rs | 5 | ||||
-rw-r--r-- | src/lib.rs | 21 | ||||
-rw-r--r-- | src/select.rs | 42 |
4 files changed, 93 insertions, 30 deletions
diff --git a/src/executor.rs b/src/executor.rs new file mode 100644 index 0000000..40a091f --- /dev/null +++ b/src/executor.rs @@ -0,0 +1,55 @@ +use proc_macro::TokenStream; +use proc_macro2::Span; +use quote::{quote, quote_spanned, ToTokens}; + +pub(crate) fn test(args: TokenStream, item: TokenStream) -> TokenStream { + if !args.is_empty() { + return syn::Error::new_spanned(proc_macro2::TokenStream::from(args), "invalid argument") + .to_compile_error() + .into(); + } + + let mut input = syn::parse_macro_input!(item as syn::ItemFn); + + if input.sig.asyncness.take().is_none() { + return syn::Error::new_spanned(input.sig.fn_token, "Only async functions are supported") + .to_compile_error() + .into(); + } + + // If type mismatch occurs, the current rustc points to the last statement. + let (last_stmt_start_span, last_stmt_end_span) = { + let mut last_stmt = input + .block + .stmts + .last() + .map(ToTokens::into_token_stream) + .unwrap_or_default() + .into_iter(); + // `Span` on stable Rust has a limitation that only points to the first + // token, not the whole tokens. We can work around this limitation by + // using the first/last span of the tokens like + // `syn::Error::new_spanned` does. + let start = last_stmt.next().map_or_else(Span::call_site, |t| t.span()); + let end = last_stmt.last().map_or(start, |t| t.span()); + (start, end) + }; + + let path = quote_spanned! {last_stmt_start_span=> + ::futures_test::__private + }; + let body = &input.block; + input.block.stmts = vec![syn::Stmt::Expr( + syn::parse2(quote_spanned! {last_stmt_end_span=> + #path::block_on(async #body) + }) + .unwrap(), + )]; + + let gen = quote! { + #[::core::prelude::v1::test] + #input + }; + + gen.into() +} diff --git a/src/join.rs b/src/join.rs index 048b62a..d427da2 100644 --- a/src/join.rs +++ b/src/join.rs @@ -27,10 +27,7 @@ impl Parse for Join { } } -fn bind_futures( - fut_exprs: Vec<Expr>, - span: Span, -) -> (Vec<TokenStream2>, Vec<Ident>) { +fn bind_futures(fut_exprs: Vec<Expr>, span: Span) -> (Vec<TokenStream2>, Vec<Ident>) { let mut future_let_bindings = Vec::with_capacity(fut_exprs.len()); let future_names: Vec<_> = fut_exprs .into_iter() @@ -13,31 +13,42 @@ extern crate proc_macro; use proc_macro::TokenStream; -use proc_macro_hack::proc_macro_hack; +mod executor; mod join; mod select; /// The `join!` macro. -#[proc_macro_hack] +#[cfg_attr(fn_like_proc_macro, proc_macro)] +#[cfg_attr(not(fn_like_proc_macro), proc_macro_hack::proc_macro_hack)] pub fn join_internal(input: TokenStream) -> TokenStream { crate::join::join(input) } /// The `try_join!` macro. -#[proc_macro_hack] +#[cfg_attr(fn_like_proc_macro, proc_macro)] +#[cfg_attr(not(fn_like_proc_macro), proc_macro_hack::proc_macro_hack)] pub fn try_join_internal(input: TokenStream) -> TokenStream { crate::join::try_join(input) } /// The `select!` macro. -#[proc_macro_hack] +#[cfg_attr(fn_like_proc_macro, proc_macro)] +#[cfg_attr(not(fn_like_proc_macro), proc_macro_hack::proc_macro_hack)] pub fn select_internal(input: TokenStream) -> TokenStream { crate::select::select(input) } /// The `select_biased!` macro. -#[proc_macro_hack] +#[cfg_attr(fn_like_proc_macro, proc_macro)] +#[cfg_attr(not(fn_like_proc_macro), proc_macro_hack::proc_macro_hack)] pub fn select_biased_internal(input: TokenStream) -> TokenStream { crate::select::select_biased(input) } + +// TODO: Change this to doc comment once rustdoc bug fixed. +// The `test` attribute. +#[proc_macro_attribute] +pub fn test_internal(input: TokenStream, item: TokenStream) -> TokenStream { + crate::executor::test(input, item) +} diff --git a/src/select.rs b/src/select.rs index 65b3187..0c8e5f1 100644 --- a/src/select.rs +++ b/src/select.rs @@ -3,8 +3,8 @@ use proc_macro::TokenStream; use proc_macro2::Span; use quote::{format_ident, quote}; -use syn::{parse_quote, Expr, Ident, Pat, Token}; use syn::parse::{Parse, ParseStream}; +use syn::{parse_quote, Expr, Ident, Pat, Token}; mod kw { syn::custom_keyword!(complete); @@ -63,7 +63,10 @@ impl Parse for Select { // Commas after the expression are only optional if it's a `Block` // or it is the last branch in the `match`. - let is_block = match expr { Expr::Block(_) => true, _ => false }; + let is_block = match expr { + Expr::Block(_) => true, + _ => false, + }; if is_block || input.is_empty() { input.parse::<Option<Token![,]>>()?; } else { @@ -76,7 +79,7 @@ impl Parse for Select { CaseKind::Normal(pat, fut_expr) => { select.normal_fut_exprs.push(fut_expr); select.normal_fut_handlers.push((pat, expr)); - }, + } } } @@ -92,22 +95,16 @@ fn declare_result_enum( result_ident: Ident, variants: usize, complete: bool, - span: Span + span: Span, ) -> (Vec<Ident>, syn::ItemEnum) { // "_0", "_1", "_2" let variant_names: Vec<Ident> = - (0..variants) - .map(|num| format_ident!("_{}", num, span = span)) - .collect(); + (0..variants).map(|num| format_ident!("_{}", num, span = span)).collect(); let type_parameters = &variant_names; let variants = &variant_names; - let complete_variant = if complete { - Some(quote!(Complete)) - } else { - None - }; + let complete_variant = if complete { Some(quote!(Complete)) } else { None }; let enum_item = parse_quote! { enum #result_ident<#(#type_parameters,)*> { @@ -148,7 +145,9 @@ fn select_inner(input: TokenStream, random: bool) -> TokenStream { // bind non-`Ident` future exprs w/ `let` let mut future_let_bindings = Vec::with_capacity(parsed.normal_fut_exprs.len()); - let bound_future_names: Vec<_> = parsed.normal_fut_exprs.into_iter() + let bound_future_names: Vec<_> = parsed + .normal_fut_exprs + .into_iter() .zip(variant_names.iter()) .map(|(expr, variant_name)| { match expr { @@ -164,7 +163,7 @@ fn select_inner(input: TokenStream, random: bool) -> TokenStream { __futures_crate::async_await::assert_unpin(&#path); }); path - }, + } _ => { // Bind and pin the resulting Future on the stack. This is // necessary to support direct select! calls on !Unpin @@ -188,8 +187,8 @@ fn select_inner(input: TokenStream, random: bool) -> TokenStream { // For each future, make an `&mut dyn FnMut(&mut Context<'_>) -> Option<Poll<__PrivResult<...>>` // to use for polling that individual future. These will then be put in an array. - let poll_functions = bound_future_names.iter().zip(variant_names.iter()) - .map(|(bound_future_name, variant_name)| { + let poll_functions = bound_future_names.iter().zip(variant_names.iter()).map( + |(bound_future_name, variant_name)| { // Below we lazily create the Pin on the Future below. // This is done in order to avoid allocating memory in the generator // for the Pin variable. @@ -216,7 +215,8 @@ fn select_inner(input: TokenStream, random: bool) -> TokenStream { &mut __futures_crate::task::Context<'_> ) -> __futures_crate::Option<__futures_crate::task::Poll<_>> = &mut #variant_name; } - }); + }, + ); let none_polled = if parsed.complete.is_some() { quote! { @@ -229,13 +229,13 @@ fn select_inner(input: TokenStream, random: bool) -> TokenStream { } }; - let branches = parsed.normal_fut_handlers.into_iter() - .zip(variant_names.iter()) - .map(|((pat, expr), variant_name)| { + let branches = parsed.normal_fut_handlers.into_iter().zip(variant_names.iter()).map( + |((pat, expr), variant_name)| { quote! { #enum_ident::#variant_name(#pat) => { #expr }, } - }); + }, + ); let branches = quote! { #( #branches )* }; let complete_branch = parsed.complete.map(|complete_expr| { |