Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

port futures 0.3 to std futures #1034

Merged
merged 9 commits into from
Jun 19, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,5 @@ members = [
# "futures-macro-async",
# "futures-macro-await",
"futures-sink",
# "futures-stable",
"futures-util",
]
2 changes: 1 addition & 1 deletion futures-channel/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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")]
Expand Down
59 changes: 1 addition & 58 deletions futures-core/src/executor.rs
Original file line number Diff line number Diff line change
@@ -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,
}
30 changes: 15 additions & 15 deletions futures-core/src/future/either.rs
Original file line number Diff line number Diff line change
@@ -1,24 +1,24 @@
use {task, Future, Stream, Poll};
use {task, Stream, Poll};

use core::mem::PinMut;

use either::Either;

impl<A, B> Future for Either<A, B>
where A: Future,
B: Future<Output = A::Output>
{
type Output = A::Output;
// impl<A, B> Future for Either<A, B>
// where A: Future,
// B: Future<Output = A::Output>
// {
// type Output = A::Output;

fn poll(self: PinMut<Self>, cx: &mut task::Context) -> Poll<A::Output> {
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<Self>, cx: &mut task::Context) -> Poll<A::Output> {
// unsafe {
// match PinMut::get_mut(self) {
// Either::Left(a) => PinMut::new_unchecked(a).poll(cx),
// Either::Right(b) => PinMut::new_unchecked(b).poll(cx),
// }
// }
// }
// }
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why was this removed?

Copy link
Contributor Author

@tinaun tinaun Jun 12, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

since either is defined in https://github.com/bluss/either and Future in std it can't exist here because of orphan rules - i might write a pr moving this to the either crate as an unstable feature

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd gently suggest removing the commented code, if it is, in fact, going away


impl<A, B> Stream for Either<A, B>
where A: Stream,
Expand Down
148 changes: 5 additions & 143 deletions futures-core/src/future/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,106 +12,10 @@ 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<Self>, cx: &mut task::Context) -> Poll<Self::Output>;
pub use core::future::Future;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎉


/// 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<Self::Output>
where Self: Unpin
Expand All @@ -120,50 +24,8 @@ pub trait Future {
}
}

impl<'a, F: ?Sized + Future + Unpin> Future for &'a mut F {
type Output = F::Output;

fn poll(mut self: PinMut<Self>, cx: &mut task::Context) -> Poll<Self::Output> {
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<Self>, cx: &mut task::Context) -> Poll<Self::Output> {
F::poll((*self).reborrow(), cx)
}
}

if_std! {
use std::boxed::{Box, PinBox};

impl<'a, F: ?Sized + Future + Unpin> Future for Box<F> {
type Output = F::Output;

fn poll(mut self: PinMut<Self>, cx: &mut task::Context) -> Poll<Self::Output> {
(**self).poll_unpin(cx)
}
}

impl<'a, F: ?Sized + Future> Future for PinBox<F> {
type Output = F::Output;

fn poll(mut self: PinMut<Self>, cx: &mut task::Context) -> Poll<Self::Output> {
self.as_pin_mut().poll(cx)
}
}

impl<'a, F: Future> Future for ::std::panic::AssertUnwindSafe<F> {
type Output = F::Output;

fn poll(mut self: PinMut<Self>, cx: &mut task::Context) -> Poll<Self::Output> {
unsafe { pinned_field!(self, 0).poll(cx) }
}
}
}

impl<T: ?Sized> CoreFutureExt for T where T: Future {}

/// A convenience for futures that return `Result` values that includes
/// a variety of adapters tailored to such futures.
pub trait TryFuture {
Expand Down
1 change: 1 addition & 0 deletions futures-core/src/lib.rs
Original file line number Diff line number Diff line change
@@ -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)]
Expand Down
73 changes: 3 additions & 70 deletions futures-core/src/poll.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@

pub use core::task::Poll;

/// A macro for extracting the successful type of a `Poll<Result<T, E>>`.
///
/// This macro bakes in propagation of `Pending` and `Err` signals by returning early.
Expand Down Expand Up @@ -38,73 +41,3 @@ macro_rules! ready {
$crate::Poll::Pending => return $crate::Poll::Pending,
})
}

/// 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<T> {
/// 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,
}

impl<T> Poll<T> {
/// Change the ready value of this `Poll` with the closure provided
pub fn map<U, F>(self, f: F) -> Poll<U>
where F: FnOnce(T) -> U
{
match self {
Poll::Ready(t) => Poll::Ready(f(t)),
Poll::Pending => Poll::Pending,
}
}

/// Returns whether this is `Poll::Ready`
pub 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<T, E> Poll<Result<T, E>> {
/// Change the success value of this `Poll` with the closure provided
pub fn map_ok<U, F>(self, f: F) -> Poll<Result<U, E>>
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,
}
}

/// Change the error value of this `Poll` with the closure provided
pub fn map_err<U, F>(self, f: F) -> Poll<Result<T, U>>
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,
}
}
}

impl<T> From<T> for Poll<T> {
fn from(t: T) -> Poll<T> {
Poll::Ready(t)
}
}
Loading