@@ -105,6 +105,12 @@ enum MaybeDone<F: Future> {
105105 Taken , // Output has been taken
106106}
107107
108+ // MaybeDone<F> stores F::Output, which the compiler can't prove
109+ // is Unpin even when F: Unpin. Since we only use Join with Unpin
110+ // futures and never pin-project into fields, implementing Unpin
111+ // by hand is safe and lets us call self.get_mut() in poll().
112+ impl <A : Future + Unpin , B : Future + Unpin > Unpin for Join <A , B > {}
113+
108114impl <A , B > Join <A , B >
109115where
110116 A : Future ,
@@ -125,30 +131,32 @@ where
125131{
126132 type Output = (A :: Output , B :: Output );
127133
128- fn poll (mut self : Pin <& mut Self >, cx : & mut Context <'_ >) -> Poll <Self :: Output > {
134+ fn poll (self : Pin <& mut Self >, cx : & mut Context <'_ >) -> Poll <Self :: Output > {
135+ let this = self . get_mut ();
136+
129137 // Poll A if not done
130- if let MaybeDone :: Pending (ref mut fut ) = self . a {
138+ if let MaybeDone :: Pending (ref mut fut ) = this . a {
131139 if let Poll :: Ready (val ) = Pin :: new (fut ). poll (cx ) {
132- self . a = MaybeDone :: Done (val );
140+ this . a = MaybeDone :: Done (val );
133141 }
134142 }
135143
136144 // Poll B if not done
137- if let MaybeDone :: Pending (ref mut fut ) = self . b {
145+ if let MaybeDone :: Pending (ref mut fut ) = this . b {
138146 if let Poll :: Ready (val ) = Pin :: new (fut ). poll (cx ) {
139- self . b = MaybeDone :: Done (val );
147+ this . b = MaybeDone :: Done (val );
140148 }
141149 }
142150
143151 // Both done?
144- match (& self . a, & self . b) {
152+ match (& this . a, & this . b) {
145153 (MaybeDone :: Done (_ ), MaybeDone :: Done (_ )) => {
146154 // Take both outputs
147- let a_val = match std :: mem :: replace (& mut self . a, MaybeDone :: Taken ) {
155+ let a_val = match std :: mem :: replace (& mut this . a, MaybeDone :: Taken ) {
148156 MaybeDone :: Done (v ) => v ,
149157 _ => unreachable! (),
150158 };
151- let b_val = match std :: mem :: replace (& mut self . b, MaybeDone :: Taken ) {
159+ let b_val = match std :: mem :: replace (& mut this . b, MaybeDone :: Taken ) {
152160 MaybeDone :: Done (v ) => v ,
153161 _ => unreachable! (),
154162 };
@@ -159,10 +167,10 @@ where
159167 }
160168}
161169
162- // Usage:
170+ // Usage (async blocks are !Unpin, so wrap them with Box::pin) :
163171// let (page1, page2) = Join::new(
164- // http_get("https://example.com/a"),
165- // http_get("https://example.com/b"),
172+ // Box::pin( http_get("https://example.com/a") ),
173+ // Box::pin( http_get("https://example.com/b") ),
166174// ).await;
167175// Both requests run concurrently!
168176```
0 commit comments