diff --git a/src/liballoc/boxed.rs b/src/liballoc/boxed.rs index 6a05ef680889a..fb16bdf0ab43a 100644 --- a/src/liballoc/boxed.rs +++ b/src/liballoc/boxed.rs @@ -58,16 +58,16 @@ use core::any::Any; use core::borrow; use core::cmp::Ordering; +use core::convert::From; use core::fmt; -use core::future::Future; +use core::future::{Future, FutureObj, LocalFutureObj, UnsafeFutureObj}; use core::hash::{Hash, Hasher}; use core::iter::FusedIterator; use core::marker::{Unpin, Unsize}; use core::mem::{self, PinMut}; use core::ops::{CoerceUnsized, Deref, DerefMut, Generator, GeneratorState}; use core::ptr::{self, NonNull, Unique}; -use core::task::{Context, Poll, UnsafeTask, TaskObj, LocalTaskObj}; -use core::convert::From; +use core::task::{Context, Poll}; use raw_vec::RawVec; use str::from_boxed_utf8_unchecked; @@ -915,7 +915,7 @@ impl, U: ?Sized> CoerceUnsized> for PinBox {} impl Unpin for PinBox {} #[unstable(feature = "futures_api", issue = "50547")] -impl<'a, F: ?Sized + Future + Unpin> Future for Box { +impl Future for Box { type Output = F::Output; fn poll(mut self: PinMut, cx: &mut Context) -> Poll { @@ -924,7 +924,7 @@ impl<'a, F: ?Sized + Future + Unpin> Future for Box { } #[unstable(feature = "futures_api", issue = "50547")] -impl<'a, F: ?Sized + Future> Future for PinBox { +impl Future for PinBox { type Output = F::Output; fn poll(mut self: PinMut, cx: &mut Context) -> Poll { @@ -933,46 +933,67 @@ impl<'a, F: ?Sized + Future> Future for PinBox { } #[unstable(feature = "futures_api", issue = "50547")] -unsafe impl + 'static> UnsafeTask for PinBox { +unsafe impl<'a, T, F> UnsafeFutureObj<'a, T> for Box + where F: Future + 'a +{ + fn into_raw(self) -> *mut () { + Box::into_raw(self) as *mut () + } + + unsafe fn poll(ptr: *mut (), cx: &mut Context) -> Poll { + let ptr = ptr as *mut F; + let pin: PinMut = PinMut::new_unchecked(&mut *ptr); + pin.poll(cx) + } + + unsafe fn drop(ptr: *mut ()) { + drop(Box::from_raw(ptr as *mut F)) + } +} + +#[unstable(feature = "futures_api", issue = "50547")] +unsafe impl<'a, T, F> UnsafeFutureObj<'a, T> for PinBox + where F: Future + 'a +{ fn into_raw(self) -> *mut () { PinBox::into_raw(self) as *mut () } - unsafe fn poll(task: *mut (), cx: &mut Context) -> Poll<()> { - let ptr = task as *mut F; + unsafe fn poll(ptr: *mut (), cx: &mut Context) -> Poll { + let ptr = ptr as *mut F; let pin: PinMut = PinMut::new_unchecked(&mut *ptr); pin.poll(cx) } - unsafe fn drop(task: *mut ()) { - drop(PinBox::from_raw(task as *mut F)) + unsafe fn drop(ptr: *mut ()) { + drop(PinBox::from_raw(ptr as *mut F)) } } #[unstable(feature = "futures_api", issue = "50547")] -impl + Send + 'static> From> for TaskObj { +impl<'a, F: Future + Send + 'a> From> for FutureObj<'a, ()> { fn from(boxed: PinBox) -> Self { - TaskObj::new(boxed) + FutureObj::new(boxed) } } #[unstable(feature = "futures_api", issue = "50547")] -impl + Send + 'static> From> for TaskObj { +impl<'a, F: Future + Send + 'a> From> for FutureObj<'a, ()> { fn from(boxed: Box) -> Self { - TaskObj::new(PinBox::from(boxed)) + FutureObj::new(boxed) } } #[unstable(feature = "futures_api", issue = "50547")] -impl + 'static> From> for LocalTaskObj { +impl<'a, F: Future + 'a> From> for LocalFutureObj<'a, ()> { fn from(boxed: PinBox) -> Self { - LocalTaskObj::new(boxed) + LocalFutureObj::new(boxed) } } #[unstable(feature = "futures_api", issue = "50547")] -impl + 'static> From> for LocalTaskObj { +impl<'a, F: Future + 'a> From> for LocalFutureObj<'a, ()> { fn from(boxed: Box) -> Self { - LocalTaskObj::new(PinBox::from(boxed)) + LocalFutureObj::new(boxed) } } diff --git a/src/libcore/future.rs b/src/libcore/future/future.rs similarity index 99% rename from src/libcore/future.rs rename to src/libcore/future/future.rs index 153cd6c0724d6..10b4ca9b0b27a 100644 --- a/src/libcore/future.rs +++ b/src/libcore/future/future.rs @@ -12,8 +12,6 @@ reason = "futures in libcore are unstable", issue = "50547")] -//! Asynchronous values. - use mem::PinMut; use marker::Unpin; use task::{self, Poll}; diff --git a/src/libcore/future/future_obj.rs b/src/libcore/future/future_obj.rs new file mode 100644 index 0000000000000..98c504a3f7bef --- /dev/null +++ b/src/libcore/future/future_obj.rs @@ -0,0 +1,179 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![unstable(feature = "futures_api", + reason = "futures in libcore are unstable", + issue = "50547")] + +use fmt; +use future::Future; +use marker::{PhantomData, Unpin}; +use mem::PinMut; +use task::{Context, Poll}; + +/// A custom trait object for polling futures, roughly akin to +/// `Box + 'a>`. +/// +/// This custom trait object was introduced for two reasons: +/// - Currently it is not possible to take `dyn Trait` by value and +/// `Box` is not available in no_std contexts. +/// - The `Future` trait is currently not object safe: The `Future::poll` +/// method makes uses the arbitrary self types feature and traits in which +/// this feature is used are currently not object safe due to current compiler +/// limitations. (See tracking issue for arbitray self types for more +/// information #44874) +pub struct LocalFutureObj<'a, T> { + ptr: *mut (), + poll_fn: unsafe fn(*mut (), &mut Context) -> Poll, + drop_fn: unsafe fn(*mut ()), + _marker: PhantomData<&'a ()>, +} + +impl<'a, T> LocalFutureObj<'a, T> { + /// Create a `LocalFutureObj` from a custom trait object representation. + #[inline] + pub fn new + 'a>(f: F) -> LocalFutureObj<'a, T> { + LocalFutureObj { + ptr: f.into_raw(), + poll_fn: F::poll, + drop_fn: F::drop, + _marker: PhantomData, + } + } + + /// Converts the `LocalFutureObj` into a `FutureObj` + /// To make this operation safe one has to ensure that the `UnsafeFutureObj` + /// instance from which this `LocalFutureObj` was created actually + /// implements `Send`. + #[inline] + pub unsafe fn into_future_obj(self) -> FutureObj<'a, T> { + FutureObj(self) + } +} + +impl<'a, T> fmt::Debug for LocalFutureObj<'a, T> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("LocalFutureObj") + .finish() + } +} + +impl<'a, T> From> for LocalFutureObj<'a, T> { + #[inline] + fn from(f: FutureObj<'a, T>) -> LocalFutureObj<'a, T> { + f.0 + } +} + +impl<'a, T> Future for LocalFutureObj<'a, T> { + type Output = T; + + #[inline] + fn poll(self: PinMut, cx: &mut Context) -> Poll { + unsafe { + (self.poll_fn)(self.ptr, cx) + } + } +} + +impl<'a, T> Drop for LocalFutureObj<'a, T> { + fn drop(&mut self) { + unsafe { + (self.drop_fn)(self.ptr) + } + } +} + +/// A custom trait object for polling futures, roughly akin to +/// `Box + Send + 'a>`. +/// +/// This custom trait object was introduced for two reasons: +/// - Currently it is not possible to take `dyn Trait` by value and +/// `Box` is not available in no_std contexts. +/// - The `Future` trait is currently not object safe: The `Future::poll` +/// method makes uses the arbitrary self types feature and traits in which +/// this feature is used are currently not object safe due to current compiler +/// limitations. (See tracking issue for arbitray self types for more +/// information #44874) +pub struct FutureObj<'a, T>(LocalFutureObj<'a, T>); + +unsafe impl<'a, T> Send for FutureObj<'a, T> {} + +impl<'a, T> FutureObj<'a, T> { + /// Create a `FutureObj` from a custom trait object representation. + #[inline] + pub fn new + Send>(f: F) -> FutureObj<'a, T> { + FutureObj(LocalFutureObj::new(f)) + } +} + +impl<'a, T> fmt::Debug for FutureObj<'a, T> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("FutureObj") + .finish() + } +} + +impl<'a, T> Future for FutureObj<'a, T> { + type Output = T; + + #[inline] + fn poll(self: PinMut, cx: &mut Context) -> Poll { + let pinned_field = unsafe { PinMut::map_unchecked(self, |x| &mut x.0) }; + pinned_field.poll(cx) + } +} + +/// A custom implementation of a future trait object for `FutureObj`, providing +/// a hand-rolled vtable. +/// +/// This custom representation is typically used only in `no_std` contexts, +/// where the default `Box`-based implementation is not available. +/// +/// 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 +/// called. +pub unsafe trait UnsafeFutureObj<'a, T>: 'a { + /// Convert an owned instance into a (conceptually owned) void pointer. + fn into_raw(self) -> *mut (); + + /// Poll the future represented by the given void pointer. + /// + /// # Safety + /// + /// 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 + /// are not, however, allowed to race with each other or with calls to + /// `drop`. + unsafe fn poll(ptr: *mut (), cx: &mut Context) -> Poll; + + /// Drops the future represented by the given void pointer. + /// + /// # Safety + /// + /// The trait implementor must guarantee that it is safe to call this + /// function once per `into_raw` invocation; that call cannot race with + /// other calls to `drop` or `poll`. + unsafe fn drop(ptr: *mut ()); +} + +unsafe impl<'a, T, F> UnsafeFutureObj<'a, T> for &'a mut F + where F: Future + Unpin + 'a +{ + fn into_raw(self) -> *mut () { + self as *mut F as *mut () + } + + unsafe fn poll(ptr: *mut (), cx: &mut Context) -> Poll { + PinMut::new_unchecked(&mut *(ptr as *mut F)).poll(cx) + } + + unsafe fn drop(_ptr: *mut ()) {} +} diff --git a/src/libcore/future/mod.rs b/src/libcore/future/mod.rs new file mode 100644 index 0000000000000..f9361a0f4e7a3 --- /dev/null +++ b/src/libcore/future/mod.rs @@ -0,0 +1,21 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![unstable(feature = "futures_api", + reason = "futures in libcore are unstable", + issue = "50547")] + +//! Asynchronous values. + +mod future; +pub use self::future::Future; + +mod future_obj; +pub use self::future_obj::{FutureObj, LocalFutureObj, UnsafeFutureObj}; diff --git a/src/libcore/mem.rs b/src/libcore/mem.rs index 08bd9289ab487..84173654655eb 100644 --- a/src/libcore/mem.rs +++ b/src/libcore/mem.rs @@ -18,10 +18,12 @@ use clone; use cmp; use fmt; +use future::{Future, UnsafeFutureObj}; use hash; use intrinsics; use marker::{Copy, PhantomData, Sized, Unpin, Unsize}; use ptr; +use task::{Context, Poll}; use ops::{Deref, DerefMut, CoerceUnsized}; #[stable(feature = "rust1", since = "1.0.0")] @@ -1227,3 +1229,18 @@ impl<'a, T: ?Sized + Unsize, U: ?Sized> CoerceUnsized> for PinM #[unstable(feature = "pin", issue = "49150")] impl<'a, T: ?Sized> Unpin for PinMut<'a, T> {} + +#[unstable(feature = "futures_api", issue = "50547")] +unsafe impl<'a, T, F> UnsafeFutureObj<'a, T> for PinMut<'a, F> + where F: Future + 'a +{ + fn into_raw(self) -> *mut () { + unsafe { PinMut::get_mut_unchecked(self) as *mut F as *mut () } + } + + unsafe fn poll(ptr: *mut (), cx: &mut Context) -> Poll { + PinMut::new_unchecked(&mut *(ptr as *mut F)).poll(cx) + } + + unsafe fn drop(_ptr: *mut ()) {} +} diff --git a/src/libcore/task/executor.rs b/src/libcore/task/executor.rs index 73bf80d2f9997..f1db5093e9880 100644 --- a/src/libcore/task/executor.rs +++ b/src/libcore/task/executor.rs @@ -13,7 +13,7 @@ issue = "50547")] use fmt; -use super::{TaskObj, LocalTaskObj}; +use future::{FutureObj, LocalFutureObj}; /// A task executor. /// @@ -29,7 +29,7 @@ pub trait Executor { /// /// The executor may be unable to spawn tasks, either because it has /// been shut down or is resource-constrained. - fn spawn_obj(&mut self, task: TaskObj) -> Result<(), SpawnObjError>; + fn spawn_obj(&mut self, task: FutureObj<'static, ()>) -> Result<(), SpawnObjError>; /// Determine whether the executor is able to spawn new tasks. /// @@ -76,7 +76,7 @@ pub struct SpawnObjError { pub kind: SpawnErrorKind, /// The task for which spawning was attempted - pub task: TaskObj, + pub task: FutureObj<'static, ()>, } /// The result of a failed spawn @@ -86,5 +86,5 @@ pub struct SpawnLocalObjError { pub kind: SpawnErrorKind, /// The task for which spawning was attempted - pub task: LocalTaskObj, + pub task: LocalFutureObj<'static, ()>, } diff --git a/src/libcore/task/mod.rs b/src/libcore/task/mod.rs index d167a37410553..c4f075361640f 100644 --- a/src/libcore/task/mod.rs +++ b/src/libcore/task/mod.rs @@ -25,8 +25,5 @@ pub use self::executor::{ mod poll; pub use self::poll::Poll; -mod task; -pub use self::task::{TaskObj, LocalTaskObj, UnsafeTask}; - mod wake; pub use self::wake::{Waker, LocalWaker, UnsafeWake}; diff --git a/src/libcore/task/task.rs b/src/libcore/task/task.rs deleted file mode 100644 index c5a41873db427..0000000000000 --- a/src/libcore/task/task.rs +++ /dev/null @@ -1,142 +0,0 @@ -// Copyright 2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#![unstable(feature = "futures_api", - reason = "futures in libcore are unstable", - issue = "50547")] - -use fmt; -use future::Future; -use mem::PinMut; -use super::{Context, Poll}; - -/// A custom trait object for polling tasks, roughly akin to -/// `Box>`. -/// Contrary to `TaskObj`, `LocalTaskObj` does not have a `Send` bound. -pub struct LocalTaskObj { - ptr: *mut (), - poll_fn: unsafe fn(*mut (), &mut Context) -> Poll<()>, - drop_fn: unsafe fn(*mut ()), -} - -impl LocalTaskObj { - /// Create a `LocalTaskObj` from a custom trait object representation. - #[inline] - pub fn new(t: T) -> LocalTaskObj { - LocalTaskObj { - ptr: t.into_raw(), - poll_fn: T::poll, - drop_fn: T::drop, - } - } - - /// Converts the `LocalTaskObj` into a `TaskObj` - /// To make this operation safe one has to ensure that the `UnsafeTask` - /// instance from which this `LocalTaskObj` was created actually implements - /// `Send`. - pub unsafe fn as_task_obj(self) -> TaskObj { - TaskObj(self) - } -} - -impl fmt::Debug for LocalTaskObj { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.debug_struct("LocalTaskObj") - .finish() - } -} - -impl From for LocalTaskObj { - fn from(task: TaskObj) -> LocalTaskObj { - task.0 - } -} - -impl Future for LocalTaskObj { - type Output = (); - - #[inline] - fn poll(self: PinMut, cx: &mut Context) -> Poll<()> { - unsafe { - (self.poll_fn)(self.ptr, cx) - } - } -} - -impl Drop for LocalTaskObj { - fn drop(&mut self) { - unsafe { - (self.drop_fn)(self.ptr) - } - } -} - -/// A custom trait object for polling tasks, roughly akin to -/// `Box + Send>`. -pub struct TaskObj(LocalTaskObj); - -unsafe impl Send for TaskObj {} - -impl TaskObj { - /// Create a `TaskObj` from a custom trait object representation. - #[inline] - pub fn new(t: T) -> TaskObj { - TaskObj(LocalTaskObj::new(t)) - } -} - -impl fmt::Debug for TaskObj { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.debug_struct("TaskObj") - .finish() - } -} - -impl Future for TaskObj { - type Output = (); - - #[inline] - fn poll(self: PinMut, cx: &mut Context) -> Poll<()> { - let pinned_field = unsafe { PinMut::map_unchecked(self, |x| &mut x.0) }; - pinned_field.poll(cx) - } -} - -/// A custom implementation of a task trait object for `TaskObj`, providing -/// a hand-rolled vtable. -/// -/// This custom representation is typically used only in `no_std` contexts, -/// where the default `Box`-based implementation is not available. -/// -/// 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 -/// called. -pub unsafe trait UnsafeTask: 'static { - /// Convert a owned instance into a (conceptually owned) void pointer. - fn into_raw(self) -> *mut (); - - /// Poll the task represented by the given void pointer. - /// - /// # Safety - /// - /// 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 - /// are not, however, allowed to race with each other or with calls to `drop`. - unsafe fn poll(task: *mut (), cx: &mut Context) -> Poll<()>; - - /// Drops the task represented by the given void pointer. - /// - /// # Safety - /// - /// The trait implementor must guarantee that it is safe to call this - /// function once per `into_raw` invocation; that call cannot race with - /// other calls to `drop` or `poll`. - unsafe fn drop(task: *mut ()); -} diff --git a/src/test/run-pass/async-await.rs b/src/test/run-pass/async-await.rs index 8b649f6ef7bbd..0ac37485d3dc8 100644 --- a/src/test/run-pass/async-await.rs +++ b/src/test/run-pass/async-await.rs @@ -19,9 +19,10 @@ use std::sync::{ Arc, atomic::{self, AtomicUsize}, }; +use std::future::FutureObj; use std::task::{ Context, Poll, Wake, - Executor, TaskObj, SpawnObjError, + Executor, SpawnObjError, local_waker_from_nonlocal, }; @@ -37,7 +38,7 @@ impl Wake for Counter { struct NoopExecutor; impl Executor for NoopExecutor { - fn spawn_obj(&mut self, _: TaskObj) -> Result<(), SpawnObjError> { + fn spawn_obj(&mut self, _: FutureObj<'static, ()>) -> Result<(), SpawnObjError> { Ok(()) } } diff --git a/src/test/run-pass/futures-api.rs b/src/test/run-pass/futures-api.rs index 3b5a1725b66cb..6cb975a9560b9 100644 --- a/src/test/run-pass/futures-api.rs +++ b/src/test/run-pass/futures-api.rs @@ -19,10 +19,11 @@ use std::sync::{ Arc, atomic::{self, AtomicUsize}, }; +use std::future::FutureObj; use std::task::{ Context, Poll, Wake, Waker, LocalWaker, - Executor, TaskObj, SpawnObjError, + Executor, SpawnObjError, local_waker, local_waker_from_nonlocal, }; @@ -44,7 +45,7 @@ impl Wake for Counter { struct NoopExecutor; impl Executor for NoopExecutor { - fn spawn_obj(&mut self, _: TaskObj) -> Result<(), SpawnObjError> { + fn spawn_obj(&mut self, _: FutureObj<'static, ()>) -> Result<(), SpawnObjError> { Ok(()) } }