Skip to content

Commit c8df60a

Browse files
committed
Auto merge of #51944 - MajorBreakfast:generic-future-obj, r=cramertj
Make custom trait object for `Future` generic - `TaskObj` -> `FutureObj<'static, ()>` - The `impl From<...> for FutureObj<'a, T>` impls are impossible because of the type parameter `T`. The impl has to live in libstd, but `FutureObj<'a, T>` is from libcore. Therefore `Into<FutureObj<'a, T>>` was implemented instead. Edit: This didn‘t compile without warnings. I am now using non-generic Form impls. See rust-lang/futures-rs#1058 r? @cramertj Edit: Added lifetime
2 parents 9363342 + e666c2b commit c8df60a

File tree

10 files changed

+266
-173
lines changed

10 files changed

+266
-173
lines changed

src/liballoc/boxed.rs

+39-18
Original file line numberDiff line numberDiff line change
@@ -58,16 +58,16 @@
5858
use core::any::Any;
5959
use core::borrow;
6060
use core::cmp::Ordering;
61+
use core::convert::From;
6162
use core::fmt;
62-
use core::future::Future;
63+
use core::future::{Future, FutureObj, LocalFutureObj, UnsafeFutureObj};
6364
use core::hash::{Hash, Hasher};
6465
use core::iter::FusedIterator;
6566
use core::marker::{Unpin, Unsize};
6667
use core::mem::{self, PinMut};
6768
use core::ops::{CoerceUnsized, Deref, DerefMut, Generator, GeneratorState};
6869
use core::ptr::{self, NonNull, Unique};
69-
use core::task::{Context, Poll, UnsafeTask, TaskObj, LocalTaskObj};
70-
use core::convert::From;
70+
use core::task::{Context, Poll};
7171

7272
use raw_vec::RawVec;
7373
use str::from_boxed_utf8_unchecked;
@@ -915,7 +915,7 @@ impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<PinBox<U>> for PinBox<T> {}
915915
impl<T: ?Sized> Unpin for PinBox<T> {}
916916

