Skip to content

Commit 8772c18

Browse files
committed
Support reexport for join!/try_join! macros
1 parent 2f8943d commit 8772c18

File tree

10 files changed

+108
-76
lines changed

10 files changed

+108
-76
lines changed

Cargo.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@ members = [
1111
"futures-util",
1212
"futures-test",
1313

14+
"futures/tests/macro-tests",
15+
"futures/tests/macro-reexport",
16+
1417
"examples/functional",
1518
"examples/imperative",
1619
]

futures-macro/src/join.rs

Lines changed: 21 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -4,32 +4,17 @@ use proc_macro::TokenStream;
44
use proc_macro2::{Span, TokenStream as TokenStream2};
55
use quote::{format_ident, quote};
66
use syn::parse::{Parse, ParseStream};
7-
use syn::{parenthesized, parse_quote, Expr, Ident, Token};
8-
9-
mod kw {
10-
syn::custom_keyword!(futures_crate_path);
11-
}
7+
use syn::{Expr, Ident, Token};
128

139
#[derive(Default)]
1410
struct Join {
15-
futures_crate_path: Option<syn::Path>,
1611
fut_exprs: Vec<Expr>,
1712
}
1813

1914
impl Parse for Join {
2015
fn parse(input: ParseStream<'_>) -> syn::Result<Self> {
2116
let mut join = Join::default();
2217

23-
// When `futures_crate_path(::path::to::futures::lib)` is provided,
24-
// it sets the path through which futures library functions will be
25-
// accessed.
26-
if input.peek(kw::futures_crate_path) {
27-
input.parse::<kw::futures_crate_path>()?;
28-
let content;
29-
parenthesized!(content in input);
30-
join.futures_crate_path = Some(content.parse()?);
31-
}
32-
3318
while !input.is_empty() {
3419
join.fut_exprs.push(input.parse::<Expr>()?);
3520

@@ -43,7 +28,6 @@ impl Parse for Join {
4328
}
4429

4530
fn bind_futures(
46-
futures_crate: &syn::Path,
4731
fut_exprs: Vec<Expr>,
4832
span: Span,
4933
) -> (Vec<TokenStream2>, Vec<Ident>) {
@@ -56,7 +40,7 @@ fn bind_futures(
5640
future_let_bindings.push(quote! {
5741
// Move future into a local so that it is pinned in one place and
5842
// is no longer accessible by the end user.
59-
let mut #name = #futures_crate::future::maybe_done(#expr);
43+
let mut #name = __futures_crate::future::maybe_done(#expr);
6044
});
6145
name
6246
})
@@ -69,39 +53,35 @@ fn bind_futures(
6953
pub(crate) fn join(input: TokenStream) -> TokenStream {
7054
let parsed = syn::parse_macro_input!(input as Join);
7155

72-
let futures_crate = parsed
73-
.futures_crate_path
74-
.unwrap_or_else(|| parse_quote!(::futures_util));
75-
7656
// should be def_site, but that's unstable
7757
let span = Span::call_site();
7858

79-
let (future_let_bindings, future_names) = bind_futures(&futures_crate, parsed.fut_exprs, span);
59+
let (future_let_bindings, future_names) = bind_futures(parsed.fut_exprs, span);
8060

8161
let poll_futures = future_names.iter().map(|fut| {
8262
quote! {
83-
__all_done &= #futures_crate::core_reexport::future::Future::poll(
84-
unsafe { #futures_crate::core_reexport::pin::Pin::new_unchecked(&mut #fut) }, __cx).is_ready();
63+
__all_done &= __futures_crate::future::Future::poll(
64+
unsafe { __futures_crate::core_reexport::pin::Pin::new_unchecked(&mut #fut) }, __cx).is_ready();
8565
}
8666
});
8767
let take_outputs = future_names.iter().map(|fut| {
8868
quote! {
89-
unsafe { #futures_crate::core_reexport::pin::Pin::new_unchecked(&mut #fut) }.take_output().unwrap(),
69+
unsafe { __futures_crate::core_reexport::pin::Pin::new_unchecked(&mut #fut) }.take_output().unwrap(),
9070
}
9171
});
9272

9373
TokenStream::from(quote! { {
9474
#( #future_let_bindings )*
9575

96-
#futures_crate::future::poll_fn(move |__cx: &mut #futures_crate::task::Context<'_>| {
76+
__futures_crate::future::poll_fn(move |__cx: &mut __futures_crate::task::Context<'_>| {
9777
let mut __all_done = true;
9878
#( #poll_futures )*
9979
if __all_done {
100-
#futures_crate::core_reexport::task::Poll::Ready((
80+
__futures_crate::task::Poll::Ready((
10181
#( #take_outputs )*
10282
))
10383
} else {
104-
#futures_crate::core_reexport::task::Poll::Pending
84+
__futures_crate::task::Poll::Pending
10585
}
10686
}).await
10787
} })
@@ -111,29 +91,25 @@ pub(crate) fn join(input: TokenStream) -> TokenStream {
11191
pub(crate) fn try_join(input: TokenStream) -> TokenStream {
11292
let parsed = syn::parse_macro_input!(input as Join);
11393

114-
let futures_crate = parsed
115-
.futures_crate_path
116-
.unwrap_or_else(|| parse_quote!(::futures_util));
117-
11894
// should be def_site, but that's unstable
11995
let span = Span::call_site();
12096

121-
let (future_let_bindings, future_names) = bind_futures(&futures_crate, parsed.fut_exprs, span);
97+
let (future_let_bindings, future_names) = bind_futures(parsed.fut_exprs, span);
12298

12399
let poll_futures = future_names.iter().map(|fut| {
124100
quote! {
125-
if #futures_crate::core_reexport::future::Future::poll(
126-
unsafe { #futures_crate::core_reexport::pin::Pin::new_unchecked(&mut #fut) }, __cx).is_pending()
101+
if __futures_crate::future::Future::poll(
102+
unsafe { __futures_crate::core_reexport::pin::Pin::new_unchecked(&mut #fut) }, __cx).is_pending()
127103
{
128104
__all_done = false;
129-
} else if unsafe { #futures_crate::core_reexport::pin::Pin::new_unchecked(&mut #fut) }.output_mut().unwrap().is_err() {
105+
} else if unsafe { __futures_crate::core_reexport::pin::Pin::new_unchecked(&mut #fut) }.output_mut().unwrap().is_err() {
130106
// `.err().unwrap()` rather than `.unwrap_err()` so that we don't introduce
131107
// a `T: Debug` bound.
132108
// Also, for an error type of ! any code after `err().unwrap()` is unreachable.
133109
#[allow(unreachable_code)]
134-
return #futures_crate::core_reexport::task::Poll::Ready(
135-
#futures_crate::core_reexport::result::Result::Err(
136-
unsafe { #futures_crate::core_reexport::pin::Pin::new_unchecked(&mut #fut) }.take_output().unwrap().err().unwrap()
110+
return __futures_crate::task::Poll::Ready(
111+
__futures_crate::core_reexport::result::Result::Err(
112+
unsafe { __futures_crate::core_reexport::pin::Pin::new_unchecked(&mut #fut) }.take_output().unwrap().err().unwrap()
137113
)
138114
);
139115
}
@@ -145,25 +121,25 @@ pub(crate) fn try_join(input: TokenStream) -> TokenStream {
145121
// an `E: Debug` bound.
146122
// Also, for an ok type of ! any code after `ok().unwrap()` is unreachable.
147123
#[allow(unreachable_code)]
148-
unsafe { #futures_crate::core_reexport::pin::Pin::new_unchecked(&mut #fut) }.take_output().unwrap().ok().unwrap(),
124+
unsafe { __futures_crate::core_reexport::pin::Pin::new_unchecked(&mut #fut) }.take_output().unwrap().ok().unwrap(),
149125
}
150126
});
151127

152128
TokenStream::from(quote! { {
153129
#( #future_let_bindings )*
154130

155131
#[allow(clippy::diverging_sub_expression)]
156-
#futures_crate::future::poll_fn(move |__cx: &mut #futures_crate::task::Context<'_>| {
132+
__futures_crate::future::poll_fn(move |__cx: &mut __futures_crate::task::Context<'_>| {
157133
let mut __all_done = true;
158134
#( #poll_futures )*
159135
if __all_done {
160-
#futures_crate::core_reexport::task::Poll::Ready(
161-
#futures_crate::core_reexport::result::Result::Ok((
136+
__futures_crate::task::Poll::Ready(
137+
__futures_crate::core_reexport::result::Result::Ok((
162138
#( #take_outputs )*
163139
))
164140
)
165141
} else {
166-
#futures_crate::core_reexport::task::Poll::Pending
142+
__futures_crate::task::Poll::Pending
167143
}
168144
}).await
169145
} })

futures-macro/src/lib.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,13 +23,13 @@ mod select;
2323

2424
/// The `join!` macro.
2525
#[proc_macro_hack]
26-
pub fn join(input: TokenStream) -> TokenStream {
26+
pub fn join_internal(input: TokenStream) -> TokenStream {
2727
crate::join::join(input)
2828
}
2929

3030
/// The `try_join!` macro.
3131
#[proc_macro_hack]
32-
pub fn try_join(input: TokenStream) -> TokenStream {
32+
pub fn try_join_internal(input: TokenStream) -> TokenStream {
3333
crate::join::try_join(input)
3434
}
3535

futures-util/src/async_await/join_mod.rs

Lines changed: 26 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,6 @@
22
33
use proc_macro_hack::proc_macro_hack;
44

5-
#[doc(hidden)]
6-
#[macro_export]
75
macro_rules! document_join_macro {
86
($join:item $try_join:item) => {
97
/// Polls multiple futures simultaneously, returning a tuple
@@ -73,10 +71,32 @@ macro_rules! document_join_macro {
7371
}
7472
}
7573

74+
#[doc(hidden)]
75+
#[proc_macro_hack(support_nested)]
76+
pub use futures_macro::join_internal;
77+
78+
#[doc(hidden)]
79+
#[proc_macro_hack(support_nested)]
80+
pub use futures_macro::try_join_internal;
81+
7682
document_join_macro! {
77-
#[proc_macro_hack(support_nested)]
78-
pub use futures_macro::join;
83+
#[macro_export]
84+
macro_rules! join {
85+
($($tokens:tt)*) => {{
86+
use $crate::__reexport as __futures_crate;
87+
$crate::join_internal! {
88+
$( $tokens )*
89+
}
90+
}}
91+
}
7992

80-
#[proc_macro_hack(support_nested)]
81-
pub use futures_macro::try_join;
93+
#[macro_export]
94+
macro_rules! try_join {
95+
($($tokens:tt)*) => {{
96+
use $crate::__reexport as __futures_crate;
97+
$crate::try_join_internal! {
98+
$( $tokens )*
99+
}
100+
}}
101+
}
82102
}

futures-util/src/lib.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,14 @@ pub use self::async_await::*;
5151
#[doc(hidden)]
5252
pub use futures_core::core_reexport;
5353

54+
// Not public API.
55+
#[cfg(feature = "async-await")]
56+
#[doc(hidden)]
57+
pub mod __reexport {
58+
#[doc(hidden)]
59+
pub use crate::*;
60+
}
61+
5462
macro_rules! cfg_target_has_atomic {
5563
($($item:item)*) => {$(
5664
#[cfg_attr(feature = "cfg-target-has-atomic", cfg(target_has_atomic = "ptr"))]

futures/src/lib.rs

Lines changed: 1 addition & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -550,35 +550,13 @@ pub use futures_util::async_await;
550550
#[cfg(feature = "async-await")]
551551
#[doc(hidden)]
552552
pub mod inner_macro {
553-
pub use futures_util::join;
554-
pub use futures_util::try_join;
555553
#[cfg(feature = "std")]
556554
pub use futures_util::select;
557555
pub use futures_util::select_biased;
558556
}
559557

560558
#[cfg(feature = "async-await")]
561-
futures_util::document_join_macro! {
562-
#[macro_export]
563-
macro_rules! join { // replace `::futures_util` with `::futures` as the crate path
564-
($($tokens:tt)*) => {
565-
$crate::inner_macro::join! {
566-
futures_crate_path ( ::futures )
567-
$( $tokens )*
568-
}
569-
}
570-
}
571-
572-
#[macro_export]
573-
macro_rules! try_join { // replace `::futures_util` with `::futures` as the crate path
574-
($($tokens:tt)*) => {
575-
$crate::inner_macro::try_join! {
576-
futures_crate_path ( ::futures )
577-
$( $tokens )*
578-
}
579-
}
580-
}
581-
}
559+
pub use futures_util::{join, try_join};
582560

583561
#[cfg(feature = "async-await")]
584562
futures_util::document_select_macro! {
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
[package]
2+
name = "macro-reexport"
3+
version = "0.1.0"
4+
authors = ["Taiki Endo <[email protected]>"]
5+
edition = "2018"
6+
publish = false
7+
8+
[dependencies]
9+
futures03 = { path = "../..", package = "futures" }
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
// normal reexport
2+
pub use futures03::{join, try_join};
3+
4+
// reexport + rename
5+
pub use futures03::{join as join2, try_join as try_join2};

futures/tests/macro-tests/Cargo.toml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
[package]
2+
name = "macro-tests"
3+
version = "0.1.0"
4+
authors = ["Taiki Endo <[email protected]>"]
5+
edition = "2018"
6+
publish = false
7+
8+
[dependencies]
9+
futures03 = { path = "../..", package = "futures" }
10+
macro-reexport = { path = "../macro-reexport" }

futures/tests/macro-tests/src/main.rs

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
// Check that it works even if proc-macros are reexported.
2+
3+
fn main() {
4+
use futures03::executor::block_on;
5+
6+
// join! macro
7+
let _ = block_on(async {
8+
let _ = futures03::join!(async {}, async {});
9+
let _ = macro_reexport::join!(async {}, async {});
10+
let _ = macro_reexport::join2!(async {}, async {});
11+
});
12+
13+
// try_join! macro
14+
let _ = block_on(async {
15+
let _ = futures03::try_join!(async { Ok::<(), ()>(()) }, async { Ok::<(), ()>(()) });
16+
let _ = macro_reexport::try_join!(async { Ok::<(), ()>(()) }, async { Ok::<(), ()>(()) });
17+
let _ = macro_reexport::try_join2!(async { Ok::<(), ()>(()) }, async { Ok::<(), ()>(()) });
18+
Ok::<(), ()>(())
19+
});
20+
21+
// TODO: add select! and select_biased!
22+
23+
}

0 commit comments

Comments
 (0)