Snap for 8358640 from a2e0086b1a3443173b9d9951ca9b11a3a6ca3d83 to mainline-go-extservices-release Change-Id: Ide7ceba5366c0b69daf15fa0cb038d16122f7856
diff --git a/.cargo_vcs_info.json b/.cargo_vcs_info.json index f3ad3ab..942329b 100644 --- a/.cargo_vcs_info.json +++ b/.cargo_vcs_info.json
@@ -1,5 +1,6 @@ { "git": { - "sha1": "c91f8691672c7401b1923ab00bf138975c99391a" - } -} + "sha1": "fc1e3250219170e31cddb8857a276cba7dd08d44" + }, + "path_in_vcs": "futures-macro" +} \ No newline at end of file
diff --git a/Android.bp b/Android.bp index 996d4d9..7674084 100644 --- a/Android.bp +++ b/Android.bp
@@ -1,4 +1,4 @@ -// This file is generated by cargo2android.py --run --dependencies. +// This file is generated by cargo2android.py --config cargo2android.json. // Do not modify this file as changes will be overridden on upgrade. package { @@ -40,6 +40,8 @@ rust_proc_macro { name: "libfutures_macro", crate_name: "futures_macro", + cargo_env_compat: true, + cargo_pkg_version: "0.3.21", srcs: ["src/lib.rs"], edition: "2018", rustlibs: [ @@ -47,12 +49,4 @@ "libquote", "libsyn", ], - proc_macros: ["libproc_macro_hack"], } - -// dependent_library ["feature_list"] -// proc-macro-hack-0.5.19 -// proc-macro2-1.0.26 "default,proc-macro" -// quote-1.0.9 "default,proc-macro" -// syn-1.0.68 "clone-impls,default,derive,full,parsing,printing,proc-macro,quote" -// unicode-xid-0.2.1 "default"
diff --git a/Cargo.toml b/Cargo.toml index a01c8cc..86fc5c9 100644 --- a/Cargo.toml +++ b/Cargo.toml
@@ -3,28 +3,26 @@ # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies -# to registry (e.g., crates.io) dependencies +# to registry (e.g., crates.io) dependencies. # -# If you believe there's an error in this file please file an -# issue against the rust-lang/cargo repository. If you're -# editing this file be aware that the upstream Cargo.toml -# will likely look very different (and much more reasonable) +# If you are reading this file be aware that the original Cargo.toml +# will likely look very different (and much more reasonable). +# See Cargo.toml.orig for the original contents. [package] edition = "2018" +rust-version = "1.45" name = "futures-macro" -version = "0.3.13" -authors = ["Taylor Cramer <[email protected]>", "Taiki Endo <[email protected]>"] -description = "The futures-rs procedural macro implementations.\n" +version = "0.3.21" +description = """ +The futures-rs procedural macro implementations. +""" homepage = "https://rust-lang.github.io/futures-rs" -documentation = "https://docs.rs/futures-macro/0.3" license = "MIT OR Apache-2.0" repository = "https://github.com/rust-lang/futures-rs" [lib] proc-macro = true -[dependencies.proc-macro-hack] -version = "0.5.19" [dependencies.proc-macro2] version = "1.0" @@ -33,7 +31,7 @@ version = "1.0" [dependencies.syn] -version = "1.0" +version = "1.0.56" features = ["full"] [features]
diff --git a/Cargo.toml.orig b/Cargo.toml.orig index 090f736..a929d0f 100644 --- a/Cargo.toml.orig +++ b/Cargo.toml.orig
@@ -1,12 +1,11 @@ [package] name = "futures-macro" +version = "0.3.21" edition = "2018" -version = "0.3.13" -authors = ["Taylor Cramer <[email protected]>", "Taiki Endo <[email protected]>"] +rust-version = "1.45" license = "MIT OR Apache-2.0" repository = "https://github.com/rust-lang/futures-rs" homepage = "https://rust-lang.github.io/futures-rs" -documentation = "https://docs.rs/futures-macro/0.3" description = """ The futures-rs procedural macro implementations. """ @@ -18,6 +17,5 @@ [dependencies] proc-macro2 = "1.0" -proc-macro-hack = "0.5.19" quote = "1.0" -syn = { version = "1.0", features = ["full"] } +syn = { version = "1.0.56", features = ["full"] }
diff --git a/METADATA b/METADATA index 05b2aa8..ca144da 100644 --- a/METADATA +++ b/METADATA
@@ -7,13 +7,13 @@ } url { type: ARCHIVE - value: "https://static.crates.io/crates/futures-macro/futures-macro-0.3.13.crate" + value: "https://static.crates.io/crates/futures-macro/futures-macro-0.3.21.crate" } - version: "0.3.13" + version: "0.3.21" license_type: NOTICE last_upgrade_date { - year: 2021 - month: 4 + year: 2022 + month: 3 day: 1 } }
diff --git a/TEST_MAPPING b/TEST_MAPPING index a86ecdd..5ef61de 100644 --- a/TEST_MAPPING +++ b/TEST_MAPPING
@@ -1,56 +1,45 @@ // Generated by update_crate_tests.py for tests that depend on this crate. { + "imports": [ + { + "path": "external/rust/crates/anyhow" + }, + { + "path": "external/rust/crates/futures-util" + }, + { + "path": "external/rust/crates/tokio" + }, + { + "path": "external/rust/crates/tokio-test" + } + ], "presubmit": [ { - "name": "tokio-test_device_test_src_lib" + "name": "ZipFuseTest" }, { - "name": "tokio-test_device_test_tests_io" + "name": "authfs_device_test_src_lib" }, { - "name": "tokio-test_device_test_tests_macros" + "name": "doh_unit_test" }, { - "name": "anyhow_device_test_tests_test_convert" + "name": "virtualizationservice_device_test" + } + ], + "presubmit-rust": [ + { + "name": "ZipFuseTest" }, { - "name": "tokio-test_device_test_tests_block_on" + "name": "authfs_device_test_src_lib" }, { - "name": "anyhow_device_test_tests_test_source" + "name": "doh_unit_test" }, { - "name": "anyhow_device_test_tests_test_context" - }, - { - "name": "anyhow_device_test_tests_test_fmt" - }, - { - "name": "anyhow_device_test_tests_test_macros" - }, - { - "name": "anyhow_device_test_tests_test_repr" - }, - { - "name": "futures-util_device_test_src_lib" - }, - { - "name": "anyhow_device_test_tests_test_ffi" - }, - { - "name": "anyhow_device_test_tests_test_chain" - }, - { - "name": "anyhow_device_test_tests_test_boxed" - }, - { - "name": "anyhow_device_test_tests_test_autotrait" - }, - { - "name": "anyhow_device_test_src_lib" - }, - { - "name": "anyhow_device_test_tests_test_downcast" + "name": "virtualizationservice_device_test" } ] }
diff --git a/cargo2android.json b/cargo2android.json new file mode 100644 index 0000000..958632b --- /dev/null +++ b/cargo2android.json
@@ -0,0 +1,3 @@ +{ + "run": true +} \ No newline at end of file
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 @@ } } -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()
diff --git a/src/lib.rs b/src/lib.rs index 5f0c47c..0afe34b 100644 --- a/src/lib.rs +++ b/src/lib.rs
@@ -1,11 +1,13 @@ //! The futures-rs procedural macro implementations. -#![recursion_limit = "128"] -#![warn(rust_2018_idioms, unreachable_pub)] -// It cannot be included in the published code because this lints have false positives in the minimum required version. -#![cfg_attr(test, warn(single_use_lifetimes))] -#![warn(clippy::all)] -#![doc(test(attr(deny(warnings), allow(dead_code, unused_assignments, unused_variables))))] +#![warn(rust_2018_idioms, single_use_lifetimes, unreachable_pub)] +#![doc(test( + no_crate_inject, + attr( + deny(warnings, rust_2018_idioms, single_use_lifetimes), + allow(dead_code, unused_assignments, unused_variables) + ) +))] // Since https://github.com/rust-lang/cargo/pull/7700 `proc_macro` is part of the prelude for // proc-macro crates, but to support older compilers we still need this explicit `extern crate`. @@ -13,31 +15,47 @@ extern crate proc_macro; use proc_macro::TokenStream; -use proc_macro_hack::proc_macro_hack; +mod executor; mod join; mod select; +mod stream_select; /// The `join!` macro. -#[proc_macro_hack] +#[proc_macro] pub fn join_internal(input: TokenStream) -> TokenStream { crate::join::join(input) } /// The `try_join!` macro. -#[proc_macro_hack] +#[proc_macro] pub fn try_join_internal(input: TokenStream) -> TokenStream { crate::join::try_join(input) } /// The `select!` macro. -#[proc_macro_hack] +#[proc_macro] pub fn select_internal(input: TokenStream) -> TokenStream { crate::select::select(input) } /// The `select_biased!` macro. -#[proc_macro_hack] +#[proc_macro] pub fn select_biased_internal(input: TokenStream) -> TokenStream { crate::select::select_biased(input) } + +// TODO: Change this to doc comment once rustdoc bug fixed: https://github.com/rust-lang/futures-rs/pull/2435 +// The `test` attribute. +#[proc_macro_attribute] +pub fn test_internal(input: TokenStream, item: TokenStream) -> TokenStream { + crate::executor::test(input, item) +} + +/// The `stream_select!` macro. +#[proc_macro] +pub fn stream_select_internal(input: TokenStream) -> TokenStream { + crate::stream_select::stream_select(input.into()) + .unwrap_or_else(syn::Error::into_compile_error) + .into() +}
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 @@ // 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 @@ CaseKind::Normal(pat, fut_expr) => { select.normal_fut_exprs.push(fut_expr); select.normal_fut_handlers.push((pat, expr)); - }, + } } } @@ -92,22 +95,16 @@ 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 @@ // 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 @@ __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 @@ // 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 @@ &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 @@ } }; - 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| {
diff --git a/src/stream_select.rs b/src/stream_select.rs new file mode 100644 index 0000000..9927b53 --- /dev/null +++ b/src/stream_select.rs
@@ -0,0 +1,113 @@ +use proc_macro2::TokenStream; +use quote::{format_ident, quote, ToTokens}; +use syn::{parse::Parser, punctuated::Punctuated, Expr, Index, Token}; + +/// The `stream_select!` macro. +pub(crate) fn stream_select(input: TokenStream) -> Result<TokenStream, syn::Error> { + let args = Punctuated::<Expr, Token![,]>::parse_terminated.parse2(input)?; + if args.len() < 2 { + return Ok(quote! { + compile_error!("stream select macro needs at least two arguments.") + }); + } + let generic_idents = (0..args.len()).map(|i| format_ident!("_{}", i)).collect::<Vec<_>>(); + let field_idents = (0..args.len()).map(|i| format_ident!("__{}", i)).collect::<Vec<_>>(); + let field_idents_2 = (0..args.len()).map(|i| format_ident!("___{}", i)).collect::<Vec<_>>(); + let field_indices = (0..args.len()).map(Index::from).collect::<Vec<_>>(); + let args = args.iter().map(|e| e.to_token_stream()); + + Ok(quote! { + { + #[derive(Debug)] + struct StreamSelect<#(#generic_idents),*> (#(Option<#generic_idents>),*); + + enum StreamEnum<#(#generic_idents),*> { + #( + #generic_idents(#generic_idents) + ),*, + None, + } + + impl<ITEM, #(#generic_idents),*> __futures_crate::stream::Stream for StreamEnum<#(#generic_idents),*> + where #(#generic_idents: __futures_crate::stream::Stream<Item=ITEM> + ::std::marker::Unpin,)* + { + type Item = ITEM; + + fn poll_next(mut self: ::std::pin::Pin<&mut Self>, cx: &mut __futures_crate::task::Context<'_>) -> __futures_crate::task::Poll<Option<Self::Item>> { + match self.get_mut() { + #( + Self::#generic_idents(#generic_idents) => ::std::pin::Pin::new(#generic_idents).poll_next(cx) + ),*, + Self::None => panic!("StreamEnum::None should never be polled!"), + } + } + } + + impl<ITEM, #(#generic_idents),*> __futures_crate::stream::Stream for StreamSelect<#(#generic_idents),*> + where #(#generic_idents: __futures_crate::stream::Stream<Item=ITEM> + ::std::marker::Unpin,)* + { + type Item = ITEM; + + fn poll_next(mut self: ::std::pin::Pin<&mut Self>, cx: &mut __futures_crate::task::Context<'_>) -> __futures_crate::task::Poll<Option<Self::Item>> { + let Self(#(ref mut #field_idents),*) = self.get_mut(); + #( + let mut #field_idents_2 = false; + )* + let mut any_pending = false; + { + let mut stream_array = [#(#field_idents.as_mut().map(|f| StreamEnum::#generic_idents(f)).unwrap_or(StreamEnum::None)),*]; + __futures_crate::async_await::shuffle(&mut stream_array); + + for mut s in stream_array { + if let StreamEnum::None = s { + continue; + } else { + match __futures_crate::stream::Stream::poll_next(::std::pin::Pin::new(&mut s), cx) { + r @ __futures_crate::task::Poll::Ready(Some(_)) => { + return r; + }, + __futures_crate::task::Poll::Pending => { + any_pending = true; + }, + __futures_crate::task::Poll::Ready(None) => { + match s { + #( + StreamEnum::#generic_idents(_) => { #field_idents_2 = true; } + ),*, + StreamEnum::None => panic!("StreamEnum::None should never be polled!"), + } + }, + } + } + } + } + #( + if #field_idents_2 { + *#field_idents = None; + } + )* + if any_pending { + __futures_crate::task::Poll::Pending + } else { + __futures_crate::task::Poll::Ready(None) + } + } + + fn size_hint(&self) -> (usize, Option<usize>) { + let mut s = (0, Some(0)); + #( + if let Some(new_hint) = self.#field_indices.as_ref().map(|s| s.size_hint()) { + s.0 += new_hint.0; + // We can change this out for `.zip` when the MSRV is 1.46.0 or higher. + s.1 = s.1.and_then(|a| new_hint.1.map(|b| a + b)); + } + )* + s + } + } + + StreamSelect(#(Some(#args)),*) + + } + }) +}