917917
#[unstable(feature = "futures_api", issue = "50547")]
918-
impl<'a, F: ?Sized + Future + Unpin> Future for Box<F> {
918+
impl<F: ?Sized + Future + Unpin> Future for Box<F> {
919919
type Output = F::Output;
920920

921921
fn poll(mut self: PinMut<Self>, cx: &mut Context) -> Poll<Self::Output> {
@@ -924,7 +924,7 @@ impl<'a, F: ?Sized + Future + Unpin> Future for Box<F> {
924924
}
925925

926926
#[unstable(feature = "futures_api", issue = "50547")]
927-
impl<'a, F: ?Sized + Future> Future for PinBox<F> {
927+
impl<F: ?Sized + Future> Future for PinBox<F> {
928928
type Output = F::Output;
929929

930930
fn poll(mut self: PinMut<Self>, cx: &mut Context) -> Poll<Self::Output> {
@@ -933,46 +933,67 @@ impl<'a, F: ?Sized + Future> Future for PinBox<F> {
933933
}
934934

935935
#[unstable(feature = "futures_api", issue = "50547")]
936-
unsafe impl<F: Future<Output = ()> + 'static> UnsafeTask for PinBox<F> {
936+
unsafe impl<'a, T, F> UnsafeFutureObj<'a, T> for Box<F>
937+
where F: Future<Output = T> + 'a
938+
{
939+
fn into_raw(self) -> *mut () {
940+
Box::into_raw(self) as *mut ()
941+
}
942+
943+
unsafe fn poll(ptr: *mut (), cx: &mut Context) -> Poll<T> {
944+
let ptr = ptr as *mut F;
945+
let pin: PinMut<F> = PinMut::new_unchecked(&mut *ptr);
946+
pin.poll(cx)
947+
}
948+
949+
unsafe fn drop(ptr: *mut ()) {
950+
drop(Box::from_raw(ptr as *mut F))
951+
}
952+
}
953+
954+
#[unstable(feature = "futures_api", issue = "50547")]
955+
unsafe impl<'a, T, F> UnsafeFutureObj<'a, T> for PinBox<F>
956+
where F: Future<Output = T> + 'a
957+
{
937958
fn into_raw(self) -> *mut () {
938959
PinBox::into_raw(self) as *mut ()
939960
}
940961

941-
unsafe fn poll(task: *mut (), cx: &mut Context) -> Poll<()> {
942-
let ptr = task as *mut F;
962+
unsafe fn poll(ptr: *mut (), cx: &mut Context) -> Poll<T> {
963+
let ptr = ptr as *mut F;
943964
let pin: PinMut<F> = PinMut::new_unchecked(&mut *ptr);
944965
pin.poll(cx)
945966
}
946967

947-
unsafe fn drop(task: *mut ()) {
948-
drop(PinBox::from_raw(task as *mut F))
968+
unsafe fn drop(ptr: *mut ()) {
969+
drop(PinBox::from_raw(ptr as *mut F))
949970
}
950971
}
951972

952973
#[unstable(feature = "futures_api", issue = "50547")]
953-
impl<F: Future<Output = ()> + Send + 'static> From<PinBox<F>> for TaskObj {
974+
impl<'a, F: Future<Output = ()> + Send + 'a> From<PinBox<F>> for FutureObj<'a, ()> {
954975
fn from(boxed: PinBox<F>) -> Self {
955-
TaskObj::new(boxed)
976+
FutureObj::new(boxed)
956977
}
957978
}
958979

959980
#[unstable(feature = "futures_api", issue = "50547")]
960-
impl<F: Future<Output = ()> + Send + 'static> From<Box<F>> for TaskObj {
981+
impl<'a, F: Future<Output = ()> + Send + 'a> From<Box<F>> for FutureObj<'a, ()> {
961982
fn from(boxed: Box<F>) -> Self {
962-
TaskObj::new(PinBox::from(boxed))
983+
FutureObj::new(boxed)
963984
}
964985
}
965986

966987
#[unstable(feature = "futures_api", issue = "50547")]
967-
impl<F: Future<Output = ()> + 'static> From<PinBox<F>> for LocalTaskObj {
988+
impl<'a, F: Future<Output = ()> + 'a> From<PinBox<F>> for LocalFutureObj<'a, ()> {
968989
fn from(boxed: PinBox<F>) -> Self {
969-
LocalTaskObj::new(boxed)
990+
LocalFutureObj::new(boxed)
970991
}
971992
}
972993

973994
#[unstable(feature = "futures_api", issue = "50547")]
974-
impl<F: Future<Output = ()> + 'static> From<Box<F>> for LocalTaskObj {
995+
impl<'a, F: Future<Output = ()> + 'a> From<Box<F>> for LocalFutureObj<'a, ()> {
975996
fn from(boxed: Box<F>) -> Self {
976-
LocalTaskObj::new(PinBox::from(boxed))
997+
LocalFutureObj::new(boxed)
977998
}
978999
}

src/libcore/future.rs src/libcore/future/future.rs

-2
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,6 @@
1212
reason = "futures in libcore are unstable",
1313
issue = "50547")]
1414

15-
//! Asynchronous values.
16-
1715
use mem::PinMut;
1816
use marker::Unpin;
1917
use task::{self, Poll};

src/libcore/future/future_obj.rs

