@@ -4,6 +4,7 @@ use crate::cell::UnsafeCell;
4
4
use crate :: future:: { poll_fn, Future } ;
5
5
use crate :: pin:: Pin ;
6
6
use crate :: task:: Poll ;
7
+
7
8
/// Polls multiple futures simultaneously, returning a tuple
8
9
/// of all results once complete.
9
10
///
@@ -53,95 +54,78 @@ pub macro join {
53
54
@count : ( $( $count: tt) * ) ,
54
55
// Futures and their positions in the tuple: "{ a => (_), b => (_ _)) }"
55
56
@futures : { $( $fut: tt) * } ,
56
- // The future currently being expanded, and the rest
57
+ // Take a future from @rest to expand
57
58
@rest : ( $current: expr, $( $rest: tt) * )
58
59
) => {
59
60
join ! {
60
- @count: ( $( $count) * _) , // Add to the count
61
- @futures: { $( $fut) * $current => ( $( $count) * ) , } , // Add the future from @rest with it's position
62
- @rest: ( $( $rest) * ) // And leave the rest
61
+ @count: ( $( $count) * _) ,
62
+ @futures: { $( $fut) * $current => ( $( $count) * ) , } ,
63
+ @rest: ( $( $rest) * )
63
64
}
64
65
} ,
65
66
// Now generate the output future
66
67
(
67
68
@count: ( $( $count: tt) * ) ,
68
69
@futures : {
69
- $( $fut: expr => ( $( $pos: tt) * ) , ) *
70
+ $( $( @$f : tt ) ? $ fut: expr => ( $( $pos: tt) * ) , ) *
70
71
} ,
71
72
@rest : ( )
72
73
) => { {
73
- let mut futures = ( $( MaybeDone :: Future ( $fut) , ) * ) ;
74
+ // The futures and whether they have completed
75
+ let mut state = ( $( UnsafeCell :: new ( ( $fut, false ) ) , ) * ) ;
76
+
77
+ // Make sure the futures don't panic
78
+ // if polled after completion, and
79
+ // store their output separately
80
+ let mut futures = ( $(
81
+ ( {
82
+ let ( $( $pos, ) * state, .. ) = & state;
83
+
84
+ poll_fn ( move |cx| {
85
+ // SAFETY: each future borrows a distinct element
86
+ // of the tuple
87
+ let ( fut, done) = unsafe { & mut * state. get ( ) } ;
88
+
89
+ if * done {
90
+ return Poll :: Ready ( None )
91
+ }
92
+
93
+ // SAFETY: The futures are never moved
94
+ match unsafe { Pin :: new_unchecked ( fut) . poll ( cx) } {
95
+ Poll :: Ready ( val) => {
96
+ * done = true ;
97
+ Poll :: Ready ( Some ( val) )
98
+ }
99
+ Poll :: Pending => Poll :: Pending
100
+ }
101
+ } )
102
+ } , None ) ,
103
+ ) * ) ;
74
104
75
105
poll_fn ( move |cx| {
76
106
let mut done = true ;
77
107
78
108
$(
79
- // Extract the future from the tuple
80
- let ( $( $pos, ) * fut, .. ) = & mut futures;
109
+ let ( $( $pos, ) * ( fut, out) , .. ) = & mut futures;
81
110
82
- // SAFETY: the futures are never moved
83
- done &= unsafe { Pin :: new_unchecked ( fut) . poll ( cx) . is_ready ( ) } ;
111
+ // SAFETY: The futures are never moved
112
+ match unsafe { Pin :: new_unchecked ( fut) . poll ( cx) } {
113
+ Poll :: Ready ( Some ( val) ) => * out = Some ( val) ,
114
+ // the future was already done
115
+ Poll :: Ready ( None ) => { } ,
116
+ Poll :: Pending => done = false ,
117
+ }
84
118
) *
85
119
86
120
if done {
121
+ // Extract all the outputs
87
122
Poll :: Ready ( ( $( {
88
- let ( $( $pos, ) * fut, .. ) = & mut futures;
89
-
90
- // SAFETY: the futures are never moved
91
- unsafe { Pin :: new_unchecked ( fut) . take_output ( ) . unwrap ( ) }
123
+ let ( $( $pos, ) * ( _, val) , .. ) = & mut futures;
124
+ val. unwrap ( )
92
125
} ) , * ) )
93
126
} else {
94
127
Poll :: Pending
95
128
}
96
129
} ) . await
97
130
} }
98
131
}
99
-
100
- /// Future used by `join!` that stores it's output to
101
- /// be later taken and doesn' t panic when polled after ready.
102
- #[ allow ( dead_code) ]
103
- #[ unstable( feature = "future_join" , issue = "none" ) ]
104
- enum MaybeDone < F : Future > {
105
- Future ( F ) ,
106
- Done ( F :: Output ) ,
107
- Took ,
108
- }
109
-
110
- #[ unstable( feature = "future_join" , issue = "none" ) ]
111
- impl < F : Future + Unpin > Unpin for MaybeDone < F > { }
112
-
113
- #[ unstable( feature = "future_join" , issue = "none" ) ]
114
- impl < F : Future > MaybeDone < F > {
115
- #[ allow( dead_code) ]
116
- fn take_output ( self : Pin < & mut Self > ) -> Option < F :: Output > {
117
- unsafe {
118
- match & * self {
119
- MaybeDone :: Done ( _) => match mem:: replace ( self . get_unchecked_mut ( ) , Self :: Took ) {
120
- MaybeDone :: Done ( val) => Some ( val) ,
121
- _ => unreachable ! ( ) ,
122
- } ,
123
- _ => None ,
124
- }
125
- }
126
- }
127
- }
128
-
129
- #[ unstable( feature = "future_join" , issue = "none" ) ]
130
- impl < F : Future > Future for MaybeDone < F > {
131
- type Output = ( ) ;
132
-
133
- fn poll ( mut self : Pin < & mut Self > , cx : & mut Context < ' _ > ) -> Poll < Self :: Output > {
134
- unsafe {
135
- match self . as_mut ( ) . get_unchecked_mut ( ) {
136
- MaybeDone :: Future ( f) => match Pin :: new_unchecked ( f) . poll ( cx) {
137
- Poll :: Ready ( val) => self . set ( Self :: Done ( val) ) ,
138
- Poll :: Pending => return Poll :: Pending ,
139
- } ,
140
- MaybeDone :: Done ( _) => { }
141
- MaybeDone :: Took => unreachable ! ( ) ,
142
- }
143
- }
144
-
145
- Poll :: Ready ( ( ) )
146
- }
147
- }
0 commit comments