@@ -75,8 +75,22 @@ use alloc::boxed::Box;
7575/// it also respects any alignment requirements for the wrapped future. Note that the
7676/// wrapped future's alignment must be less than or equal to that of the overall
7777/// `StackFuture` struct.
78+ // NOTE: we use a type alias rather than a default const generic argument, as that would make methods
79+ // like StackFuture::new ambiguous when calling.
80+ pub type StackFuture < ' a , T , const STACK_SIZE : usize > = StackFutureImpl < ' a , T , STACK_SIZE , true > ;
81+
82+ /// A variant of [`StackFuture`] which allows for futures that do not implement the [`Send`] trait.
83+ ///
84+ /// See the documentation of `StackFuture` for more information.
85+ pub type LocalStackFuture < ' a , T , const STACK_SIZE : usize > = StackFutureImpl < ' a , T , STACK_SIZE , false > ;
86+
87+ /// A variant of [`StackFuture`] which supports either [`Send`] ofr non-`Send` futures, depending
88+ /// on the value of the `SEND` const generic argument.
89+ ///
90+ /// In most cases, you will want to use `StackFuture` or [`LocalStackFuture`] directly.
91+ /// See the documentation for [`StackFuture`] for more details.
7892#[ repr( C ) ] // Ensures the data first does not have any padding before it in the struct
79- pub struct StackFuture < ' a , T , const STACK_SIZE : usize > {
93+ pub struct StackFutureImpl < ' a , T , const STACK_SIZE : usize , const SEND : bool > {
8094 /// An array of bytes that is used to store the wrapped future.
8195 data : [ MaybeUninit < u8 > ; STACK_SIZE ] ,
8296 /// Since the type of `StackFuture` does not know the underlying future that it is wrapping,
@@ -88,13 +102,22 @@ pub struct StackFuture<'a, T, const STACK_SIZE: usize> {
88102 /// Stores a pointer to the drop function wrapper
89103 ///
90104 /// See the documentation on `poll_fn` for more details.
91- drop_fn : fn ( this : & mut Self ) ,
105+ ///
106+ /// SAFETY:
107+ /// Must only be called from within the Drop impl of this type.
108+ drop_fn : unsafe fn ( this : & mut Self ) ,
92109 /// StackFuture can be used similarly to a `dyn Future`. We keep a PhantomData
93110 /// here so the type system knows this.
94- _phantom : PhantomData < dyn Future < Output = T > + Send + ' a > ,
111+ _phantom : PhantomData < dyn Future < Output = T > + ' a > ,
95112}
96113
97- impl < ' a , T , const STACK_SIZE : usize > StackFuture < ' a , T , { STACK_SIZE } > {
114+ // SAFETY:
115+ // We ensure by the API exposed for this type that the contained future will always be Send
116+ // as long as the `SEND` const generic arg is true.
117+ unsafe impl < ' a , T , const STACK_SIZE : usize > Send for StackFutureImpl < ' a , T , STACK_SIZE , true >
118+ { }
119+
120+ impl < ' a , T , const STACK_SIZE : usize > StackFutureImpl < ' a , T , { STACK_SIZE } , true > {
98121 /// Creates a `StackFuture` from an existing future
99122 ///
100123 /// See the documentation on [`StackFuture`] for examples of how to use this.
@@ -135,13 +158,88 @@ impl<'a, T, const STACK_SIZE: usize> StackFuture<'a, T, { STACK_SIZE }> {
135158 /// ```
136159 pub fn from < F > ( future : F ) -> Self
137160 where
138- F : Future < Output = T > + Send + ' a , // the bounds here should match those in the _phantom field
161+ F : Future < Output = T > + Send + ' a ,
162+ {
163+ Self :: from_inner ( future)
164+ }
165+
166+ /// Attempts to create a `StackFuture` from an existing future
167+ ///
168+ /// If the `StackFuture` is not large enough to hold `future`, this function returns an
169+ /// `Err` with the argument `future` returned to you.
170+ ///
171+ /// Panics
172+ ///
173+ /// If we cannot satisfy the alignment requirements for `F`, this function will panic.
174+ pub fn try_from < F > ( future : F ) -> Result < Self , IntoStackFutureError < F > >
175+ where
176+ F : Future < Output = T > + Send + ' a ,
177+ {
178+ Self :: try_from_inner ( future)
179+ }
180+
181+ /// Creates a StackFuture from the given future, boxing if necessary
182+ ///
183+ /// This version will succeed even if the future is larger than `STACK_SIZE`. If the future
184+ /// is too large, `from_or_box` will allocate a `Box` on the heap and store the resulting
185+ /// boxed future in the `StackFuture`.
186+ ///
187+ /// The same thing also happens if the wrapped future's alignment is larger than StackFuture's
188+ /// alignment.
189+ ///
190+ /// This function requires the "alloc" crate feature.
191+ #[ cfg( feature = "alloc" ) ]
192+ pub fn from_or_box < F > ( future : F ) -> Self
193+ where
194+ F : Future < Output = T > + Send + ' a ,
195+ {
196+ Self :: from_or_box_inner ( future)
197+ }
198+ }
199+
200+ impl < ' a , T , const STACK_SIZE : usize > StackFutureImpl < ' a , T , STACK_SIZE , false > {
201+ /// Creates a `StackFuture` from an existing future.
202+ ///
203+ /// See the documentation of [`StackFuture::from`] for more details.
204+ pub fn from < F > ( future : F ) -> Self
205+ where
206+ F : Future < Output = T > + ' a , // the bounds here should match those in the _phantom field
207+ {
208+ Self :: from_inner ( future)
209+ }
210+
211+ /// Attempts to create a `StackFuture` from an existing future.
212+ ///
213+ /// See the documentation of [`StackFuture::try_from`] for more details.
214+ pub fn try_from < F > ( future : F ) -> Result < Self , IntoStackFutureError < F > >
215+ where
216+ F : Future < Output = T > + ' a , // the bounds here should match those in the _phantom field
217+ {
218+ Self :: try_from_inner ( future)
219+ }
220+
221+ /// Creates a StackFuture from the given future, boxing if necessary
222+ ///
223+ /// See the documentation of [`StackFuture::from_or_box`] for more details.
224+ #[ cfg( feature = "alloc" ) ]
225+ pub fn from_or_box < F > ( future : F ) -> Self
226+ where
227+ F : Future < Output = T > + ' a , // the bounds here should match those in the _phantom field
228+ {
229+ Self :: from_or_box_inner ( future)
230+ }
231+ }
232+
233+ impl < ' a , T , const STACK_SIZE : usize , const SEND : bool > StackFutureImpl < ' a , T , STACK_SIZE , SEND > {
234+ fn from_inner < F > ( future : F ) -> Self
235+ where
236+ F : Future < Output = T > + ' a , // the bounds here should match those in the _phantom field
139237 {
140238 // Ideally we would provide this as:
141239 //
142240 // impl<'a, F, const STACK_SIZE: usize> From<F> for StackFuture<'a, F::Output, { STACK_SIZE }>
143241 // where
144- // F: Future + Send + 'a
242+ // F: Future + 'a
145243 //
146244 // However, libcore provides a blanket `impl<T> From<T> for T`, and since `StackFuture: Future`,
147245 // both impls end up being applicable to do `From<StackFuture> for StackFuture`.
@@ -150,23 +248,15 @@ impl<'a, T, const STACK_SIZE: usize> StackFuture<'a, T, { STACK_SIZE }> {
150248 #[ allow( clippy:: let_unit_value) ]
151249 let _ = AssertFits :: < F , STACK_SIZE > :: ASSERT ;
152250
153- Self :: try_from ( future) . unwrap ( )
251+ Self :: try_from_inner ( future) . unwrap ( )
154252 }
155253
156- /// Attempts to create a `StackFuture` from an existing future
157- ///
158- /// If the `StackFuture` is not large enough to hold `future`, this function returns an
159- /// `Err` with the argument `future` returned to you.
160- ///
161- /// Panics
162- ///
163- /// If we cannot satisfy the alignment requirements for `F`, this function will panic.
164- pub fn try_from < F > ( future : F ) -> Result < Self , IntoStackFutureError < F > >
254+ fn try_from_inner < F > ( future : F ) -> Result < Self , IntoStackFutureError < F > >
165255 where
166- F : Future < Output = T > + Send + ' a , // the bounds here should match those in the _phantom field
256+ F : Future < Output = T > + ' a , // the bounds here should match those in the _phantom field
167257 {
168258 if Self :: has_space_for_val ( & future) && Self :: has_alignment_for_val ( & future) {
169- let mut result = StackFuture {
259+ let mut result = Self {
170260 data : [ MaybeUninit :: uninit ( ) ; STACK_SIZE ] ,
171261 poll_fn : Self :: poll_inner :: < F > ,
172262 drop_fn : Self :: drop_inner :: < F > ,
@@ -192,22 +282,12 @@ impl<'a, T, const STACK_SIZE: usize> StackFuture<'a, T, { STACK_SIZE }> {
192282 }
193283 }
194284
195- /// Creates a StackFuture from the given future, boxing if necessary
196- ///
197- /// This version will succeed even if the future is larger than `STACK_SIZE`. If the future
198- /// is too large, `from_or_box` will allocate a `Box` on the heap and store the resulting
199- /// boxed future in the `StackFuture`.
200- ///
201- /// The same thing also happens if the wrapped future's alignment is larger than StackFuture's
202- /// alignment.
203- ///
204- /// This function requires the "alloc" crate feature.
205285 #[ cfg( feature = "alloc" ) ]
206- pub fn from_or_box < F > ( future : F ) -> Self
286+ fn from_or_box_inner < F > ( future : F ) -> Self
207287 where
208- F : Future < Output = T > + Send + ' a , // the bounds here should match those in the _phantom field
288+ F : Future < Output = T > + ' a , // the bounds here should match those in the _phantom field
209289 {
210- Self :: try_from ( future) . unwrap_or_else ( |err| Self :: from ( Box :: pin ( err. into_inner ( ) ) ) )
290+ Self :: try_from_inner ( future) . unwrap_or_else ( |err| Self :: from_inner ( Box :: pin ( err. into_inner ( ) ) ) )
211291 }
212292
213293 /// A wrapper around the inner future's poll function, which we store in the poll_fn field
@@ -218,8 +298,13 @@ impl<'a, T, const STACK_SIZE: usize> StackFuture<'a, T, { STACK_SIZE }> {
218298
219299 /// A wrapper around the inner future's drop function, which we store in the drop_fn field
220300 /// of this struct.
221- fn drop_inner < F > ( & mut self ) {
222- // SAFETY: *this.as_mut_ptr() was previously written as type F
301+ ///
302+ /// SAFETY:
303+ /// Must only be called from the drop impl of this type.
304+ unsafe fn drop_inner < F > ( & mut self ) {
305+ // SAFETY:
306+ // * this.as_mut_ptr() was previously written as type F
307+ // * caller ensures this will only be called from the drop impl of this type.
223308 unsafe { ptr:: drop_in_place ( self . as_mut_ptr :: < F > ( ) ) }
224309 }
225310
@@ -277,48 +362,43 @@ impl<'a, T, const STACK_SIZE: usize> StackFuture<'a, T, { STACK_SIZE }> {
277362 }
278363}
279364
280- impl < ' a , T , const STACK_SIZE : usize > Future for StackFuture < ' a , T , { STACK_SIZE } > {
365+ impl < ' a , T , const STACK_SIZE : usize , const SEND : bool > Future for StackFutureImpl < ' a , T , { STACK_SIZE } , SEND > {
281366 type Output = T ;
282367
283- fn poll ( self : Pin < & mut Self > , cx : & mut Context < ' _ > ) -> Poll < Self :: Output > {
284- // SAFETY: This is doing pin projection. We unpin self so we can
285- // access self.poll_fn, and then re-pin self to pass it into poll_in.
286- // The part of the struct that needs to be pinned is data, since it
287- // contains a potentially self-referential future object, but since we
288- // do not touch that while self is unpinned and we do not move self
289- // while unpinned we are okay.
290- unsafe {
291- let this = self . get_unchecked_mut ( ) ;
292- ( this. poll_fn ) ( Pin :: new_unchecked ( this) , cx)
293- }
368+ fn poll ( self : Pin < & mut Self > , cx : & mut Context ) -> Poll < Self :: Output > {
369+ ( self . poll_fn ) ( self , cx)
294370 }
295371}
296372
297- impl < ' a , T , const STACK_SIZE : usize > Drop for StackFuture < ' a , T , { STACK_SIZE } > {
373+ impl < ' a , T , const STACK_SIZE : usize , const SEND : bool > Drop for StackFutureImpl < ' a , T , { STACK_SIZE } , SEND > {
298374 fn drop ( & mut self ) {
299- ( self . drop_fn ) ( self ) ;
375+ // SAFETY: we are calling this from the drop impl of this type,
376+ // which is the only valid place to call `drop_fn`.
377+ unsafe {
378+ ( self . drop_fn ) ( self ) ;
379+ }
300380 }
301381}
302382
303383struct AssertFits < F , const STACK_SIZE : usize > ( PhantomData < F > ) ;
304384
305385impl < F , const STACK_SIZE : usize > AssertFits < F , STACK_SIZE > {
306386 const ASSERT : ( ) = {
307- if !StackFuture :: < F , STACK_SIZE > :: has_space_for :: < F > ( ) {
387+ if !StackFutureImpl :: < F , STACK_SIZE , false > :: has_space_for :: < F > ( ) {
308388 concat_panic ! (
309389 "Future is too large: " ,
310- StackFuture :: <F , STACK_SIZE >:: required_space:: <F >( ) ,
390+ StackFutureImpl :: <F , STACK_SIZE , false >:: required_space:: <F >( ) ,
311391 " > " ,
312392 STACK_SIZE
313393 ) ;
314394 }
315395
316- if !StackFuture :: < F , STACK_SIZE > :: has_alignment_for :: < F > ( ) {
396+ if !StackFutureImpl :: < F , STACK_SIZE , false > :: has_alignment_for :: < F > ( ) {
317397 concat_panic ! (
318398 "Future has incompatible alignment: " ,
319399 align_of:: <F >( ) ,
320400 " > " ,
321- align_of:: <StackFuture :: <F , STACK_SIZE >>( )
401+ align_of:: <StackFutureImpl :: <F , STACK_SIZE , false >>( )
322402 ) ;
323403 }
324404 } ;
0 commit comments