+179
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,179 @@
1+
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
#![unstable(feature = "futures_api",
12+
reason = "futures in libcore are unstable",
13+
issue = "50547")]
14+
15+
use fmt;
16+
use future::Future;
17+
use marker::{PhantomData, Unpin};
18+
use mem::PinMut;
19+
use task::{Context, Poll};
20+
21+
/// A custom trait object for polling futures, roughly akin to
22+
/// `Box<dyn Future<Output = T> + 'a>`.
23+
///
24+
/// This custom trait object was introduced for two reasons:
25+
/// - Currently it is not possible to take `dyn Trait` by value and
26+
/// `Box<dyn Trait>` is not available in no_std contexts.
27+
/// - The `Future` trait is currently not object safe: The `Future::poll`
28+
/// method makes uses the arbitrary self types feature and traits in which
29+
/// this feature is used are currently not object safe due to current compiler
30+
/// limitations. (See tracking issue for arbitray self types for more
31+
/// information #44874)
32+
pub struct LocalFutureObj<'a, T> {
33+
ptr: *mut (),
34+
poll_fn: unsafe fn(*mut (), &mut Context) -> Poll<T>,
35+
drop_fn: unsafe fn(*mut ()),
36+
_marker: PhantomData<&'a ()>,
37+
}
38+
39+
impl<'a, T> LocalFutureObj<'a, T> {
40+
/// Create a `LocalFutureObj` from a custom trait object representation.
41+
#[inline]
42+
pub fn new<F: UnsafeFutureObj<'a, T> + 'a>(f: F) -> LocalFutureObj<'a, T> {
43+
LocalFutureObj {
44+
ptr: f.into_raw(),
45+
poll_fn: F::poll,
46+
drop_fn: F::drop,
47+
_marker: PhantomData,
48+
}
49+
}
50+
51+
/// Converts the `LocalFutureObj` into a `FutureObj`
52+
/// To make this operation safe one has to ensure that the `UnsafeFutureObj`
53+
/// instance from which this `LocalFutureObj` was created actually
54+
/// implements `Send`.
55+
#[inline]
56+
pub unsafe fn into_future_obj(self) -> FutureObj<'a, T> {
57+
FutureObj(self)
58+
}
59+
}
60+
61+
impl<'a, T> fmt::Debug for LocalFutureObj<'a, T> {
62+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
63+
f.debug_struct("LocalFutureObj")
64+
.finish()
65+
}
66+
}
67+
68+
impl<'a, T> From<FutureObj<'a, T>> for LocalFutureObj<'a, T> {
69+
#[inline]
70+
fn from(f: FutureObj<'a, T>) -> LocalFutureObj<'a, T> {
71+
f.0
72+
}
73+
}
74+
75+
impl<'a, T> Future for LocalFutureObj<'a, T> {
76+
type Output = T;
77+
78+
#[inline]
79+
fn poll(self: PinMut<Self>, cx: &mut Context) -> Poll<T> {
80+
unsafe {
81+
(self.poll_fn)(self.ptr, cx)
82+
}
83+
}
84+
}
85+
86+
impl<'a, T> Drop for LocalFutureObj<'a, T> {
87+
fn drop(&mut self) {
88+
unsafe {
89+
(self.drop_fn)(self.ptr)
90+
}
91+
}
92+
}
93+
94+
/// A custom trait object for polling futures, roughly akin to
95+
/// `Box<dyn Future<Output = T> + Send + 'a>`.
96+
///
97+
/// This custom trait object was introduced for two reasons:
98+
/// - Currently it is not possible to take `dyn Trait` by value and
99+
/// `Box<dyn Trait>` is not available in no_std contexts.
100+
/// - The `Future` trait is currently not object safe: The `Future::poll`
101+
/// method makes uses the arbitrary self types feature and traits in which
102+
/// this feature is used are currently not object safe due to current compiler
103+
/// limitations. (See tracking issue for arbitray self types for more
104+
/// information #44874)
105+
pub struct FutureObj<'a, T>(LocalFutureObj<'a, T>);
106+
107+
unsafe impl<'a, T> Send for FutureObj<'a, T> {}
108+
109+
impl<'a, T> FutureObj<'a, T> {
110+
/// Create a `FutureObj` from a custom trait object representation.
111+
#[inline]
112+
pub fn new<F: UnsafeFutureObj<'a, T> + Send>(f: F) -> FutureObj<'a, T> {
113+
FutureObj(LocalFutureObj::new(f))
114+
}
115+
}
116+
117+
impl<'a, T> fmt::Debug for FutureObj<'a, T> {
118+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
119+
f.debug_struct("FutureObj")
120+
.finish()
121+
}
122+
}
123+
124+
impl<'a, T> Future for FutureObj<'a, T> {
125+
type Output = T;
126+
127+
#[inline]
128+
fn poll(self: PinMut<Self>, cx: &mut Context) -> Poll<T> {
129+
let pinned_field = unsafe { PinMut::map_unchecked(self, |x| &mut x.0) };
130+
pinned_field.poll(cx)
131+
}
132+
}
133+
134+
/// A custom implementation of a future trait object for `FutureObj`, providing
135+
/// a hand-rolled vtable.
136+
///
137+
/// This custom representation is typically used only in `no_std` contexts,
138+
/// where the default `Box`-based implementation is not available.
139+
///
140+
/// The implementor must guarantee that it is safe to call `poll` repeatedly (in
141+
/// a non-concurrent fashion) with the result of `into_raw` until `drop` is
142+
/// called.
143+
pub unsafe trait UnsafeFutureObj<'a, T>: 'a {
144+
/// Convert an owned instance into a (conceptually owned) void pointer.
145+
fn into_raw(self) -> *mut ();
146+
147+
/// Poll the future represented by the given void pointer.
148+
///
149+
/// # Safety
150+
///
151+
/// The trait implementor must guarantee that it is safe to repeatedly call
152+
/// `poll` with the result of `into_raw` until `drop` is called; such calls
153+
/// are not, however, allowed to race with each other or with calls to
154+
/// `drop`.
155+
unsafe fn poll(ptr: *mut (), cx: &mut Context) -> Poll<T>;
156+
157+
/// Drops the future represented by the given void pointer.
158+
///
159+
/// # Safety
160+
///
161+
/// The trait implementor must guarantee that it is safe to call this
162+
/// function once per `into_raw` invocation; that call cannot race with
163+
/// other calls to `drop` or `poll`.
164+
unsafe fn drop(ptr: *mut ());
165+
}
166+
167+
unsafe impl<'a, T, F> UnsafeFutureObj<'a, T> for &'a mut F
168+
where F: Future<Output = T> + Unpin + 'a
169+
{
170+
fn into_raw(self) -> *mut () {
171+
self as *mut F as *mut ()
172+
}
173+
174+
unsafe fn poll(ptr: *mut (), cx: &mut Context) -> Poll<T> {
175+
PinMut::new_unchecked(&mut *(ptr as *mut F)).poll(cx)
176+
}
177+
178+
unsafe fn drop(_ptr: *mut ()) {}
179+
}

