Make custom trait object for Future generic

This commit is contained in:
Josef Reinhard Brandl
2018-06-30 17:26:38 +02:00
parent a96c88e80f
commit 3d43f828f5
6 changed files with 77 additions and 72 deletions

View File

@@ -66,7 +66,7 @@ use core::marker::{Unpin, Unsize};
use core::mem::{self, PinMut}; use core::mem::{self, PinMut};
use core::ops::{CoerceUnsized, Deref, DerefMut, Generator, GeneratorState}; use core::ops::{CoerceUnsized, Deref, DerefMut, Generator, GeneratorState};
use core::ptr::{self, NonNull, Unique}; use core::ptr::{self, NonNull, Unique};
use core::task::{Context, Poll, UnsafeTask, TaskObj, LocalTaskObj}; use core::task::{Context, Poll, UnsafeFutureObj, FutureObj, LocalFutureObj};
use core::convert::From; use core::convert::From;
use raw_vec::RawVec; use raw_vec::RawVec;
@@ -933,12 +933,12 @@ impl<'a, F: ?Sized + Future> Future for PinBox<F> {
} }
#[unstable(feature = "futures_api", issue = "50547")] #[unstable(feature = "futures_api", issue = "50547")]
unsafe impl<F: Future<Output = ()> + 'static> UnsafeTask for PinBox<F> { unsafe impl<T, F: Future<Output = T> + 'static> UnsafeFutureObj<T> for PinBox<F> {
fn into_raw(self) -> *mut () { fn into_raw(self) -> *mut () {
PinBox::into_raw(self) as *mut () PinBox::into_raw(self) as *mut ()
} }
unsafe fn poll(task: *mut (), cx: &mut Context) -> Poll<()> { unsafe fn poll(task: *mut (), cx: &mut Context) -> Poll<T> {
let ptr = task as *mut F; let ptr = task as *mut F;
let pin: PinMut<F> = PinMut::new_unchecked(&mut *ptr); let pin: PinMut<F> = PinMut::new_unchecked(&mut *ptr);
pin.poll(cx) pin.poll(cx)
@@ -950,29 +950,29 @@ unsafe impl<F: Future<Output = ()> + 'static> UnsafeTask for PinBox<F> {
} }
#[unstable(feature = "futures_api", issue = "50547")] #[unstable(feature = "futures_api", issue = "50547")]
impl<F: Future<Output = ()> + Send + 'static> From<PinBox<F>> for TaskObj { impl<T, F: Future<Output = T> + Send + 'static> Into<FutureObj<T>> for PinBox<F> {
fn from(boxed: PinBox<F>) -> Self { fn into(self) -> FutureObj<T> {
TaskObj::new(boxed) FutureObj::new(self)
} }
} }
#[unstable(feature = "futures_api", issue = "50547")] #[unstable(feature = "futures_api", issue = "50547")]
impl<F: Future<Output = ()> + Send + 'static> From<Box<F>> for TaskObj { impl<T, F: Future<Output = T> + Send + 'static> Into<FutureObj<T>> for Box<F> {
fn from(boxed: Box<F>) -> Self { fn into(self) -> FutureObj<T> {
TaskObj::new(PinBox::from(boxed)) FutureObj::new(PinBox::from(self))
} }
} }
#[unstable(feature = "futures_api", issue = "50547")] #[unstable(feature = "futures_api", issue = "50547")]
impl<F: Future<Output = ()> + 'static> From<PinBox<F>> for LocalTaskObj { impl<T, F: Future<Output = T> + 'static> Into<LocalFutureObj<T>> for PinBox<F> {
fn from(boxed: PinBox<F>) -> Self { fn into(self) -> LocalFutureObj<T> {
LocalTaskObj::new(boxed) LocalFutureObj::new(self)
} }
} }
#[unstable(feature = "futures_api", issue = "50547")] #[unstable(feature = "futures_api", issue = "50547")]
impl<F: Future<Output = ()> + 'static> From<Box<F>> for LocalTaskObj { impl<T, F: Future<Output = T> + 'static> Into<LocalFutureObj<T>> for Box<F> {
fn from(boxed: Box<F>) -> Self { fn into(self) -> LocalFutureObj<T> {
LocalTaskObj::new(PinBox::from(boxed)) LocalFutureObj::new(PinBox::from(self))
} }
} }

