Skip to content

Commit b436178

Browse files
committed
Change FutureObj to use a *mut dyn Future fat pointer
1 parent 1341de8 commit b436178

File tree

4 files changed

+145
-69
lines changed

4 files changed

+145
-69
lines changed

futures-core/src/future/future_obj.rs

+140-64
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use core::{
2+
mem,
23
fmt,
34
future::Future,
45
marker::PhantomData,
@@ -13,22 +14,32 @@ use core::{
1314
/// take `dyn Trait` by value and `Box<dyn Trait>` is not available in no_std
1415
/// contexts.
1516
pub struct LocalFutureObj<'a, T> {
16-
ptr: *mut (),
17-
poll_fn: unsafe fn(*mut (), &mut Context<'_>) -> Poll<T>,
18-
drop_fn: unsafe fn(*mut ()),
17+
future: *mut (dyn Future<Output = T> + 'static),
18+
drop_fn: unsafe fn(*mut (dyn Future<Output = T> + 'static)),
1919
_marker: PhantomData<&'a ()>,
2020
}
2121

2222
impl<T> Unpin for LocalFutureObj<'_, T> {}
2323

24+
unsafe fn remove_future_lifetime<'a, T>(ptr: *mut (dyn Future<Output = T> + 'a))
25+
-> *mut (dyn Future<Output = T> + 'static)
26+
{
27+
mem::transmute(ptr)
28+
}
29+
30+
unsafe fn remove_drop_lifetime<'a, T>(ptr: unsafe fn (*mut (dyn Future<Output = T> + 'a)))
31+
-> unsafe fn(*mut (dyn Future<Output = T> + 'static))
32+
{
33+
mem::transmute(ptr)
34+
}
35+
2436
impl<'a, T> LocalFutureObj<'a, T> {
2537
/// Create a `LocalFutureObj` from a custom trait object representation.
2638
#[inline]
2739
pub fn new<F: UnsafeFutureObj<'a, T> + 'a>(f: F) -> LocalFutureObj<'a, T> {
2840
LocalFutureObj {
29-
ptr: f.into_raw(),
30-
poll_fn: F::poll,
31-
drop_fn: F::drop,
41+
future: unsafe { remove_future_lifetime(f.into_raw()) },
42+
drop_fn: unsafe { remove_drop_lifetime(F::drop) },
3243
_marker: PhantomData,
3344
}
3445
}
@@ -61,17 +72,17 @@ impl<T> Future for LocalFutureObj<'_, T> {
6172
type Output = T;
6273

6374
#[inline]
64-
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<T> {
75+
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<T> {
6576
unsafe {
66-
((*self).poll_fn)((*self).ptr, cx)
77+
Pin::new_unchecked(&mut *self.future).poll(cx)
6778
}
6879
}
6980
}
7081

7182
impl<T> Drop for LocalFutureObj<'_, T> {
7283
fn drop(&mut self) {
7384
unsafe {
74-
(self.drop_fn)(self.ptr)
85+
(self.drop_fn)(self.future)
7586
}
7687
}
7788
}
@@ -119,115 +130,168 @@ impl<T> Future for FutureObj<'_, T> {
119130
}
120131

121132
/// A custom implementation of a future trait object for `FutureObj`, providing
122-
/// a hand-rolled vtable.
133+
/// a vtable with drop support.
123134
///
124135
/// This custom representation is typically used only in `no_std` contexts,
125136
/// where the default `Box`-based implementation is not available.
126137
///
127-
/// The implementor must guarantee that it is safe to call `poll` repeatedly (in
128-
/// a non-concurrent fashion) with the result of `into_raw` until `drop` is
129-
/// called.
138+
/// # Safety
139+
///
140+
/// See the safety notes on individual methods for what guarantees an
141+
/// implementor must provide.
130142
pub unsafe trait UnsafeFutureObj<'a, T>: 'a {
131-
/// Convert an owned instance into a (conceptually owned) void pointer.
132-
fn into_raw(self) -> *mut ();
133-
134-
/// Poll the future represented by the given void pointer.
143+
/// Convert an owned instance into a (conceptually owned) fat pointer.
135144
///
136145
/// # Safety
137146
///
138-
/// The trait implementor must guarantee that it is safe to repeatedly call
139-
/// `poll` with the result of `into_raw` until `drop` is called; such calls
140-
/// are not, however, allowed to race with each other or with calls to
141-
/// `drop`.
142-
unsafe fn poll(ptr: *mut (), cx: &mut Context<'_>) -> Poll<T>;
147+
/// ## Implementor
148+
///
149+
/// The trait implementor must guarantee that it is safe to convert the
150+
/// provided `*mut (dyn Future<Output = T> + 'a)` into a `Pin<&mut (dyn
151+
/// Future<Output = T> + 'a)>` and call methods on it, non-reentrantly,
152+
/// until `UnsafeFutureObj::drop` is called with it.
153+
fn into_raw(self) -> *mut (dyn Future<Output = T> + 'a);
143154

144-
/// Drops the future represented by the given void pointer.
155+
/// Drops the future represented by the given fat pointer.
145156
///
146157
/// # Safety
147158
///
159+
/// ## Implementor
160+
///
148161
/// The trait implementor must guarantee that it is safe to call this
149-
/// function once per `into_raw` invocation; that call cannot race with
150-
/// other calls to `drop` or `poll`.
151-
unsafe fn drop(ptr: *mut ());
162+
/// function once per `into_raw` invocation.
163+
///
164+
/// ## Caller
165+
///
166+
/// The caller must ensure:
167+
///
168+
/// * the pointer passed was obtained from an `into_raw` invocation from
169+
/// this same trait object
170+
/// * the pointer is not currently in use as a `Pin<&mut (dyn Future<Output
171+
/// = T> + 'a)>`
172+
/// * the pointer must not be used again after this function is called
173+
unsafe fn drop(ptr: *mut (dyn Future<Output = T> + 'a));
152174
}
153175

154176
unsafe impl<'a, T, F> UnsafeFutureObj<'a, T> for &'a mut F
155177
where
156178
F: Future<Output = T> + Unpin + 'a
157179
{
158-
fn into_raw(self) -> *mut () {
159-
self as *mut F as *mut ()
180+
fn into_raw(self) -> *mut (dyn Future<Output = T> + 'a) {
181+
self as *mut dyn Future<Output = T>
160182
}
161183

162-
unsafe fn poll(ptr: *mut (), cx: &mut Context<'_>) -> Poll<T> {
163-
let p: Pin<&mut F> = Pin::new_unchecked(&mut *(ptr as *mut F));
164-
F::poll(p, cx)
184+
unsafe fn drop(_ptr: *mut (dyn Future<Output = T> + 'a)) {}
185+
}
186+
187+
unsafe impl<'a, T> UnsafeFutureObj<'a, T> for &'a mut (dyn Future<Output = T> + Unpin + 'a)
188+
{
189+
fn into_raw(self) -> *mut (dyn Future<Output = T> + 'a) {
190+
self as *mut dyn Future<Output = T>
165191
}
166192

167-
unsafe fn drop(_ptr: *mut ()) {}
193+
unsafe fn drop(_ptr: *mut (dyn Future<Output = T> + 'a)) {}
168194
}
169195

170196
unsafe impl<'a, T, F> UnsafeFutureObj<'a, T> for Pin<&'a mut F>
171197
where
172198
F: Future<Output = T> + 'a
173199
{
174-
fn into_raw(mut self) -> *mut () {
175-
let mut_ref: &mut F = unsafe { Pin::get_unchecked_mut(self.as_mut()) };
176-
mut_ref as *mut F as *mut ()
200+
fn into_raw(self) -> *mut (dyn Future<Output = T> + 'a) {
201+
unsafe { Pin::into_inner_unchecked(self) as *mut dyn Future<Output = T> }
177202
}
178203

179-
unsafe fn poll(ptr: *mut (), cx: &mut Context<'_>) -> Poll<T> {
180-
let future: Pin<&mut F> = Pin::new_unchecked(&mut *(ptr as *mut F));
181-
F::poll(future, cx)
204+
unsafe fn drop(_ptr: *mut (dyn Future<Output = T> + 'a)) {}
205+
}
206+
207+
unsafe impl<'a, T> UnsafeFutureObj<'a, T> for Pin<&'a mut (dyn Future<Output = T> + 'a)>
208+
{
209+
fn into_raw(self) -> *mut (dyn Future<Output = T> + 'a) {
210+
unsafe { Pin::into_inner_unchecked(self) as *mut dyn Future<Output = T> }
182211
}
183212

184-
unsafe fn drop(_ptr: *mut ()) {}
213+
unsafe fn drop(_ptr: *mut (dyn Future<Output = T> + 'a)) {}
185214
}
186215

187216
#[cfg(feature = "alloc")]
188217
mod if_alloc {
189218
use super::*;
190-
use core::mem;
191219
use alloc::boxed::Box;
192220

193221
unsafe impl<'a, T, F> UnsafeFutureObj<'a, T> for Box<F>
194222
where F: Future<Output = T> + 'a
195223
{
196-
fn into_raw(self) -> *mut () {
197-
Box::into_raw(self) as *mut ()
224+
fn into_raw(self) -> *mut (dyn Future<Output = T> + 'a) {
225+
Box::into_raw(self)
198226
}
199227

200-
unsafe fn poll(ptr: *mut (), cx: &mut Context<'_>) -> Poll<T> {
201-
let ptr = ptr as *mut F;
202-
let pin: Pin<&mut F> = Pin::new_unchecked(&mut *ptr);
203-
F::poll(pin, cx)
228+
unsafe fn drop(ptr: *mut (dyn Future<Output = T> + 'a)) {
229+
drop(Box::from_raw(ptr as *mut F))
204230
}
231+
}
205232

206-
unsafe fn drop(ptr: *mut ()) {
207-
drop(Box::from_raw(ptr as *mut F))
233+
unsafe impl<'a, T: 'a> UnsafeFutureObj<'a, T> for Box<dyn Future<Output = T> + 'a> {
234+
fn into_raw(self) -> *mut (dyn Future<Output = T> + 'a) {
235+
Box::into_raw(self)
236+
}
237+
238+
unsafe fn drop(ptr: *mut (dyn Future<Output = T> + 'a)) {
239+
drop(Box::from_raw(ptr))
240+
}
241+
}
242+
243+
unsafe impl<'a, T: 'a> UnsafeFutureObj<'a, T> for Box<dyn Future<Output = T> + Send + 'a> {
244+
fn into_raw(self) -> *mut (dyn Future<Output = T> + 'a) {
245+
Box::into_raw(self)
246+
}
247+
248+
unsafe fn drop(ptr: *mut (dyn Future<Output = T> + 'a)) {
249+
drop(Box::from_raw(ptr))
208250
}
209251
}
210252

211253
unsafe impl<'a, T, F> UnsafeFutureObj<'a, T> for Pin<Box<F>>
212254
where
213255
F: Future<Output = T> + 'a
214256
{
215-
fn into_raw(mut self) -> *mut () {
216-
let mut_ref: &mut F = unsafe { Pin::get_unchecked_mut(self.as_mut()) };
217-
let ptr = mut_ref as *mut F as *mut ();
218-
mem::forget(self); // Don't drop the box
219-
ptr
257+
fn into_raw(self) -> *mut (dyn Future<Output = T> + 'a) {
258+
Box::into_raw(unsafe { Pin::into_inner_unchecked(self) })
259+
}
260+
261+
unsafe fn drop(ptr: *mut (dyn Future<Output = T> + 'a)) {
262+
drop(Pin::from(Box::from_raw(ptr)))
263+
}
264+
}
265+
266+
unsafe impl<'a, T: 'a> UnsafeFutureObj<'a, T> for Pin<Box<dyn Future<Output = T> + 'a>> {
267+
fn into_raw(self) -> *mut (dyn Future<Output = T> + 'a) {
268+
Box::into_raw(unsafe { Pin::into_inner_unchecked(self) })
269+
}
270+
271+
unsafe fn drop(ptr: *mut (dyn Future<Output = T> + 'a)) {
272+
drop(Pin::from(Box::from_raw(ptr)))
273+
}
274+
}
275+
276+
unsafe impl<'a, T: 'a> UnsafeFutureObj<'a, T> for Pin<Box<dyn Future<Output = T> + Send + 'a>> {
277+
fn into_raw(self) -> *mut (dyn Future<Output = T> + 'a) {
278+
Box::into_raw(unsafe { Pin::into_inner_unchecked(self) })
220279
}
221280

222-
unsafe fn poll(ptr: *mut (), cx: &mut Context<'_>) -> Poll<T> {
223-
let ptr = ptr as *mut F;
224-
let pin: Pin<&mut F> = Pin::new_unchecked(&mut *ptr);
225-
F::poll(pin, cx)
281+
unsafe fn drop(ptr: *mut (dyn Future<Output = T> + 'a)) {
282+
drop(Pin::from(Box::from_raw(ptr)))
226283
}
284+
}
227285

228-
unsafe fn drop(ptr: *mut ()) {
229-
#[allow(clippy::cast_ptr_alignment)]
230-
drop(Pin::from(Box::from_raw(ptr as *mut F)));
286+
impl<'a, F: Future<Output = ()> + Send + 'a> From<Box<F>> for FutureObj<'a, ()> {
287+
fn from(boxed: Box<F>) -> Self {
288+
FutureObj::new(boxed)
289+
}
290+
}
291+
292+
impl<'a> From<Box<dyn Future<Output = ()> + Send + 'a>> for FutureObj<'a, ()> {
293+
fn from(boxed: Box<dyn Future<Output = ()> + Send + 'a>) -> Self {
294+
FutureObj::new(boxed)
231295
}
232296
}
233297

@@ -237,20 +301,32 @@ mod if_alloc {
237301
}
238302
}
239303

240-
impl<'a, F: Future<Output = ()> + Send + 'a> From<Box<F>> for FutureObj<'a, ()> {
241-
fn from(boxed: Box<F>) -> Self {
304+
impl<'a> From<Pin<Box<dyn Future<Output = ()> + Send + 'a>>> for FutureObj<'a, ()> {
305+
fn from(boxed: Pin<Box<dyn Future<Output = ()> + Send + 'a>>) -> Self {
242306
FutureObj::new(boxed)
243307
}
244308
}
245309

310+
impl<'a, F: Future<Output = ()> + 'a> From<Box<F>> for LocalFutureObj<'a, ()> {
311+
fn from(boxed: Box<F>) -> Self {
312+
LocalFutureObj::new(boxed)
313+
}
314+
}
315+
316+
impl<'a> From<Box<dyn Future<Output = ()> + 'a>> for LocalFutureObj<'a, ()> {
317+
fn from(boxed: Box<dyn Future<Output = ()> + 'a>) -> Self {
318+
LocalFutureObj::new(boxed)
319+
}
320+
}
321+
246322
impl<'a, F: Future<Output = ()> + 'a> From<Pin<Box<F>>> for LocalFutureObj<'a, ()> {
247323
fn from(boxed: Pin<Box<F>>) -> Self {
248324
LocalFutureObj::new(boxed)
249325
}
250326
}
251327

252-
impl<'a, F: Future<Output = ()> + 'a> From<Box<F>> for LocalFutureObj<'a, ()> {
253-
fn from(boxed: Box<F>) -> Self {
328+
impl<'a> From<Pin<Box<dyn Future<Output = ()> + 'a>>> for LocalFutureObj<'a, ()> {
329+
fn from(boxed: Pin<Box<dyn Future<Output = ()> + 'a>>) -> Self {
254330
LocalFutureObj::new(boxed)
255331
}
256332
}

futures-core/src/lib.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
//! Core traits and types for asynchronous operations in Rust.
22
3-
#![feature(futures_api)]
3+
#![feature(futures_api, pin_into_inner)]
44
#![cfg_attr(feature = "cfg-target-has-atomic", feature(cfg_target_has_atomic))]
55

66
#![cfg_attr(not(feature = "std"), no_std)]

futures-util/src/future/mod.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -493,8 +493,8 @@ pub trait FutureExt: Future {
493493

494494
/// Wrap the future in a Box, pinning it.
495495
#[cfg(feature = "alloc")]
496-
fn boxed(self) -> BoxFuture<'static, Self::Output>
497-
where Self: Sized + Send + 'static
496+
fn boxed<'a>(self) -> BoxFuture<'a, Self::Output>
497+
where Self: Sized + Send + 'a
498498
{
499499
Box::pin(self)
500500
}

futures/tests/future_obj.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use futures::task::{Context, Poll};
66

77
#[test]
88
fn dropping_does_not_segfault() {
9-
FutureObj::new(Box::new(async { String::new() }));
9+
FutureObj::new(async { String::new() }.boxed());
1010
}
1111

1212
#[test]
@@ -29,7 +29,7 @@ fn dropping_drops_the_future() {
2929
}
3030
}
3131

32-
FutureObj::new(Box::new(Inc(&mut times_dropped)));
32+
FutureObj::new(Inc(&mut times_dropped).boxed());
3333

3434
assert_eq!(times_dropped, 1);
3535
}

0 commit comments

Comments
 (0)