From de9ab1d4e52847b8ebf135bbcb60c2f8cadfed16 Mon Sep 17 00:00:00 2001 From: tinaun Date: Thu, 7 Jun 2018 15:38:05 -0400 Subject: [PATCH 1/9] remove `futures-stable` --- Cargo.toml | 1 - futures-stable/Cargo.toml | 22 -------- futures-stable/src/executor.rs | 36 ------------ futures-stable/src/lib.rs | 97 -------------------------------- futures-stable/src/unsafe_pin.rs | 30 ---------- 5 files changed, 186 deletions(-) delete mode 100644 futures-stable/Cargo.toml delete mode 100644 futures-stable/src/executor.rs delete mode 100644 futures-stable/src/lib.rs delete mode 100644 futures-stable/src/unsafe_pin.rs diff --git a/Cargo.toml b/Cargo.toml index 7ba636a554..6f0d5e522c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,6 +9,5 @@ members = [ # "futures-macro-async", # "futures-macro-await", "futures-sink", -# "futures-stable", "futures-util", ] diff --git a/futures-stable/Cargo.toml b/futures-stable/Cargo.toml deleted file mode 100644 index b71a5b9412..0000000000 --- a/futures-stable/Cargo.toml +++ /dev/null @@ -1,22 +0,0 @@ -[package] -name = "futures-stable" -description = "futures which support internal references" -version = "0.2.0" -authors = ["boats "] -license = "MIT OR Apache-2.0" -repository = "https://github.com/rust-lang-nursery/futures-rs" - -[dependencies.futures-core] -path = "../futures-core" -version = "0.2.0" -default-features = false - -[dependencies.futures-executor] -path = "../futures-executor" -version = "0.2.0" -default-features = false - -[features] -nightly = ["futures-core/nightly"] -std = ["futures-core/std", "futures-executor/std"] -default = ["std"] diff --git a/futures-stable/src/executor.rs b/futures-stable/src/executor.rs deleted file mode 100644 index 903d170193..0000000000 --- a/futures-stable/src/executor.rs +++ /dev/null @@ -1,36 +0,0 @@ -use std::boxed::PinBox; - -use futures_core::{Future, Never}; -use futures_core::executor::{Executor, SpawnError}; -use futures_executor::{ThreadPool, LocalPool, LocalExecutor}; - -use StableFuture; -use UnsafePinMut; - -pub trait StableExecutor: Executor { - fn spawn_pinned(&mut self, f: PinBox + Send>) -> Result<(), SpawnError>; -} - -impl StableExecutor for ThreadPool { - fn spawn_pinned(&mut self, f: PinBox + Send>) -> Result<(), SpawnError> { - unsafe { self.spawn(PinBox::unpin(f)) } - } -} - -impl StableExecutor for LocalExecutor { - fn spawn_pinned(&mut self, f: PinBox + Send>) -> Result<(), SpawnError> { - unsafe { self.spawn(PinBox::unpin(f)) } - } -} - -pub fn block_on_stable(f: F) -> Result { - let mut pool = LocalPool::new(); - let mut exec = pool.executor(); - - // run our main future to completion - let res = pool.run_until(unsafe { UnsafePinMut::new(f) }, &mut exec); - // run any remainingspawned tasks to completion - pool.run(&mut exec); - - res -} diff --git a/futures-stable/src/lib.rs b/futures-stable/src/lib.rs deleted file mode 100644 index 9c514cb679..0000000000 --- a/futures-stable/src/lib.rs +++ /dev/null @@ -1,97 +0,0 @@ -#![no_std] -#![cfg_attr(feature = "nightly", feature(arbitrary_self_types))] -#![cfg_attr(feature = "nightly", feature(pin))] - -macro_rules! if_nightly { - ($($i:item)*) => ($( - #[cfg(feature = "nightly")] - $i - )*) -} - -if_nightly! { - macro_rules! if_std { - ($($i:item)*) => ($( - #[cfg(feature = "std")] - $i - )*) - } - - extern crate futures_core; - extern crate futures_executor; - - use core::mem::PinMut; - use futures_core::{Future, Stream, Poll, task}; - - if_std! { - extern crate std; - - mod executor; - mod unsafe_pin; - - use std::boxed::PinBox; - - pub use executor::{StableExecutor, block_on_stable}; - use unsafe_pin::UnsafePinMut; - } - - pub trait StableFuture { - type Item; - type Error; - - fn poll(self: PinMut, ctx: &mut task::Context) -> Poll; - - #[cfg(feature = "std")] - fn pin<'a>(self) -> PinBox + Send + 'a> - where Self: Send + Sized + 'a - { - PinBox::new(unsafe { UnsafePinMut::new(self) }) - } - - #[cfg(feature = "std")] - fn pin_local<'a>(self) -> PinBox + 'a> - where Self: Sized + 'a - { - PinBox::new(unsafe { UnsafePinMut::new(self) }) - } - } - - impl StableFuture for F { - type Item = F::Item; - type Error = F::Error; - - fn poll(mut self: PinMut, ctx: &mut task::Context) -> Poll { - F::poll(unsafe { PinMut::get_mut(&mut self) }, ctx) - } - } - - pub trait StableStream { - type Item; - type Error; - - fn poll_next(self: PinMut, ctx: &mut task::Context) -> Poll, Self::Error>; - - #[cfg(feature = "std")] - fn pin<'a>(self) -> PinBox + Send + 'a> - where Self: Send + Sized + 'a - { - PinBox::new(unsafe { UnsafePinMut::new(self) }) - } - - #[cfg(feature = "std")] - fn pin_local<'a>(self) -> PinBox + 'a> - where Self: Sized + 'a - { - PinBox::new(unsafe { UnsafePinMut::new(self) }) - } - } - - impl StableStream for S { - type Item = S::Item; - type Error = S::Error; - - fn poll_next(mut self: PinMut, ctx: &mut task::Context) -> Poll, Self::Error> { - S::poll_next(unsafe { PinMut::get_mut(&mut self) }, ctx) - } - } -} diff --git a/futures-stable/src/unsafe_pin.rs b/futures-stable/src/unsafe_pin.rs deleted file mode 100644 index 8b164eaa38..0000000000 --- a/futures-stable/src/unsafe_pin.rs +++ /dev/null @@ -1,30 +0,0 @@ -use core::mem::PinMut; -use futures_core::{Future, Stream, Poll, task}; - -use {StableFuture, StableStream}; - -pub(crate) struct UnsafePinMut { - inner: T, -} - -impl UnsafePinMut { - pub(crate) unsafe fn new(inner: T) -> UnsafePinMut { - UnsafePinMut { inner } - } -} - -impl<'a, T: StableFuture> Future for UnsafePinMut { - type Item = T::Item; - type Error = T::Error; - fn poll(&mut self, ctx: &mut task::Context) -> Poll { - T::poll(unsafe { PinMut::new_unchecked(&mut self.inner) }, ctx) - } -} - -impl<'a, T: StableStream> Stream for UnsafePinMut { - type Item = T::Item; - type Error = T::Error; - fn poll_next(&mut self, ctx: &mut task::Context) -> Poll, Self::Error> { - T::poll_next(unsafe { PinMut::new_unchecked(&mut self.inner) }, ctx) - } -} From 33d6ba46a63ebc137edf47818997be5ce41d5616 Mon Sep 17 00:00:00 2001 From: tinaun Date: Thu, 7 Jun 2018 16:24:56 -0400 Subject: [PATCH 2/9] stdify Poll --- futures-core/src/executor.rs | 59 +------- futures-core/src/future/mod.rs | 190 +++++++------------------ futures-core/src/lib.rs | 1 + futures-core/src/poll.rs | 62 ++++---- futures-core/src/task/context.rs | 89 ------------ futures-core/src/task/mod.rs | 130 ++++------------- futures-core/src/task/wake.rs | 235 ------------------------------- 7 files changed, 106 insertions(+), 660 deletions(-) delete mode 100644 futures-core/src/task/context.rs delete mode 100644 futures-core/src/task/wake.rs diff --git a/futures-core/src/executor.rs b/futures-core/src/executor.rs index 87af8d8aaa..f505bbc47e 100644 --- a/futures-core/src/executor.rs +++ b/futures-core/src/executor.rs @@ -1,61 +1,4 @@ //! Executors. -use task::TaskObj; +pub use core::task::{Executor, SpawnErrorKind, SpawnObjError}; -/// A task executor. -/// -/// A *task* is a `()`-producing future that runs at the top level, and will -/// be `poll`ed until completion. It's also the unit at which wake-up -/// notifications occur. Executors, such as thread pools, allow tasks to be -/// spawned and are responsible for putting tasks onto ready queues when -/// they are woken up, and polling them when they are ready. -pub trait Executor { - /// Spawn the given task object, polling it until completion. - /// - /// # Errors - /// - /// 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>; - - /// Determine whether the executor is able to spawn new tasks. - /// - /// # Returns - /// - /// An `Ok` return means the executor is *likely* (but not guaranteed) - /// to accept a subsequent spawn attempt. Likewise, an `Err` return - /// means that `spawn` is likely, but not guaranteed, to yield an error. - fn status(&self) -> Result<(), SpawnErrorKind> { - Ok(()) - } - - // TODO: downcasting hooks -} - -/// Provides the reason that an executor was unable to spawn. -#[derive(Debug)] -pub struct SpawnErrorKind { - _a: () -} - -impl SpawnErrorKind { - /// Spawning is failing because the executor has been shut down. - pub fn shutdown() -> SpawnErrorKind { - SpawnErrorKind { _a: () } - } - - /// Check whether this error is the `shutdown` error. - pub fn is_shutdown() -> bool { - true - } -} - -/// The result of a failed spawn -#[derive(Debug)] -pub struct SpawnObjError { - /// The kind of error - pub kind: SpawnErrorKind, - - /// The task for which spawning was attempted - pub task: TaskObj, -} diff --git a/futures-core/src/future/mod.rs b/futures-core/src/future/mod.rs index 854c3be407..b2823933ca 100644 --- a/futures-core/src/future/mod.rs +++ b/futures-core/src/future/mod.rs @@ -12,106 +12,9 @@ pub use self::option::FutureOption; #[cfg(feature = "either")] mod either; -/// A future represents an asychronous computation. -/// -/// A future is a value that may not have finished computing yet. This kind of -/// "asynchronous value" makes it possible for a thread to continue doing useful -/// work while it waits for the value to become available. -/// -/// The ergonomics and implementation of the `Future` trait are very similar to -/// the `Iterator` trait in that there is just one method you need to -/// implement, but you get a whole lot of others for free as a result. These -/// other methods allow you to chain together large computations based on -/// futures, which will automatically handle asynchrony for you. -/// -/// # The `poll` method -/// -/// The core method of future, `poll`, *attempts* to resolve the future into a -/// final value. This method does not block if the value is not ready. Instead, -/// the current task is scheduled to be woken up when it's possible to make -/// further progress by `poll`ing again. The wake up is performed using -/// `cx.waker()`, a handle for waking up the current task. -/// -/// When using a future, you generally won't call `poll` directly, but instead -/// use combinators to build up asynchronous computations. A complete -/// computation can then be spawned onto an -/// [executor](../futures_core/executor/trait.Executor.html) as a new, independent -/// task that will automatically be `poll`ed to completion. -/// -/// # Combinators -/// -/// Like iterators, futures provide a large number of combinators to work with -/// futures to express computations in a much more natural method than -/// scheduling a number of callbacks. As with iterators, the combinators are -/// zero-cost: they compile away. You can find the combinators in the -/// [future-util](https://docs.rs/futures-util) crate. -pub trait Future { - /// The result of the future - type Output; - - /// Attempt to resolve the future to a final value, registering - /// the current task for wakeup if the value is not yet available. - /// - /// # Return value - /// - /// This function returns: - /// - /// - `Poll::Pending` if the future is not ready yet - /// - `Poll::Ready(val)` with the result `val` of this future if it finished - /// successfully. - /// - /// Once a future has finished, clients should not `poll` it again. - /// - /// When a future is not ready yet, `poll` returns - /// [`Poll::Pending`](::Poll). The future will *also* register the - /// interest of the current task in the value being produced. For example, - /// if the future represents the availability of data on a socket, then the - /// task is recorded so that when data arrives, it is woken up (via - /// [`cx.waker()`](::task::Context::waker). Once a task has been woken up, - /// it should attempt to `poll` the future again, which may or may not - /// produce a final value. - /// - /// Note that if `Pending` is returned it only means that the *current* task - /// (represented by the argument `cx`) will receive a notification. Tasks - /// from previous calls to `poll` will *not* receive notifications. - /// - /// # Runtime characteristics - /// - /// Futures alone are *inert*; they must be *actively* `poll`ed to make - /// progress, meaning that each time the current task is woken up, it should - /// actively re-`poll` pending futures that it still has an interest in. - /// Usually this is done by building up a large computation as a single - /// future (using combinators), then spawning that future as a *task* onto - /// an [executor](../futures_core/executor/trait.Executor.html). Executors - /// ensure that each task is `poll`ed every time a future internal to that - /// task is ready to make progress. - /// - /// The `poll` function is not called repeatedly in a tight loop for - /// futures, but only whenever the future itself is ready, as signaled via - /// [`cx.waker()`](::task::Context::waker). If you're familiar with the - /// `poll(2)` or `select(2)` syscalls on Unix it's worth noting that futures - /// typically do *not* suffer the same problems of "all wakeups must poll - /// all events"; they are more like `epoll(4)`. - /// - /// An implementation of `poll` should strive to return quickly, and must - /// *never* block. Returning quickly prevents unnecessarily clogging up - /// threads or event loops. If it is known ahead of time that a call to - /// `poll` may end up taking awhile, the work should be offloaded to a - /// thread pool (or something similar) to ensure that `poll` can return - /// quickly. - /// - /// # Panics - /// - /// Once a future has completed (returned `Ready` from `poll`), - /// then any future calls to `poll` may panic, block forever, or otherwise - /// cause bad behavior. The `Future` trait itself provides no guarantees - /// about the behavior of `poll` after a future has completed. - /// - /// Callers who may call `poll` too many times may want to consider using - /// the `fuse` adaptor which defines the behavior of `poll`, but comes with - /// a little bit of extra cost. - fn poll(self: PinMut, cx: &mut task::Context) -> Poll; +pub use core::future::Future; +pub trait CoreFutureExt: Future { /// A convenience for calling `Future::poll` on `Unpin` future types. fn poll_unpin(&mut self, cx: &mut task::Context) -> Poll where Self: Unpin @@ -119,50 +22,51 @@ pub trait Future { PinMut::new(self).poll(cx) } } - -impl<'a, F: ?Sized + Future + Unpin> Future for &'a mut F { - type Output = F::Output; - - fn poll(mut self: PinMut, cx: &mut task::Context) -> Poll { - F::poll(PinMut::new(&mut **self), cx) - } -} - -impl<'a, F: ?Sized + Future> Future for PinMut<'a, F> { - type Output = F::Output; - - fn poll(mut self: PinMut, cx: &mut task::Context) -> Poll { - F::poll((*self).reborrow(), cx) - } -} - -if_std! { - use std::boxed::{Box, PinBox}; - - impl<'a, F: ?Sized + Future + Unpin> Future for Box { - type Output = F::Output; - - fn poll(mut self: PinMut, cx: &mut task::Context) -> Poll { - (**self).poll_unpin(cx) - } - } - - impl<'a, F: ?Sized + Future> Future for PinBox { - type Output = F::Output; - - fn poll(mut self: PinMut, cx: &mut task::Context) -> Poll { - self.as_pin_mut().poll(cx) - } - } - - impl<'a, F: Future> Future for ::std::panic::AssertUnwindSafe { - type Output = F::Output; - - fn poll(mut self: PinMut, cx: &mut task::Context) -> Poll { - unsafe { pinned_field!(self, 0).poll(cx) } - } - } -} + +// should be in std +// impl<'a, F: ?Sized + Future + Unpin> Future for &'a mut F { +// type Output = F::Output; + +// fn poll(mut self: PinMut, cx: &mut task::Context) -> Poll { +// F::poll(PinMut::new(&mut **self), cx) +// } +// } + +// impl<'a, F: ?Sized + Future> Future for PinMut<'a, F> { +// type Output = F::Output; + +// fn poll(mut self: PinMut, cx: &mut task::Context) -> Poll { +// F::poll((*self).reborrow(), cx) +// } +// } + +// if_std! { +// use std::boxed::{Box, PinBox}; + +// impl<'a, F: ?Sized + Future + Unpin> Future for Box { +// type Output = F::Output; + +// fn poll(mut self: PinMut, cx: &mut task::Context) -> Poll { +// (**self).poll_unpin(cx) +// } +// } + +// impl<'a, F: ?Sized + Future> Future for PinBox { +// type Output = F::Output; + +// fn poll(mut self: PinMut, cx: &mut task::Context) -> Poll { +// self.as_pin_mut().poll(cx) +// } +// } + +// impl<'a, F: Future> Future for ::std::panic::AssertUnwindSafe { +// type Output = F::Output; + +// fn poll(mut self: PinMut, cx: &mut task::Context) -> Poll { +// unsafe { pinned_field!(self, 0).poll(cx) } +// } +// } +// } /// A convenience for futures that return `Result` values that includes /// a variety of adapters tailored to such futures. diff --git a/futures-core/src/lib.rs b/futures-core/src/lib.rs index 04cac38426..546f685772 100644 --- a/futures-core/src/lib.rs +++ b/futures-core/src/lib.rs @@ -1,6 +1,7 @@ //! Core traits and types for asynchronous operations in Rust. #![feature(pin, arbitrary_self_types)] +#![feature(futures_api)] #![no_std] #![deny(missing_docs, missing_debug_implementations, warnings)] diff --git a/futures-core/src/poll.rs b/futures-core/src/poll.rs index 973755825c..a3b74cdb1a 100644 --- a/futures-core/src/poll.rs +++ b/futures-core/src/poll.rs @@ -1,3 +1,6 @@ + +pub use core::task::Poll; + /// A macro for extracting the successful type of a `Poll>`. /// /// This macro bakes in propagation of `Pending` and `Err` signals by returning early. @@ -39,24 +42,21 @@ macro_rules! ready { }) } -/// Indicates whether a value is available, or if the current task has been -/// scheduled for later wake-up instead. -#[derive(Copy, Clone, Debug, PartialEq)] -pub enum Poll { - /// Represents that a value is immediately ready. - Ready(T), - - /// Represents that a value is not ready yet. - /// - /// When a function returns `Pending`, the function *must* also - /// ensure that the current task is scheduled to be awoken when - /// progress can be made. - Pending, +pub trait PollExt { + /// Change the ready value of this `Poll` with the closure provided + fn map(self, f: F) -> Poll + where F: FnOnce(T) -> U; + /// Returns whether this is `Poll::Ready` + fn is_ready(&self) -> bool; + /// Returns whether this is `Poll::Pending` + fn is_pending(&self) -> bool { + !self.is_ready() + } } -impl Poll { - /// Change the ready value of this `Poll` with the closure provided - pub fn map(self, f: F) -> Poll +impl PollExt for Poll { + + fn map(self, f: F) -> Poll where F: FnOnce(T) -> U { match self { @@ -65,23 +65,26 @@ impl Poll { } } - /// Returns whether this is `Poll::Ready` - pub fn is_ready(&self) -> bool { + fn is_ready(&self) -> bool { match *self { Poll::Ready(_) => true, Poll::Pending => false, } } - - /// Returns whether this is `Poll::Pending` - pub fn is_pending(&self) -> bool { - !self.is_ready() - } } -impl Poll> { +pub trait PollResultExt { /// Change the success value of this `Poll` with the closure provided - pub fn map_ok(self, f: F) -> Poll> + fn map_ok(self, f: F) -> Poll> + where F: FnOnce(T) -> U; + /// Change the error value of this `Poll` with the closure provided + fn map_err(self, f: F) -> Poll> + where F: FnOnce(E) -> U; +} + +impl PollResultExt for Poll> { + + fn map_ok(self, f: F) -> Poll> where F: FnOnce(T) -> U { match self { @@ -91,8 +94,7 @@ impl Poll> { } } - /// Change the error value of this `Poll` with the closure provided - pub fn map_err(self, f: F) -> Poll> + fn map_err(self, f: F) -> Poll> where F: FnOnce(E) -> U { match self { @@ -103,8 +105,4 @@ impl Poll> { } } -impl From for Poll { - fn from(t: T) -> Poll { - Poll::Ready(t) - } -} + diff --git a/futures-core/src/task/context.rs b/futures-core/src/task/context.rs deleted file mode 100644 index 5672679cd2..0000000000 --- a/futures-core/src/task/context.rs +++ /dev/null @@ -1,89 +0,0 @@ -use core::fmt; - -use executor::Executor; -use task::{TaskObj, Waker}; - -/// Information about the currently-running task. -/// -/// Contexts are always tied to the stack, since they are set up specifically -/// when performing a single `poll` step on a task. -pub struct Context<'a> { - waker: &'a Waker, - executor: &'a mut Executor, -} - -impl<'a> Context<'a> { - /// Create a new task context. - /// - /// Task contexts are equipped with: - /// - A means of waking the task - /// - A means of spawning new tasks, i.e. an [executor]() - pub fn new(waker: &'a Waker, executor: &'a mut E) -> Context<'a> - where E: Executor - { - Context { waker, executor } - } - - /// Get the default executor associated with this task. - /// - /// This method is useful primarily if you want to explicitly handle - /// spawn failures. - pub fn executor(&mut self) -> &mut Executor { - self.executor - } - - /// Produce a context like the current one, but using the given executor - /// instead. - /// - /// This advanced method is primarily used when building "internal - /// schedulers" within a task. - pub fn with_executor<'b, E>(&'b mut self, executor: &'b mut E) -> Context<'b> - where E: Executor - { - Context { waker: self.waker, executor } - } - - /// Get the [`Waker`](::task::Waker) associated with the current task. - /// - /// The waker can subsequently be used to wake up the task when some - /// event of interest has happened. - pub fn waker(&self) -> &Waker { - self.waker - } - - /// Produce a context like the current one, but using the given waker - /// instead. - /// - /// This advanced method is primarily used when building "internal - /// schedulers" within a task, where you want to provide some customized - /// wakeup logic. - pub fn with_waker<'b>(&'b mut self, waker: &'b Waker) -> Context<'b> { - Context { waker, executor: self.executor } - } -} - -impl<'a> fmt::Debug for Context<'a> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.debug_struct("Context") - .finish() - } -} - -if_std! { - use Future; - - impl<'a> Context<'a> { - /// Spawn a future onto the default executor. - /// - /// # Panics - /// - /// This method will panic if the default executor is unable to spawn. - /// - /// To handle executor errors, use [executor()](self::Context::executor) - /// instead. - pub fn spawn(&mut self, f: F) where F: Future + 'static + Send { - self.executor() - .spawn_obj(TaskObj::new(f)).unwrap() - } - } -} diff --git a/futures-core/src/task/mod.rs b/futures-core/src/task/mod.rs index d584335f61..326053634f 100644 --- a/futures-core/src/task/mod.rs +++ b/futures-core/src/task/mod.rs @@ -1,129 +1,53 @@ //! Task notification. use core::mem::{self, PinMut}; -use core::fmt; use {Future, Poll}; -mod wake; -pub use self::wake::{UnsafeWake, Waker}; +pub use core::task::{UnsafeWake, Waker}; #[cfg(feature = "std")] -pub use self::wake::Wake; +pub use std::task::Wake; -mod context; -pub use self::context::Context; +pub use core::task::Context; #[cfg_attr(feature = "nightly", cfg(target_has_atomic = "ptr"))] mod atomic_waker; #[cfg_attr(feature = "nightly", cfg(target_has_atomic = "ptr"))] pub use self::atomic_waker::AtomicWaker; -/// A custom trait object for polling tasks, roughly akin to -/// `Box + Send>`. -pub struct TaskObj { - ptr: *mut (), - poll: unsafe fn(*mut (), &mut Context) -> Poll<()>, - drop: unsafe fn(*mut ()), -} - -impl fmt::Debug for TaskObj { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.debug_struct("TakObj") - .finish() - } -} - -unsafe impl Send for TaskObj {} -unsafe impl Sync for TaskObj {} - -/// 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 UnsafePoll: Send + '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 ()); -} - -impl TaskObj { - /// Create a `TaskObj` from a custom trait object representation. - pub fn from_poll_task(t: T) -> TaskObj { - TaskObj { - ptr: t.into_raw(), - poll: T::poll, - drop: T::drop, - } - } - - /// Poll the task. - /// - /// The semantics here are identical to that for futures, but unlike - /// futures only an `&mut self` reference is needed here. - pub fn poll_task(&mut self, cx: &mut Context) -> Poll<()> { - unsafe { - (self.poll)(self.ptr, cx) - } - } -} - -impl Drop for TaskObj { - fn drop(&mut self) { - unsafe { - (self.drop)(self.ptr) - } - } -} +pub use core::task::{TaskObj, UnsafePoll}; if_std! { use std::boxed::Box; - unsafe impl + Send + 'static> UnsafePoll for Box { - fn into_raw(self) -> *mut () { - unsafe { - mem::transmute(self) - } - } + pub trait TaskObjExt { + /// Create a new `TaskObj` by boxing the given future. + fn new + Send + 'static>(f: F) -> TaskObj; + } - unsafe fn poll(task: *mut (), cx: &mut Context) -> Poll<()> { - let ptr: *mut F = mem::transmute(task); - let pin: PinMut = PinMut::new_unchecked(&mut *ptr); - pin.poll(cx) + impl TaskObjExt for TaskObj { + /// Create a new `TaskObj` by boxing the given future. + fn new + Send + 'static>(f: F) -> TaskObj { + TaskObj::from_poll_task(Box::new(f)) } + } - unsafe fn drop(task: *mut ()) { - let ptr: *mut F = mem::transmute(task); - let boxed = Box::from_raw(ptr); - drop(boxed) - } + pub trait ContextExt { + /// Spawn a future onto the default executor. + /// + /// # Panics + /// + /// This method will panic if the default executor is unable to spawn. + /// + /// To handle executor errors, use [executor()](self::Context::executor) + /// instead. + fn spawn(&mut self, f: F) where F: Future + 'static + Send; } - impl TaskObj { - /// Create a new `TaskObj` by boxing the given future. - pub fn new + Send + 'static>(f: F) -> TaskObj { - TaskObj::from_poll_task(Box::new(f)) + impl<'a> ContextExt for Context<'a> { + fn spawn(&mut self, f: F) where F: Future + 'static + Send { + self.executor() + .spawn_obj(TaskObj::new(f)).unwrap() } } } diff --git a/futures-core/src/task/wake.rs b/futures-core/src/task/wake.rs deleted file mode 100644 index 0be3f36e7c..0000000000 --- a/futures-core/src/task/wake.rs +++ /dev/null @@ -1,235 +0,0 @@ -use core::fmt; - -/// An unsafe trait for implementing custom memory management for a -/// [`Waker`](::task::Waker). -/// -/// A [`Waker`](::task::Waker) is a cloneable trait object for `Wake`, and is -/// most often essentially just `Arc`. However, in some contexts -/// (particularly `no_std`), it's desirable to avoid `Arc` in favor of some -/// custom memory management strategy. This trait is designed to allow for such -/// customization. -/// -/// A default implementation of the `UnsafeWake` trait is provided for the -/// `Arc` type in the standard library. If the `std` feature of this crate -/// is not available however, you'll be required to implement your own -/// instance of this trait to pass it into `Waker::new`. -/// -/// # Unsafety -/// -/// This trait manually encodes the memory management of the underlying trait -/// object. Implementors of this trait must guarantee: -/// -/// * Calls to `clone_raw` produce uniquely owned `Waker` handles. These handles -/// should be independently usable and droppable. -/// -/// * Calls to `drop_raw` work with `self` as a raw pointer, deallocating -/// resources associated with it. This is a pretty unsafe operation as it's -/// invalidating the `self` pointer, so extreme care needs to be taken. -/// -/// In general it's recommended to review the trait documentation as well as the -/// implementation for `Arc` in this crate before attempting a custom -/// implementation. -pub unsafe trait UnsafeWake { - /// Creates a new `Waker` from this instance of `UnsafeWake`. - /// - /// This function will create a new uniquely owned handle that under the - /// hood references the same notification instance. In other words calls - /// to `wake` on the returned handle should be equivalent to calls to - /// `wake` on this handle. - /// - /// # Unsafety - /// - /// This is also unsafe to call because it's asserting the `UnsafeWake` - /// value is in a consistent state, i.e. hasn't been dropped. - unsafe fn clone_raw(&self) -> Waker; - - /// Drops this instance of `UnsafeWake`, deallocating resources - /// associated with it. - /// - /// This method is intended to have a signature such as: - /// - /// ```ignore - /// fn drop_raw(self: *mut Self); - /// ``` - /// - /// Unfortunately in Rust today that signature is not object safe. - /// Nevertheless it's recommended to implement this function *as if* that - /// were its signature. As such it is not safe to call on an invalid - /// pointer, nor is the validity of the pointer guaranteed after this - /// function returns. - /// - /// # Unsafety - /// - /// This is also unsafe to call because it's asserting the `UnsafeWake` - /// value is in a consistent state, i.e. hasn't been dropped - unsafe fn drop_raw(&self); - - /// Indicates that the associated task is ready to make progress and should - /// be `poll`ed. - /// - /// Executors generally maintain a queue of "ready" tasks; `wake` should place - /// the associated task onto this queue. - /// - /// # Panics - /// - /// Implementations should avoid panicking, but clients should also be prepared - /// for panics. - /// - /// # Unsafety - /// - /// This is also unsafe to call because it's asserting the `UnsafeWake` - /// value is in a consistent state, i.e. hasn't been dropped - unsafe fn wake(&self); -} - -/// A `Waker` is a handle for waking up a task by notifying its executor that it -/// is ready to be run. -/// -/// This handle contains a trait object pointing to an instance of the `Wake` -/// trait, allowing notifications to get routed through it. Usually `Waker` -/// instances are provided by an executor. -/// -/// If you're implementing an executor, the recommended way to create a `Waker` -/// is via `Waker::from` applied to an `Arc` value where `T: Wake`. The -/// unsafe `new` constructor should be used only in niche, `no_std` settings. -pub struct Waker { - inner: *const UnsafeWake, -} - -unsafe impl Send for Waker {} -unsafe impl Sync for Waker {} - -impl Waker { - /// Constructs a new `Waker` directly. - /// - /// Note that most code will not need to call this. Implementers of the - /// `UnsafeWake` trait will typically provide a wrapper that calls this - /// but you otherwise shouldn't call it directly. - /// - /// If you're working with the standard library then it's recommended to - /// use the `Waker::from` function instead which works with the safe - /// `Arc` type and the safe `Wake` trait. - #[inline] - pub unsafe fn new(inner: *const UnsafeWake) -> Waker { - Waker { inner: inner } - } - - /// Wake up the task associated with this `Waker`. - pub fn wake(&self) { - unsafe { (*self.inner).wake() } - } - - /// Returns whether or not this `Waker` and `other` awaken the same task. - /// - /// This function works on a best-effort basis, and may return false even - /// when the `Waker`s would awaken the same task. However, if this function - /// returns true, it is guaranteed that the `Waker`s will awaken the same - /// task. - /// - /// This function is primarily used for optimization purposes. - pub fn will_wake(&self, other: &Waker) -> bool { - self.inner == other.inner - } -} - -impl Clone for Waker { - #[inline] - fn clone(&self) -> Self { - unsafe { - (*self.inner).clone_raw() - } - } -} - -impl fmt::Debug for Waker { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.debug_struct("Waker") - .finish() - } -} - -impl Drop for Waker { - fn drop(&mut self) { - unsafe { - (*self.inner).drop_raw() - } - } -} - -if_std! { - use std::mem; - use std::ptr; - use std::sync::Arc; - use core::marker::PhantomData; - - /// A way of waking up a specific task. - /// - /// Any task executor must provide a way of signaling that a task it owns - /// is ready to be `poll`ed again. Executors do so by implementing this trait. - /// - /// Note that, rather than working directly with `Wake` trait objects, this - /// library instead uses a custom [`Waker`](::task::Waker) to allow for - /// customization of memory management. - pub trait Wake: Send + Sync { - /// Indicates that the associated task is ready to make progress and should - /// be `poll`ed. - /// - /// Executors generally maintain a queue of "ready" tasks; `wake` should place - /// the associated task onto this queue. - /// - /// # Panics - /// - /// Implementations should avoid panicking, but clients should also be prepared - /// for panics. - fn wake(arc_self: &Arc); - } - - // Safe implementation of `UnsafeWake` for `Arc` in the standard library. - // - // Note that this is a very unsafe implementation! The crucial pieces is that - // these two values are considered equivalent: - // - // * Arc - // * *const ArcWrapped - // - // We don't actually know the layout of `ArcWrapped` as it's an - // implementation detail in the standard library. We can work, though, by - // casting it through and back an `Arc`. - // - // This also means that you won't actually find `UnsafeWake for Arc` - // because it's the wrong level of indirection. These methods are sort of - // receiving Arc, but not an owned version. It's... complicated. We may be - // one of the first users of unsafe trait objects! - - struct ArcWrapped(PhantomData); - - unsafe impl UnsafeWake for ArcWrapped { - unsafe fn clone_raw(&self) -> Waker { - let me: *const ArcWrapped = self; - let arc = (*(&me as *const *const ArcWrapped as *const Arc)).clone(); - Waker::from(arc) - } - - unsafe fn drop_raw(&self) { - let mut me: *const ArcWrapped = self; - let me = &mut me as *mut *const ArcWrapped as *mut Arc; - ptr::drop_in_place(me); - } - - unsafe fn wake(&self) { - let me: *const ArcWrapped = self; - T::wake(&*(&me as *const *const ArcWrapped as *const Arc)) - } - } - - impl From> for Waker - where T: Wake + 'static, - { - fn from(rc: Arc) -> Waker { - unsafe { - let ptr = mem::transmute::, *const ArcWrapped>(rc); - Waker::new(ptr) - } - } - } -} From c533b88f2bcbd8ab74d194bf7a844f63892aa72e Mon Sep 17 00:00:00 2001 From: tinaun Date: Fri, 8 Jun 2018 23:18:02 -0400 Subject: [PATCH 3/9] remove PollExt, add methods to std --- futures-core/src/poll.rs | 65 ---------------------------------------- 1 file changed, 65 deletions(-) diff --git a/futures-core/src/poll.rs b/futures-core/src/poll.rs index a3b74cdb1a..47bbcee62d 100644 --- a/futures-core/src/poll.rs +++ b/futures-core/src/poll.rs @@ -41,68 +41,3 @@ macro_rules! ready { $crate::Poll::Pending => return $crate::Poll::Pending, }) } - -pub trait PollExt { - /// Change the ready value of this `Poll` with the closure provided - fn map(self, f: F) -> Poll - where F: FnOnce(T) -> U; - /// Returns whether this is `Poll::Ready` - fn is_ready(&self) -> bool; - /// Returns whether this is `Poll::Pending` - fn is_pending(&self) -> bool { - !self.is_ready() - } -} - -impl PollExt for Poll { - - fn map(self, f: F) -> Poll - where F: FnOnce(T) -> U - { - match self { - Poll::Ready(t) => Poll::Ready(f(t)), - Poll::Pending => Poll::Pending, - } - } - - fn is_ready(&self) -> bool { - match *self { - Poll::Ready(_) => true, - Poll::Pending => false, - } - } -} - -pub trait PollResultExt { - /// Change the success value of this `Poll` with the closure provided - fn map_ok(self, f: F) -> Poll> - where F: FnOnce(T) -> U; - /// Change the error value of this `Poll` with the closure provided - fn map_err(self, f: F) -> Poll> - where F: FnOnce(E) -> U; -} - -impl PollResultExt for Poll> { - - fn map_ok(self, f: F) -> Poll> - where F: FnOnce(T) -> U - { - match self { - Poll::Ready(Ok(t)) => Poll::Ready(Ok(f(t))), - Poll::Ready(Err(e)) => Poll::Ready(Err(e)), - Poll::Pending => Poll::Pending, - } - } - - fn map_err(self, f: F) -> Poll> - where F: FnOnce(E) -> U - { - match self { - Poll::Ready(Ok(t)) => Poll::Ready(Ok(t)), - Poll::Ready(Err(e)) => Poll::Ready(Err(f(e))), - Poll::Pending => Poll::Pending, - } - } -} - - From 785feed24bdc3cdc6de584b3ded6fd6da08d28d6 Mon Sep 17 00:00:00 2001 From: tinaun Date: Tue, 12 Jun 2018 03:15:40 -0400 Subject: [PATCH 4/9] fix imports, add comments --- futures-core/src/future/either.rs | 30 +++++++++++++++--------------- futures-core/src/future/mod.rs | 3 +++ futures-core/src/task/mod.rs | 10 +++++----- 3 files changed, 23 insertions(+), 20 deletions(-) diff --git a/futures-core/src/future/either.rs b/futures-core/src/future/either.rs index f8d0feea59..20c694b736 100644 --- a/futures-core/src/future/either.rs +++ b/futures-core/src/future/either.rs @@ -1,24 +1,24 @@ -use {task, Future, Stream, Poll}; +use {task, Stream, Poll}; use core::mem::PinMut; use either::Either; -impl Future for Either - where A: Future, - B: Future -{ - type Output = A::Output; +// impl Future for Either +// where A: Future, +// B: Future +// { +// type Output = A::Output; - fn poll(self: PinMut, cx: &mut task::Context) -> Poll { - unsafe { - match PinMut::get_mut(self) { - Either::Left(a) => PinMut::new_unchecked(a).poll(cx), - Either::Right(b) => PinMut::new_unchecked(b).poll(cx), - } - } - } -} +// fn poll(self: PinMut, cx: &mut task::Context) -> Poll { +// unsafe { +// match PinMut::get_mut(self) { +// Either::Left(a) => PinMut::new_unchecked(a).poll(cx), +// Either::Right(b) => PinMut::new_unchecked(b).poll(cx), +// } +// } +// } +// } impl Stream for Either where A: Stream, diff --git a/futures-core/src/future/mod.rs b/futures-core/src/future/mod.rs index b2823933ca..6cdd226c66 100644 --- a/futures-core/src/future/mod.rs +++ b/futures-core/src/future/mod.rs @@ -14,6 +14,7 @@ mod either; pub use core::future::Future; +/// Will probably merge with futures_util::FutureExt pub trait CoreFutureExt: Future { /// A convenience for calling `Future::poll` on `Unpin` future types. fn poll_unpin(&mut self, cx: &mut task::Context) -> Poll @@ -22,6 +23,8 @@ pub trait CoreFutureExt: Future { PinMut::new(self).poll(cx) } } + +impl CoreFutureExt for T where T: Future {} // should be in std // impl<'a, F: ?Sized + Future + Unpin> Future for &'a mut F { diff --git a/futures-core/src/task/mod.rs b/futures-core/src/task/mod.rs index 326053634f..8063eff786 100644 --- a/futures-core/src/task/mod.rs +++ b/futures-core/src/task/mod.rs @@ -1,8 +1,6 @@ //! Task notification. -use core::mem::{self, PinMut}; - -use {Future, Poll}; +use Future; pub use core::task::{UnsafeWake, Waker}; #[cfg(feature = "std")] @@ -18,8 +16,9 @@ pub use self::atomic_waker::AtomicWaker; pub use core::task::{TaskObj, UnsafePoll}; if_std! { - use std::boxed::Box; + use std::boxed::PinBox; + /// Extension trait for `TaskObj`, adding methods that require allocation. pub trait TaskObjExt { /// Create a new `TaskObj` by boxing the given future. fn new + Send + 'static>(f: F) -> TaskObj; @@ -28,10 +27,11 @@ if_std! { impl TaskObjExt for TaskObj { /// Create a new `TaskObj` by boxing the given future. fn new + Send + 'static>(f: F) -> TaskObj { - TaskObj::from_poll_task(Box::new(f)) + TaskObj::from_poll_task(PinBox::new(f)) } } + /// Extension trait for `Context`, adding methods that require allocation. pub trait ContextExt { /// Spawn a future onto the default executor. /// From 7f4b87a258008238d6874553f48a4cb9084eca10 Mon Sep 17 00:00:00 2001 From: tinaun Date: Sat, 9 Jun 2018 00:32:37 -0400 Subject: [PATCH 5/9] stdify futures-channel --- futures-channel/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/futures-channel/src/lib.rs b/futures-channel/src/lib.rs index 7fdf3eb739..5a9cedfc81 100644 --- a/futures-channel/src/lib.rs +++ b/futures-channel/src/lib.rs @@ -3,7 +3,7 @@ //! This crate provides channels that can be used to communicate between //! asynchronous tasks. -#![feature(pin, arbitrary_self_types)] +#![feature(pin, arbitrary_self_types, futures_api)] #![deny(missing_docs, missing_debug_implementations)] #![doc(html_root_url = "https://docs.rs/futures-channel/0.2.0")] From b832ebbe568a17bf86e293b60b034508a65ff6d1 Mon Sep 17 00:00:00 2001 From: tinaun Date: Sat, 9 Jun 2018 00:33:01 -0400 Subject: [PATCH 6/9] stdify futures-io --- futures-io/src/lib.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/futures-io/src/lib.rs b/futures-io/src/lib.rs index b5b8dc6864..9e3dc68561 100644 --- a/futures-io/src/lib.rs +++ b/futures-io/src/lib.rs @@ -8,6 +8,8 @@ #![deny(missing_docs, missing_debug_implementations)] #![doc(html_rnoot_url = "https://docs.rs/futures-io/0.2.0")] +#![feature(futures_api)] + macro_rules! if_std { ($($i:item)*) => ($( #[cfg(feature = "std")] From 1cca462ba956fdc3f06de1e78417c41e7371a7ad Mon Sep 17 00:00:00 2001 From: tinaun Date: Sat, 9 Jun 2018 00:33:25 -0400 Subject: [PATCH 7/9] stdify futures-sink --- futures-sink/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/futures-sink/src/lib.rs b/futures-sink/src/lib.rs index d29660776c..ea3cf03814 100644 --- a/futures-sink/src/lib.rs +++ b/futures-sink/src/lib.rs @@ -7,7 +7,7 @@ #![deny(missing_docs, missing_debug_implementations)] #![doc(html_root_url = "https://docs.rs/futures-sink/0.2.0")] -#![feature(pin, arbitrary_self_types)] +#![feature(pin, arbitrary_self_types, futures_api)] #[cfg(feature = "std")] extern crate std; From 88af39e757993835aed481169b14a19021e09a6e Mon Sep 17 00:00:00 2001 From: tinaun Date: Sat, 9 Jun 2018 00:33:53 -0400 Subject: [PATCH 8/9] stdify futures-util --- futures-util/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/futures-util/src/lib.rs b/futures-util/src/lib.rs index cb32a94538..3ee8b38801 100644 --- a/futures-util/src/lib.rs +++ b/futures-util/src/lib.rs @@ -1,7 +1,7 @@ //! Combinators and utilities for working with `Future`s, `Stream`s, `Sink`s, //! and the `AsyncRead` and `AsyncWrite` traits. -#![feature(pin, arbitrary_self_types)] +#![feature(pin, arbitrary_self_types, futures_api)] #![no_std] #![deny(missing_docs, missing_debug_implementations, warnings)] From adbe9f9247d50ebfc35be0ed5943b87f2f305bef Mon Sep 17 00:00:00 2001 From: tinaun Date: Wed, 13 Jun 2018 00:34:02 -0400 Subject: [PATCH 9/9] remove taskobjext --- futures-core/src/future/mod.rs | 45 ---------------------------------- futures-core/src/task/mod.rs | 17 ++----------- 2 files changed, 2 insertions(+), 60 deletions(-) diff --git a/futures-core/src/future/mod.rs b/futures-core/src/future/mod.rs index 6cdd226c66..8b12a9b46c 100644 --- a/futures-core/src/future/mod.rs +++ b/futures-core/src/future/mod.rs @@ -26,51 +26,6 @@ pub trait CoreFutureExt: Future { impl CoreFutureExt for T where T: Future {} -// should be in std -// impl<'a, F: ?Sized + Future + Unpin> Future for &'a mut F { -// type Output = F::Output; - -// fn poll(mut self: PinMut, cx: &mut task::Context) -> Poll { -// F::poll(PinMut::new(&mut **self), cx) -// } -// } - -// impl<'a, F: ?Sized + Future> Future for PinMut<'a, F> { -// type Output = F::Output; - -// fn poll(mut self: PinMut, cx: &mut task::Context) -> Poll { -// F::poll((*self).reborrow(), cx) -// } -// } - -// if_std! { -// use std::boxed::{Box, PinBox}; - -// impl<'a, F: ?Sized + Future + Unpin> Future for Box { -// type Output = F::Output; - -// fn poll(mut self: PinMut, cx: &mut task::Context) -> Poll { -// (**self).poll_unpin(cx) -// } -// } - -// impl<'a, F: ?Sized + Future> Future for PinBox { -// type Output = F::Output; - -// fn poll(mut self: PinMut, cx: &mut task::Context) -> Poll { -// self.as_pin_mut().poll(cx) -// } -// } - -// impl<'a, F: Future> Future for ::std::panic::AssertUnwindSafe { -// type Output = F::Output; - -// fn poll(mut self: PinMut, cx: &mut task::Context) -> Poll { -// unsafe { pinned_field!(self, 0).poll(cx) } -// } -// } -// } - /// A convenience for futures that return `Result` values that includes /// a variety of adapters tailored to such futures. pub trait TryFuture { diff --git a/futures-core/src/task/mod.rs b/futures-core/src/task/mod.rs index 8063eff786..557c174d7c 100644 --- a/futures-core/src/task/mod.rs +++ b/futures-core/src/task/mod.rs @@ -13,24 +13,11 @@ mod atomic_waker; #[cfg_attr(feature = "nightly", cfg(target_has_atomic = "ptr"))] pub use self::atomic_waker::AtomicWaker; -pub use core::task::{TaskObj, UnsafePoll}; +pub use core::task::{TaskObj, UnsafeTask}; if_std! { use std::boxed::PinBox; - /// Extension trait for `TaskObj`, adding methods that require allocation. - pub trait TaskObjExt { - /// Create a new `TaskObj` by boxing the given future. - fn new + Send + 'static>(f: F) -> TaskObj; - } - - impl TaskObjExt for TaskObj { - /// Create a new `TaskObj` by boxing the given future. - fn new + Send + 'static>(f: F) -> TaskObj { - TaskObj::from_poll_task(PinBox::new(f)) - } - } - /// Extension trait for `Context`, adding methods that require allocation. pub trait ContextExt { /// Spawn a future onto the default executor. @@ -47,7 +34,7 @@ if_std! { impl<'a> ContextExt for Context<'a> { fn spawn(&mut self, f: F) where F: Future + 'static + Send { self.executor() - .spawn_obj(TaskObj::new(f)).unwrap() + .spawn_obj(TaskObj::new(PinBox::new(f))).unwrap() } } }