polish

Changed files
+49 -8
futures
src
combinators
+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);