diff --git a/futures-macro/src/lib.rs b/futures-macro/src/lib.rs index 095929780d..b565c290c6 100644 --- a/futures-macro/src/lib.rs +++ b/futures-macro/src/lib.rs @@ -35,12 +35,12 @@ pub fn try_join_internal(input: TokenStream) -> TokenStream { /// The `select!` macro. #[proc_macro_hack] -pub fn select(input: TokenStream) -> TokenStream { +pub fn select_internal(input: TokenStream) -> TokenStream { crate::select::select(input) } /// The `select_biased!` macro. #[proc_macro_hack] -pub fn select_biased(input: TokenStream) -> TokenStream { +pub fn select_biased_internal(input: TokenStream) -> TokenStream { crate::select::select_biased(input) } diff --git a/futures-macro/src/select.rs b/futures-macro/src/select.rs index f7f688b6ae..f615b5399c 100644 --- a/futures-macro/src/select.rs +++ b/futures-macro/src/select.rs @@ -3,16 +3,14 @@ use proc_macro::TokenStream; use proc_macro2::Span; use quote::{format_ident, quote}; -use syn::{parenthesized, parse_quote, Expr, Ident, Pat, Token}; +use syn::{parse_quote, Expr, Ident, Pat, Token}; use syn::parse::{Parse, ParseStream}; mod kw { syn::custom_keyword!(complete); - syn::custom_keyword!(futures_crate_path); } struct Select { - futures_crate_path: Option, // span of `complete`, then expression after `=> ...` complete: Option, default: Option, @@ -30,23 +28,12 @@ enum CaseKind { impl Parse for Select { fn parse(input: ParseStream<'_>) -> syn::Result { let mut select = Select { - futures_crate_path: None, complete: None, default: None, normal_fut_exprs: vec![], normal_fut_handlers: vec![], }; - // When `futures_crate_path(::path::to::futures::lib)` is provided, - // it sets the path through which futures library functions will be - // accessed. - if input.peek(kw::futures_crate_path) { - input.parse::()?; - let content; - parenthesized!(content in input); - select.futures_crate_path = Some(content.parse()?); - } - while !input.is_empty() { let case_kind = if input.peek(kw::complete) { // `complete` @@ -147,8 +134,6 @@ pub(crate) fn select_biased(input: TokenStream) -> TokenStream { fn select_inner(input: TokenStream, random: bool) -> TokenStream { let parsed = syn::parse_macro_input!(input as Select); - let futures_crate: syn::Path = parsed.futures_crate_path.unwrap_or_else(|| parse_quote!(::futures_util)); - // should be def_site, but that's unstable let span = Span::call_site(); @@ -175,8 +160,8 @@ fn select_inner(input: TokenStream, random: bool) -> TokenStream { // We check for this condition here in order to be able to // safely use Pin::new_unchecked(&mut #path) later on. future_let_bindings.push(quote! { - #futures_crate::async_await::assert_fused_future(&#path); - #futures_crate::async_await::assert_unpin(&#path); + __futures_crate::async_await::assert_fused_future(&#path); + __futures_crate::async_await::assert_unpin(&#path); }); path }, @@ -214,28 +199,28 @@ fn select_inner(input: TokenStream, random: bool) -> TokenStream { // 2. The Future is created in scope of the select! function and will // not be moved for the duration of it. It is thereby stack-pinned quote! { - let mut #variant_name = |__cx: &mut #futures_crate::task::Context<'_>| { + let mut #variant_name = |__cx: &mut __futures_crate::task::Context<'_>| { let mut #bound_future_name = unsafe { ::core::pin::Pin::new_unchecked(&mut #bound_future_name) }; - if #futures_crate::future::FusedFuture::is_terminated(&#bound_future_name) { + if __futures_crate::future::FusedFuture::is_terminated(&#bound_future_name) { None } else { - Some(#futures_crate::future::FutureExt::poll_unpin( + Some(__futures_crate::future::FutureExt::poll_unpin( &mut #bound_future_name, __cx, ).map(#enum_ident::#variant_name)) } }; let #variant_name: &mut dyn FnMut( - &mut #futures_crate::task::Context<'_> - ) -> Option<#futures_crate::task::Poll<_>> = &mut #variant_name; + &mut __futures_crate::task::Context<'_> + ) -> Option<__futures_crate::task::Poll<_>> = &mut #variant_name; } }); let none_polled = if parsed.complete.is_some() { quote! { - #futures_crate::task::Poll::Ready(#enum_ident::Complete) + __futures_crate::task::Poll::Ready(#enum_ident::Complete) } } else { quote! { @@ -267,13 +252,13 @@ fn select_inner(input: TokenStream, random: bool) -> TokenStream { let await_select_fut = if parsed.default.is_some() { // For select! with default this returns the Poll result quote! { - __poll_fn(&mut #futures_crate::task::Context::from_waker( - #futures_crate::task::noop_waker_ref() + __poll_fn(&mut __futures_crate::task::Context::from_waker( + __futures_crate::task::noop_waker_ref() )) } } else { quote! { - #futures_crate::future::poll_fn(__poll_fn).await + __futures_crate::future::poll_fn(__poll_fn).await } }; @@ -281,7 +266,7 @@ fn select_inner(input: TokenStream, random: bool) -> TokenStream { // For select! with default __select_result is a Poll, otherwise not quote! { match __select_result { - #futures_crate::task::Poll::Ready(result) => match result { + __futures_crate::task::Poll::Ready(result) => match result { #branches }, _ => #default_expr @@ -297,7 +282,7 @@ fn select_inner(input: TokenStream, random: bool) -> TokenStream { let shuffle = if random { quote! { - #futures_crate::async_await::shuffle(&mut __select_arr); + __futures_crate::async_await::shuffle(&mut __select_arr); } } else { quote!() @@ -309,7 +294,7 @@ fn select_inner(input: TokenStream, random: bool) -> TokenStream { let __select_result = { #( #future_let_bindings )* - let mut __poll_fn = |__cx: &mut #futures_crate::task::Context<'_>| { + let mut __poll_fn = |__cx: &mut __futures_crate::task::Context<'_>| { let mut __any_polled = false; #( #poll_functions )* @@ -318,12 +303,12 @@ fn select_inner(input: TokenStream, random: bool) -> TokenStream { #shuffle for poller in &mut __select_arr { let poller: &mut &mut dyn FnMut( - &mut #futures_crate::task::Context<'_> - ) -> Option<#futures_crate::task::Poll<_>> = poller; + &mut __futures_crate::task::Context<'_> + ) -> Option<__futures_crate::task::Poll<_>> = poller; match poller(__cx) { - Some(x @ #futures_crate::task::Poll::Ready(_)) => + Some(x @ __futures_crate::task::Poll::Ready(_)) => return x, - Some(#futures_crate::task::Poll::Pending) => { + Some(__futures_crate::task::Poll::Pending) => { __any_polled = true; } None => {} @@ -333,7 +318,7 @@ fn select_inner(input: TokenStream, random: bool) -> TokenStream { if !__any_polled { #none_polled } else { - #futures_crate::task::Poll::Pending + __futures_crate::task::Poll::Pending } }; diff --git a/futures-util/src/async_await/select_mod.rs b/futures-util/src/async_await/select_mod.rs index 38153c7f7a..0471f09182 100644 --- a/futures-util/src/async_await/select_mod.rs +++ b/futures-util/src/async_await/select_mod.rs @@ -2,8 +2,6 @@ use proc_macro_hack::proc_macro_hack; -#[doc(hidden)] -#[macro_export] macro_rules! document_select_macro { // This branch is required for `futures 0.3.1`, from before select_biased was introduced ($select:item) => { @@ -158,7 +156,7 @@ macro_rules! document_select_macro { }; ($select:item $select_biased:item) => { - $crate::document_select_macro!($select); + document_select_macro!($select); /// Polls multiple futures and streams simultaneously, executing the branch /// for the future that finishes first. Unlike [`select!`], if multiple futures are ready, @@ -310,11 +308,34 @@ macro_rules! document_select_macro { }; } +#[cfg(feature = "std")] +#[doc(hidden)] +#[proc_macro_hack(support_nested)] +pub use futures_macro::select_internal; + +#[doc(hidden)] +#[proc_macro_hack(support_nested)] +pub use futures_macro::select_biased_internal; + document_select_macro! { #[cfg(feature = "std")] - #[proc_macro_hack(support_nested)] - pub use futures_macro::select; + #[macro_export] + macro_rules! select { + ($($tokens:tt)*) => {{ + use $crate::__reexport as __futures_crate; + $crate::select_internal! { + $( $tokens )* + } + }} + } - #[proc_macro_hack(support_nested)] - pub use futures_macro::select_biased; + #[macro_export] + macro_rules! select_biased { + ($($tokens:tt)*) => {{ + use $crate::__reexport as __futures_crate; + $crate::select_biased_internal! { + $( $tokens )* + } + }} + } } diff --git a/futures/src/lib.rs b/futures/src/lib.rs index 3656daeccc..a49fc8634a 100644 --- a/futures/src/lib.rs +++ b/futures/src/lib.rs @@ -537,47 +537,9 @@ pub mod never { // proc-macro re-export -------------------------------------- -// Not public API. -#[doc(hidden)] -pub use futures_core::core_reexport; - -// Not public API. -#[cfg(feature = "async-await")] -#[doc(hidden)] -pub use futures_util::async_await; - -// Not public API. -#[cfg(feature = "async-await")] -#[doc(hidden)] -pub mod inner_macro { - #[cfg(feature = "std")] - pub use futures_util::select; - pub use futures_util::select_biased; -} - #[cfg(feature = "async-await")] pub use futures_util::{join, try_join}; - +#[cfg(feature = "std")] +pub use futures_util::select; #[cfg(feature = "async-await")] -futures_util::document_select_macro! { - #[cfg(feature = "std")] - #[macro_export] - macro_rules! select { // replace `::futures_util` with `::futures` as the crate path - ($($tokens:tt)*) => { - $crate::inner_macro::select! { - futures_crate_path ( ::futures ) - $( $tokens )* - } - } - } - - #[macro_export] - macro_rules! select_biased { // replace `::futures_util` with `::futures` as the crate path - ($($tokens:tt)*) => { - $crate::inner_macro::select_biased! { - futures_crate_path ( ::futures ) - $( $tokens )* - } - } - } -} +pub use futures_util::select_biased; diff --git a/futures/tests/macro-reexport/src/lib.rs b/futures/tests/macro-reexport/src/lib.rs index 4866f329c6..49691c9e07 100644 --- a/futures/tests/macro-reexport/src/lib.rs +++ b/futures/tests/macro-reexport/src/lib.rs @@ -1,5 +1,8 @@ // normal reexport -pub use futures03::{join, try_join}; +pub use futures03::{join, try_join, select, select_biased}; // reexport + rename -pub use futures03::{join as join2, try_join as try_join2}; +pub use futures03::{ + join as join2, try_join as try_join2, + select as select2, select_biased as select_biased2, +}; diff --git a/futures/tests/macro-tests/src/main.rs b/futures/tests/macro-tests/src/main.rs index 3a230f1bcf..5d11f60834 100644 --- a/futures/tests/macro-tests/src/main.rs +++ b/futures/tests/macro-tests/src/main.rs @@ -1,7 +1,7 @@ // Check that it works even if proc-macros are reexported. fn main() { - use futures03::executor::block_on; + use futures03::{executor::block_on, future}; // join! macro let _ = block_on(async { @@ -18,6 +18,52 @@ fn main() { Ok::<(), ()>(()) }); - // TODO: add select! and select_biased! + // select! macro + let _ = block_on(async { + let mut a = future::ready(()); + let mut b = future::pending::<()>(); + let _ = futures03::select! { + _ = a => {}, + _ = b => unreachable!(), + }; + + let mut a = future::ready(()); + let mut b = future::pending::<()>(); + let _ = macro_reexport::select! { + _ = a => {}, + _ = b => unreachable!(), + }; + + let mut a = future::ready(()); + let mut b = future::pending::<()>(); + let _ = macro_reexport::select2! { + _ = a => {}, + _ = b => unreachable!(), + }; + }); + + // select_biased! macro + let _ = block_on(async { + let mut a = future::ready(()); + let mut b = future::pending::<()>(); + let _ = futures03::select_biased! { + _ = a => {}, + _ = b => unreachable!(), + }; + + let mut a = future::ready(()); + let mut b = future::pending::<()>(); + let _ = macro_reexport::select_biased! { + _ = a => {}, + _ = b => unreachable!(), + }; + + let mut a = future::ready(()); + let mut b = future::pending::<()>(); + let _ = macro_reexport::select_biased2! { + _ = a => {}, + _ = b => unreachable!(), + }; + }); }