+49
-8
futures/src/combinators/join.rs
+49
-8
futures/src/combinators/join.rs
···
5
5
use std::mem;
6
6
use std::{pin::Pin, sync::atomic::Ordering};
7
7
use std::{sync::atomic::AtomicBool, task::Poll};
8
+
8
9
/// from yoshuawuyts/futures-concurrency
9
10
/// Wait for all futures to complete.
10
11
///
···
13
14
pub trait Join<'scope> {
14
15
/// The resulting output type.
15
16
type Output;
16
-
/// The [`Future`] implementation returned by this method.
17
+
/// The [`ScopedFuture`] implementation returned by this method.
17
18
type Future: ScopedFuture<'scope, Output = Self::Output>;
18
19
/// Waits for multiple futures to complete.
19
20
///
···
87
88
}
88
89
89
90
macro_rules! impl_join_tuple {
90
-
($StructName:ident $($F:ident)+) => {
91
-
#[allow(non_snake_case)]
92
-
struct Wakers<'scope> {
93
-
$($F: WakeStore<'scope>,)*
91
+
($namespace: ident $StructName:ident $($F:ident)+) => {
92
+
93
+
mod $namespace {
94
+
use super::WakeStore;
95
+
96
+
#[allow(non_snake_case)]
97
+
pub struct Wakers<'scope> {
98
+
$(pub $F: WakeStore<'scope>,)*
99
+
}
94
100
}
95
101
96
102
#[allow(non_snake_case)]
97
103
pub struct $StructName<'scope, $($F: ScopedFuture<'scope>),+> {
98
104
$($F: MaybeDone<'scope, $F>,)*
99
-
wakers: Wakers<'scope>,
105
+
wakers: $namespace::Wakers<'scope>,
100
106
}
101
107
102
108
impl<'scope, $($F: ScopedFuture<'scope> + 'scope),+> ScopedFuture<'scope>
···
113
119
114
120
if let MaybeDone::Future(fut) = &mut this.$F {
115
121
ready &= if this.wakers.$F.take_ready() {
122
+
// # Safety
123
+
//
124
+
// mem::transmute is necessary to convert between
125
+
// `&'poll dyn Wake<'scope>` and
126
+
// `&'scope dyn Wake<'scope>`, where `'poll` is the
127
+
// lifetime implicitly assigned to the `&mut self`
128
+
// argument.
129
+
//
130
+
// This is safe because
131
+
// - `Self: 'scope` (all data inside `Join` live
132
+
// for at least `'scope`)
133
+
// - `this.wakers.$F` is pinned
134
+
// - mutation to `this.wakers.$F.parent` doesn't
135
+
// violate the `&'scope dyn Wake`
116
136
unsafe {
117
137
Pin::new_unchecked(fut).poll(
118
138
mem::transmute::<&dyn Wake<'scope>, &'scope dyn Wake<'scope>>(
···
129
149
if ready {
130
150
Poll::Ready((
131
151
$(
152
+
// # Safety
153
+
//
154
+
// All $Fs start as `MaybeDone::Future`.
155
+
//
156
+
// `ready == true` is only hit when we know every
157
+
// future either just finished or previously
158
+
// finished, meaning they are all
159
+
// `MaybeDone::Done`.
160
+
//
161
+
// `MaybeDone::Done::take_output()` always returns
162
+
// the owned output of the inner future.
132
163
unsafe {
133
164
Pin::new_unchecked(&mut this.$F)
134
165
.take_output()
···
152
183
153
184
$StructName {
154
185
$($F: maybe_done($F),)*
155
-
wakers: Wakers { $($F: WakeStore::new(),)* },
186
+
wakers: $namespace::Wakers { $($F: WakeStore::new(),)* },
156
187
}
157
188
}
158
189
}
159
190
};
160
191
}
161
192
162
-
impl_join_tuple!(Join2 A B);
193
+
impl_join_tuple!(join2 Join2 A B);
194
+
impl_join_tuple!(join3 Join3 A B C);
195
+
impl_join_tuple!(join4 Join4 A B C D);
196
+
impl_join_tuple!(join5 Join5 A B C D E);
197
+
impl_join_tuple!(join6 Join6 A B C D E F);
198
+
impl_join_tuple!(join7 Join7 A B C D E F G);
199
+
impl_join_tuple!(join8 Join8 A B C D E F G H);
200
+
impl_join_tuple!(join9 Join9 A B C D E F G H I);
201
+
impl_join_tuple!(join10 Join10 A B C D E F G H I J);
202
+
impl_join_tuple!(join11 Join11 A B C D E F G H I J K);
203
+
impl_join_tuple!(join12 Join12 A B C D E F G H I J K L);