Snap for 7772614 from 85ce0ff92b87b30d0489628007b34a2ce44482b6 to tm-release

Change-Id: I136aa8105b765f89db5f3e186a7ce80af1a83d0c
diff --git a/.cargo_vcs_info.json b/.cargo_vcs_info.json
index 99dc8b0..ffd4f55 100644
--- a/.cargo_vcs_info.json
+++ b/.cargo_vcs_info.json
@@ -1,5 +1,5 @@
 {
   "git": {
-    "sha1": "ab38fd29d3f84f8fc028fa7883e53dba423da0ee"
+    "sha1": "7caefa51304e78fd5018cd5d2a03f3b9089cc010"
   }
 }
diff --git a/Android.bp b/Android.bp
index 582da8a..0cdc53f 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 --run.
 // 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.17",
     srcs: ["src/lib.rs"],
     edition: "2018",
     cfgs: ["fn_like_proc_macro"],
@@ -50,11 +52,3 @@
     ],
     proc_macros: ["libproc_macro_hack"],
 }
-
-// dependent_library ["feature_list"]
-//   autocfg-1.0.1
-//   proc-macro-hack-0.5.19
-//   proc-macro2-1.0.28 "default,proc-macro"
-//   quote-1.0.9 "default,proc-macro"
-//   syn-1.0.74 "clone-impls,default,derive,full,parsing,printing,proc-macro,quote"
-//   unicode-xid-0.2.2 "default"
diff --git a/Cargo.toml b/Cargo.toml
index 7135483..8043d65 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -12,7 +12,7 @@
 [package]
 edition = "2018"
 name = "futures-macro"
-version = "0.3.16"
+version = "0.3.17"
 authors = ["Taylor Cramer <cramertj@google.com>", "Taiki Endo <te316e89@gmail.com>"]
 description = "The futures-rs procedural macro implementations.\n"
 homepage = "https://rust-lang.github.io/futures-rs"
diff --git a/Cargo.toml.orig b/Cargo.toml.orig
index 1acd4a2..3b2740c 100644
--- a/Cargo.toml.orig
+++ b/Cargo.toml.orig
@@ -1,7 +1,7 @@
 [package]
 name = "futures-macro"
 edition = "2018"
-version = "0.3.16"
+version = "0.3.17"
 authors = ["Taylor Cramer <cramertj@google.com>", "Taiki Endo <te316e89@gmail.com>"]
 license = "MIT OR Apache-2.0"
 repository = "https://github.com/rust-lang/futures-rs"
diff --git a/METADATA b/METADATA
index b9823d8..2337a3f 100644
--- a/METADATA
+++ b/METADATA
@@ -7,13 +7,13 @@
   }
   url {
     type: ARCHIVE
-    value: "https://static.crates.io/crates/futures-macro/futures-macro-0.3.16.crate"
+    value: "https://static.crates.io/crates/futures-macro/futures-macro-0.3.17.crate"
   }
-  version: "0.3.16"
+  version: "0.3.17"
   license_type: NOTICE
   last_upgrade_date {
     year: 2021
-    month: 8
-    day: 9
+    month: 9
+    day: 22
   }
 }
diff --git a/src/lib.rs b/src/lib.rs
index d1cbc3c..fa93e48 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -19,6 +19,7 @@
 mod executor;
 mod join;
 mod select;
+mod stream_select;
 
 /// The `join!` macro.
 #[cfg_attr(fn_like_proc_macro, proc_macro)]
@@ -54,3 +55,12 @@
 pub fn test_internal(input: TokenStream, item: TokenStream) -> TokenStream {
     crate::executor::test(input, item)
 }
+
+/// The `stream_select!` macro.
+#[cfg_attr(fn_like_proc_macro, proc_macro)]
+#[cfg_attr(not(fn_like_proc_macro), proc_macro_hack::proc_macro_hack)]
+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/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)),*)
+
+        }
+    })
+}