View File

@@ -13,7 +13,7 @@
issue = "50547")] issue = "50547")]
use fmt; use fmt;
use super::{TaskObj, LocalTaskObj}; use super::{FutureObj, LocalFutureObj};
/// A task executor. /// A task executor.
/// ///
@@ -29,7 +29,7 @@ pub trait Executor {
/// ///
/// The executor may be unable to spawn tasks, either because it has /// The executor may be unable to spawn tasks, either because it has
/// been shut down or is resource-constrained. /// been shut down or is resource-constrained.
fn spawn_obj(&mut self, task: TaskObj) -> Result<(), SpawnObjError>; fn spawn_obj(&mut self, task: FutureObj<()>) -> Result<(), SpawnObjError>;
/// Determine whether the executor is able to spawn new tasks. /// Determine whether the executor is able to spawn new tasks.
/// ///
@@ -76,7 +76,7 @@ pub struct SpawnObjError {
pub kind: SpawnErrorKind, pub kind: SpawnErrorKind,
/// The task for which spawning was attempted /// The task for which spawning was attempted
pub task: TaskObj, pub task: FutureObj<()>,
} }
/// The result of a failed spawn /// The result of a failed spawn
@@ -86,5 +86,5 @@ pub struct SpawnLocalObjError {
pub kind: SpawnErrorKind, pub kind: SpawnErrorKind,
/// The task for which spawning was attempted /// The task for which spawning was attempted
pub task: LocalTaskObj, pub task: LocalFutureObj<()>,
} }

View File