src/libcore/future/mod.rs

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
#![unstable(feature = "futures_api",
12+
reason = "futures in libcore are unstable",
13+
issue = "50547")]
14+
15+
//! Asynchronous values.
16+
17+
mod future;
18+
pub use self::future::Future;
19+
20+
mod future_obj;
21+
pub use self::future_obj::{FutureObj, LocalFutureObj, UnsafeFutureObj};

src/libcore/mem.rs

+17
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,12 @@
1818
use clone;
1919
use cmp;
2020
use fmt;
21+
use future::{Future, UnsafeFutureObj};
2122
use hash;
2223
use intrinsics;
2324
use marker::{Copy, PhantomData, Sized, Unpin, Unsize};
2425
use ptr;
26+
use task::{Context, Poll};
2527
use ops::{Deref, DerefMut, CoerceUnsized};
2628

2729
#[stable(feature = "rust1", since = "1.0.0")]
@@ -1227,3 +1229,18 @@ impl<'a, T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<PinMut<'a, U>> for PinM
12271229

12281230
#[unstable(feature = "pin", issue = "49150")]
12291231
impl<'a, T: ?Sized> Unpin for PinMut<'a, T> {}
1232+
1233+
#[unstable(feature = "futures_api", issue = "50547")]
1234+
unsafe impl<'a, T, F> UnsafeFutureObj<'a, T> for PinMut<'a, F>
1235+
where F: Future<Output = T> + 'a
1236+
{
1237+
fn into_raw(self) -> *mut () {
1238+
unsafe { PinMut::get_mut_unchecked(self) as *mut F as *mut () }
1239+
}
1240+
1241+
unsafe fn poll(ptr: *mut (), cx: &mut Context) -> Poll<T> {
1242+
PinMut::new_unchecked(&mut *(ptr as *mut F)).poll(cx)
1243+
}
1244+
1245+
unsafe fn drop(_ptr: *mut ()) {}
1246+
}

src/libcore/task/executor.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
issue = "50547")]
1414

1515
use fmt;
16-
use super::{TaskObj, LocalTaskObj};
16+
use future::{FutureObj, LocalFutureObj};
1717

1818
/// A task executor.
1919
///
@@ -29,7 +29,7 @@ pub trait Executor {
2929
///
3030
/// The executor may be unable to spawn tasks, either because it has
3131
/// been shut down or is resource-constrained.
32-
fn spawn_obj(&mut self, task: TaskObj) -> Result<(), SpawnObjError>;
32+
fn spawn_obj(&mut self, task: FutureObj<'static, ()>) -> Result<(), SpawnObjError>;
3333

3434
/// Determine whether the executor is able to spawn new tasks.
3535
///
@@ -76,7 +76,7 @@ pub struct SpawnObjError {
7676
pub kind: SpawnErrorKind,
7777

7878
/// The task for which spawning was attempted
79-
pub task: TaskObj,
79+
pub task: FutureObj<'static, ()>,
8080
}
8181

8282
/// The result of a failed spawn
@@ -86,5 +86,5 @@ pub struct SpawnLocalObjError {
8686
pub kind: SpawnErrorKind,
8787

8888
/// The task for which spawning was attempted
89-
pub task: LocalTaskObj,
89+
pub task: LocalFutureObj<'static, ()>,
9090
}

0 commit comments

Comments
 (0)