@@ -75,26 +75,53 @@ 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,
8397 /// we keep a manual vtable that serves pointers to Poll::poll and Drop::drop. These are
8498 /// generated and filled in by `StackFuture::from`.
8599 ///
86100 /// This field stores a pointer to the poll function wrapper.
87- poll_fn : fn ( this : Pin < & mut Self > , cx : & mut Context < ' _ > ) -> Poll < T > ,
101+ ///
102+ /// SAFETY:
103+ /// * the argument `this` must be the same instance of this type that `poll_fn` was obtained from.
104+ poll_fn : unsafe fn ( this : Pin < & mut Self > , cx : & mut Context < ' _ > ) -> Poll < T > ,
88105 /// Stores a pointer to the drop function wrapper
89106 ///
90107 /// See the documentation on `poll_fn` for more details.
91- drop_fn : fn ( this : & mut Self ) ,
108+ ///
109+ /// SAFETY:
110+ /// * the argument `this` must be the same instance of this type that `drop_fn` was obtained from.
111+ /// * must only be called from the Drop impl of this type.
112+ drop_fn : unsafe fn ( this : & mut Self ) ,
92113 /// StackFuture can be used similarly to a `dyn Future`. We keep a PhantomData
93114 /// here so the type system knows this.
94- _phantom : PhantomData < dyn Future < Output = T > + Send + ' a > ,
115+ _phantom : PhantomData < dyn Future < Output = T > + ' a > ,
95116}
96117
97- impl < ' a , T , const STACK_SIZE : usize > StackFuture < ' a , T , { STACK_SIZE } > {
118+ // SAFETY:
119+ // We ensure by the API exposed for this type that the contained future will always be Send
120+ // as long as the `SEND` const generic arg is true.
121+ unsafe impl < ' a , T , const STACK_SIZE : usize > Send for StackFutureImpl < ' a , T , STACK_SIZE , true >
122+ { }
123+
124+ impl < ' a , T , const STACK_SIZE : usize > StackFutureImpl < ' a , T , { STACK_SIZE } , true > {
98125 /// Creates a `StackFuture` from an existing future
99126 ///
100127 /// See the documentation on [`StackFuture`] for examples of how to use this.
@@ -135,13 +162,88 @@ impl<'a, T, const STACK_SIZE: usize> StackFuture<'a, T, { STACK_SIZE }> {
135162 /// ```
136163 pub fn from < F > ( future : F ) -> Self
137164 where
138- F : Future < Output = T > + Send + ' a , // the bounds here should match those in the _phantom field
165+ F : Future < Output = T > + Send + ' a ,
166+ {
167+ Self :: from_inner ( future)
168+ }
169+
170+ /// Attempts to create a `StackFuture` from an existing future
171+ ///
172+ /// If the `StackFuture` is not large enough to hold `future`, this function returns an
173+ /// `Err` with the argument `future` returned to you.
174+ ///
175+ /// Panics
176+ ///
177+ /// If we cannot satisfy the alignment requirements for `F`, this function will panic.
178+ pub fn try_from < F > ( future : F ) -> Result < Self , IntoStackFutureError < F > >
179+ where
180+ F : Future < Output = T > + Send + ' a ,
181+ {
182+ Self :: try_from_inner ( future)
183+ }
184+
185+ /// Creates a StackFuture from the given future, boxing if necessary
186+ ///
187+ /// This version will succeed even if the future is larger than `STACK_SIZE`. If the future
188+ /// is too large, `from_or_box` will allocate a `Box` on the heap and store the resulting
189+ /// boxed future in the `StackFuture`.
190+ ///
191+ /// The same thing also happens if the wrapped future's alignment is larger than StackFuture's
192+ /// alignment.
193+ ///
194+ /// This function requires the "alloc" crate feature.
195+ #[ cfg( feature = "alloc" ) ]
196+ pub fn from_or_box < F > ( future : F ) -> Self
197+ where
198+ F : Future < Output = T > + Send + ' a ,
199+ {
200+ Self :: from_or_box_inner ( future)
201+ }
202+ }
203+
204+ impl < ' a , T , const STACK_SIZE : usize > StackFutureImpl < ' a , T , STACK_SIZE , false > {
205+ /// Creates a `StackFuture` from an existing future.
206+ ///
207+ /// See the documentation of [`StackFuture::from`] for more details.
208+ pub fn from < F > ( future : F ) -> Self
209+ where
210+ F : Future < Output = T > + ' a , // the bounds here should match those in the _phantom field
211+ {
212+ Self :: from_inner ( future)
213+ }
214+
215+ /// Attempts to create a `StackFuture` from an existing future.
216+ ///
217+ /// See the documentation of [`StackFuture::try_from`] for more details.
218+ pub fn try_from < F > ( future : F ) -> Result < Self , IntoStackFutureError < F > >
219+ where
220+ F : Future < Output = T > + ' a , // the bounds here should match those in the _phantom field
221+ {
222+ Self :: try_from_inner ( future)
223+ }
224+
225+ /// Creates a StackFuture from the given future, boxing if necessary
226+ ///
227+ /// See the documentation of [`StackFuture::from_or_box`] for more details.
228+ #[ cfg( feature = "alloc" ) ]
229+ pub fn from_or_box < F > ( future : F ) -> Self
230+ where
231+ F : Future < Output = T > + ' a , // the bounds here should match those in the _phantom field
232+ {
233+ Self :: from_or_box_inner ( future)
234+ }
235+ }
236+
237+ impl < ' a , T , const STACK_SIZE : usize , const SEND : bool > StackFutureImpl < ' a , T , STACK_SIZE , SEND > {
238+ fn from_inner < F > ( future : F ) -> Self
239+ where
240+ F : Future < Output = T > + ' a , // the bounds here should match those in the _phantom field
139241 {
140242 // Ideally we would provide this as:
141243 //
142244 // impl<'a, F, const STACK_SIZE: usize> From<F> for StackFuture<'a, F::Output, { STACK_SIZE }>
143245 // where
144- // F: Future + Send + 'a
246+ // F: Future + 'a
145247 //
146248 // However, libcore provides a blanket `impl<T> From<T> for T`, and since `StackFuture: Future`,
147249 // both impls end up being applicable to do `From<StackFuture> for StackFuture`.
@@ -150,25 +252,26 @@ impl<'a, T, const STACK_SIZE: usize> StackFuture<'a, T, { STACK_SIZE }> {
150252 #[ allow( clippy:: let_unit_value) ]
151253 let _ = AssertFits :: < F , STACK_SIZE > :: ASSERT ;
152254
153- Self :: try_from ( future) . unwrap ( )
255+ Self :: try_from_inner ( future) . unwrap ( )
154256 }
155257
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 > >
258+ fn try_from_inner < F > ( future : F ) -> Result < Self , IntoStackFutureError < F > >
165259 where
166- F : Future < Output = T > + Send + ' a , // the bounds here should match those in the _phantom field
260+ F : Future < Output = T > + ' a , // the bounds here should match those in the _phantom field
167261 {
168262 if Self :: has_space_for_val ( & future) && Self :: has_alignment_for_val ( & future) {
169- let mut result = StackFuture {
263+ let mut result = Self {
170264 data : [ MaybeUninit :: uninit ( ) ; STACK_SIZE ] ,
265+ // SAFETY:
266+ // `poll_inner` and `drop_inner` both require `F` to match the future type
267+ // used to construct `self` here. The invariants on the `poll_fn` and `drop_fn`
268+ // fields require that they are only called using the original instance they were
269+ // obtained from, which ensures that `F` will still match at the point
270+ // they are called.
171271 poll_fn : Self :: poll_inner :: < F > ,
272+ // SAFETY:
273+ // the invariants on `drop_fn` transitively uphold the requirement that `drop_inner`
274+ // is only called from the Drop impl of this type.
172275 drop_fn : Self :: drop_inner :: < F > ,
173276 _phantom : PhantomData ,
174277 } ;
@@ -192,34 +295,35 @@ impl<'a, T, const STACK_SIZE: usize> StackFuture<'a, T, { STACK_SIZE }> {
192295 }
193296 }
194297
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.
205298 #[ cfg( feature = "alloc" ) ]
206- pub fn from_or_box < F > ( future : F ) -> Self
299+ fn from_or_box_inner < F > ( future : F ) -> Self
207300 where
208- F : Future < Output = T > + Send + ' a , // the bounds here should match those in the _phantom field
301+ F : Future < Output = T > + ' a , // the bounds here should match those in the _phantom field
209302 {
210- Self :: try_from ( future) . unwrap_or_else ( |err| Self :: from ( Box :: pin ( err. into_inner ( ) ) ) )
303+ Self :: try_from_inner ( future) . unwrap_or_else ( |err| Self :: from_inner ( Box :: pin ( err. into_inner ( ) ) ) )
211304 }
212305
213306 /// A wrapper around the inner future's poll function, which we store in the poll_fn field
214307 /// of this struct.
215- fn poll_inner < F : Future > ( self : Pin < & mut Self > , cx : & mut Context < ' _ > ) -> Poll < F :: Output > {
216- self . as_pin_mut_ref :: < F > ( ) . poll ( cx)
308+ ///
309+ /// SAFETY:
310+ /// * the generic argument `F` must be the exact same type originally used to construct
311+ /// this instance via `try_from_inner`.
312+ unsafe fn poll_inner < F : Future > ( self : Pin < & mut Self > , cx : & mut Context < ' _ > ) -> Poll < F :: Output > {
313+ unsafe { self . as_pin_mut_ref :: < F > ( ) } . poll ( cx)
217314 }
218315
219316 /// A wrapper around the inner future's drop function, which we store in the drop_fn field
220317 /// of this struct.
221- fn drop_inner < F > ( & mut self ) {
222- // SAFETY: *this.as_mut_ptr() was previously written as type F
318+ ///
319+ /// SAFETY:
320+ /// * the generic argument `F` must be the exact same type originally used to construct
321+ /// this instance via `try_from_inner`.
322+ /// * must only be called from the drop impl of this type.
323+ unsafe fn drop_inner < F > ( & mut self ) {
324+ // SAFETY:
325+ // * this.as_mut_ptr() was previously written as type F
326+ // * caller ensures this will only be called from the drop impl of this type.
223327 unsafe { ptr:: drop_in_place ( self . as_mut_ptr :: < F > ( ) ) }
224328 }
225329
@@ -236,8 +340,12 @@ impl<'a, T, const STACK_SIZE: usize> StackFuture<'a, T, { STACK_SIZE }> {
236340 }
237341
238342 /// Returns a pinned mutable reference to a type F stored in self.data
239- fn as_pin_mut_ref < F > ( self : Pin < & mut Self > ) -> Pin < & mut F > {
240- // SAFETY: `StackFuture` is only created by `StackFuture::from`, which
343+ ///
344+ /// SAFETY:
345+ /// * the generic argument `F` must be the exact same type originally used to construct
346+ /// this instance via `try_from_inner`.
347+ unsafe fn as_pin_mut_ref < F > ( self : Pin < & mut Self > ) -> Pin < & mut F > {
348+ // SAFETY: `StackFuture` is only created by `StackFuture::try_from_inner`, which
241349 // writes an `F` to `self.as_mut_ptr(), so it's okay to cast the `*mut F`
242350 // to an `&mut F` with the same lifetime as `self`.
243351 //
@@ -277,26 +385,27 @@ impl<'a, T, const STACK_SIZE: usize> StackFuture<'a, T, { STACK_SIZE }> {
277385 }
278386}
279387
280- impl < ' a , T , const STACK_SIZE : usize > Future for StackFuture < ' a , T , { STACK_SIZE } > {
388+ impl < ' a , T , const STACK_SIZE : usize , const SEND : bool > Future for StackFutureImpl < ' a , T , { STACK_SIZE } , SEND > {
281389 type Output = T ;
282390
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- }
391+ fn poll ( self : Pin < & mut Self > , cx : & mut Context ) -> Poll < Self :: Output > {
392+ // SAFETY:
393+ // `self.poll_fn`` is private and never reassigned, so this must be the same instance
394+ // that `poll_fn` was originally obtained from.
395+ unsafe { ( self . poll_fn ) ( self , cx) }
294396 }
295397}
296398
297- impl < ' a , T , const STACK_SIZE : usize > Drop for StackFuture < ' a , T , { STACK_SIZE } > {
399+ impl < ' a , T , const STACK_SIZE : usize , const SEND : bool > Drop for StackFutureImpl < ' a , T , { STACK_SIZE } , SEND > {
298400 fn drop ( & mut self ) {
299- ( self . drop_fn ) ( self ) ;
401+ // SAFETY:
402+ // * `self.drop_fn`` is private and never reassigned, so this must be the same instance
403+ // that `drop_fn` was originally obtained from.
404+ // * we are calling this from the drop impl of this type, which is the only valid place
405+ // to call `drop_fn`.
406+ unsafe {
407+ ( self . drop_fn ) ( self ) ;
408+ }
300409 }
301410}
302411
0 commit comments