@@ -14,63 +14,68 @@
use fmt; use fmt;
use future::Future; use future::Future;
use marker::PhantomData;
use mem::PinMut; use mem::PinMut;
use super::{Context, Poll}; use task::{Context, Poll};
/// A custom trait object for polling tasks, roughly akin to /// A custom trait object for polling futures, roughly akin to
/// `Box<Future<Output = ()>>`. /// `Box<dyn Future<Output = T>>`.
/// Contrary to `TaskObj`, `LocalTaskObj` does not have a `Send` bound. /// Contrary to `FutureObj`, `LocalFutureObj` does not have a `Send` bound.
pub struct LocalTaskObj { pub struct LocalFutureObj<T> {
ptr: *mut (), ptr: *mut (),
poll_fn: unsafe fn(*mut (), &mut Context) -> Poll<()>, poll_fn: unsafe fn(*mut (), &mut Context) -> Poll<T>,
drop_fn: unsafe fn(*mut ()), drop_fn: unsafe fn(*mut ()),
_marker: PhantomData<T>,
} }
impl LocalTaskObj { impl<T> LocalFutureObj<T> {
/// Create a `LocalTaskObj` from a custom trait object representation. /// Create a `LocalFutureObj` from a custom trait object representation.
#[inline] #[inline]
pub fn new<T: UnsafeTask>(t: T) -> LocalTaskObj { pub fn new<F: UnsafeFutureObj<T>>(f: F) -> LocalFutureObj<T> {
LocalTaskObj { LocalFutureObj {
ptr: t.into_raw(), ptr: f.into_raw(),
poll_fn: T::poll, poll_fn: F::poll,
drop_fn: T::drop, drop_fn: F::drop,
_marker: PhantomData,
} }
} }
/// Converts the `LocalTaskObj` into a `TaskObj` /// Converts the `LocalFutureObj` into a `FutureObj`
/// To make this operation safe one has to ensure that the `UnsafeTask` /// To make this operation safe one has to ensure that the `UnsafeFutureObj`
/// instance from which this `LocalTaskObj` was created actually implements /// instance from which this `LocalFutureObj` was created actually
/// `Send`. /// implements `Send`.
pub unsafe fn as_task_obj(self) -> TaskObj { #[inline]
TaskObj(self) pub unsafe fn as_future_obj(self) -> FutureObj<T> {
FutureObj(self)
} }
} }
impl fmt::Debug for LocalTaskObj { impl<T> fmt::Debug for LocalFutureObj<T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("LocalTaskObj") f.debug_struct("LocalFutureObj")
.finish() .finish()
} }
} }
impl From<TaskObj> for LocalTaskObj { impl<T> From<FutureObj<T>> for LocalFutureObj<T> {
fn from(task: TaskObj) -> LocalTaskObj { #[inline]
task.0 fn from(f: FutureObj<T>) -> LocalFutureObj<T> {
f.0
} }
} }
impl Future for LocalTaskObj { impl<T> Future for LocalFutureObj<T> {
type Output = (); type Output = T;
#[inline] #[inline]
fn poll(self: PinMut<Self>, cx: &mut Context) -> Poll<()> { fn poll(self: PinMut<Self>, cx: &mut Context) -> Poll<T> {
unsafe { unsafe {
(self.poll_fn)(self.ptr, cx) (self.poll_fn)(self.ptr, cx)
} }
} }
} }
impl Drop for LocalTaskObj { impl<T> Drop for LocalFutureObj<T> {
fn drop(&mut self) { fn drop(&mut self) {
unsafe { unsafe {
(self.drop_fn)(self.ptr) (self.drop_fn)(self.ptr)
@@ -78,38 +83,38 @@ impl Drop for LocalTaskObj {
} }
} }
/// A custom trait object for polling tasks, roughly akin to /// A custom trait object for polling futures, roughly akin to
/// `Box<Future<Output = ()> + Send>`. /// `Box<dyn Future<Output = T>> + Send`.
pub struct TaskObj(LocalTaskObj); pub struct FutureObj<T>(LocalFutureObj<T>);
unsafe impl Send for TaskObj {} unsafe impl<T> Send for FutureObj<T> {}
impl TaskObj { impl<T> FutureObj<T> {
/// Create a `TaskObj` from a custom trait object representation. /// Create a `FutureObj` from a custom trait object representation.
#[inline] #[inline]
pub fn new<T: UnsafeTask + Send>(t: T) -> TaskObj { pub fn new<F: UnsafeFutureObj<T> + Send>(f: F) -> FutureObj<T> {
TaskObj(LocalTaskObj::new(t)) FutureObj(LocalFutureObj::new(f))
} }
} }
impl fmt::Debug for TaskObj { impl<T> fmt::Debug for FutureObj<T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("TaskObj") f.debug_struct("FutureObj")
.finish() .finish()
} }
} }
impl Future for TaskObj { impl<T> Future for FutureObj<T> {
type Output = (); type Output = T;
#[inline] #[inline]
fn poll(self: PinMut<Self>, cx: &mut Context) -> Poll<()> { fn poll(self: PinMut<Self>, cx: &mut Context) -> Poll<T> {
let pinned_field = unsafe { PinMut::map_unchecked(self, |x| &mut x.0) }; let pinned_field = unsafe { PinMut::map_unchecked(self, |x| &mut x.0) };
pinned_field.poll(cx) pinned_field.poll(cx)
} }
} }
/// A custom implementation of a task trait object for `TaskObj`, providing /// A custom implementation of a future trait object for `FutureObj`, providing
/// a hand-rolled vtable. /// a hand-rolled vtable.
/// ///
/// This custom representation is typically used only in `no_std` contexts, /// This custom representation is typically used only in `no_std` contexts,
@@ -118,25 +123,25 @@ impl Future for TaskObj {
/// The implementor must guarantee that it is safe to call `poll` repeatedly (in /// The implementor must guarantee that it is safe to call `poll` repeatedly (in
/// a non-concurrent fashion) with the result of `into_raw` until `drop` is /// a non-concurrent fashion) with the result of `into_raw` until `drop` is
/// called. /// called.
pub unsafe trait UnsafeTask: 'static { pub unsafe trait UnsafeFutureObj<T>: 'static {
/// Convert a owned instance into a (conceptually owned) void pointer. /// Convert a owned instance into a (conceptually owned) void pointer.
fn into_raw(self) -> *mut (); fn into_raw(self) -> *mut ();
/// Poll the task represented by the given void pointer. /// Poll the future represented by the given void pointer.
/// ///
/// # Safety /// # Safety
/// ///
/// The trait implementor must guarantee that it is safe to repeatedly call /// The trait implementor must guarantee that it is safe to repeatedly call
/// `poll` with the result of `into_raw` until `drop` is called; such calls /// `poll` with the result of `into_raw` until `drop` is called; such calls
/// are not, however, allowed to race with each other or with calls to `drop`. /// are not, however, allowed to race with each other or with calls to `drop`.
unsafe fn poll(task: *mut (), cx: &mut Context) -> Poll<()>; unsafe fn poll(future: *mut (), cx: &mut Context) -> Poll<T>;
/// Drops the task represented by the given void pointer. /// Drops the future represented by the given void pointer.
/// ///
/// # Safety /// # Safety
/// ///
/// The trait implementor must guarantee that it is safe to call this /// The trait implementor must guarantee that it is safe to call this
/// function once per `into_raw` invocation; that call cannot race with /// function once per `into_raw` invocation; that call cannot race with
/// other calls to `drop` or `poll`. /// other calls to `drop` or `poll`.
unsafe fn drop(task: *mut ()); unsafe fn drop(future: *mut ());
} }

View File

@@ -25,8 +25,8 @@ pub use self::executor::{
mod poll; mod poll;
pub use self::poll::Poll; pub use self::poll::Poll;
mod task; mod future_obj;
pub use self::task::{TaskObj, LocalTaskObj, UnsafeTask}; pub use self::future_obj::{FutureObj, LocalFutureObj, UnsafeFutureObj};
mod wake; mod wake;
pub use self::wake::{Waker, LocalWaker, UnsafeWake}; pub use self::wake::{Waker, LocalWaker, UnsafeWake};

View File

@@ -21,7 +21,7 @@ use std::sync::{
}; };
use std::task::{ use std::task::{
Context, Poll, Wake, Context, Poll, Wake,
Executor, TaskObj, SpawnObjError, Executor, FutureObj, SpawnObjError,
local_waker_from_nonlocal, local_waker_from_nonlocal,
}; };
@@ -37,7 +37,7 @@ impl Wake for Counter {
struct NoopExecutor; struct NoopExecutor;
impl Executor for NoopExecutor { impl Executor for NoopExecutor {
fn spawn_obj(&mut self, _: TaskObj) -> Result<(), SpawnObjError> { fn spawn_obj(&mut self, _: FutureObj<T>) -> Result<(), SpawnObjError> {
Ok(()) Ok(())
} }
} }

View File

@@ -22,7 +22,7 @@ use std::sync::{
use std::task::{ use std::task::{
Context, Poll, Context, Poll,
Wake, Waker, LocalWaker, Wake, Waker, LocalWaker,
Executor, TaskObj, SpawnObjError, Executor, FutureObj, SpawnObjError,
local_waker, local_waker_from_nonlocal, local_waker, local_waker_from_nonlocal,
}; };
@@ -44,7 +44,7 @@ impl Wake for Counter {
struct NoopExecutor; struct NoopExecutor;
impl Executor for NoopExecutor { impl Executor for NoopExecutor {
fn spawn_obj(&mut self, _: TaskObj) -> Result<(), SpawnObjError> { fn spawn_obj(&mut self, _: FutureObj<()>) -> Result<(), SpawnObjError> {
Ok(()) Ok(())
} }
} }