From 3116c359cbc399685ba7d63b2c527b83a859485f Mon Sep 17 00:00:00 2001 From: Aaron Turon Date: Tue, 24 Apr 2018 20:07:00 -0700 Subject: [PATCH 1/7] Bring futures-core in line with the new plan --- futures-core/src/async_trait/either.rs | 20 +++ futures-core/src/async_trait/mod.rs | 183 +++++++++++++++++++++++++ futures-core/src/future/either.rs | 32 ++--- futures-core/src/future/mod.rs | 114 ++++++++------- futures-core/src/future/option.rs | 28 ++-- futures-core/src/future/result.rs | 77 +++++++++++ futures-core/src/lib.rs | 10 +- futures-core/src/never.rs | 39 ++++++ futures-core/src/poll.rs | 3 + futures-core/src/stream/mod.rs | 83 ++++++----- futures-core/src/task/context.rs | 9 +- futures-core/src/task/mod.rs | 12 +- 12 files changed, 483 insertions(+), 127 deletions(-) create mode 100644 futures-core/src/async_trait/either.rs create mode 100644 futures-core/src/async_trait/mod.rs create mode 100644 futures-core/src/future/result.rs create mode 100644 futures-core/src/never.rs diff --git a/futures-core/src/async_trait/either.rs b/futures-core/src/async_trait/either.rs new file mode 100644 index 0000000000..6c5b697e96 --- /dev/null +++ b/futures-core/src/async_trait/either.rs @@ -0,0 +1,20 @@ +use {task, Async, Poll}; + +use core::mem::Pin; +use either::Either; + +impl Async for Either + where A: Async, + B: Async +{ + type Output = A::Output; + + fn poll(mut self: Pin, cx: &mut task::Context) -> Poll { + unsafe { + match *(Pin::get_mut(&mut self)) { + Either::Left(ref mut a) => Pin::new_unchecked(a).poll(cx), + Either::Right(ref mut b) => Pin::new_unchecked(b).poll(cx), + } + } + } +} diff --git a/futures-core/src/async_trait/mod.rs b/futures-core/src/async_trait/mod.rs new file mode 100644 index 0000000000..078aa3f09b --- /dev/null +++ b/futures-core/src/async_trait/mod.rs @@ -0,0 +1,183 @@ +//! Asynchronous values. + +use core::mem::Pin; +use core::marker::Unpin; + +use {Poll, task}; + +#[cfg(feature = "either")] +mod either; + +/// An `Async` value represents an asychronous computation. +/// +/// An `Asyn` 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 `Async` 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 +/// async values, which will automatically handle asynchrony for you. +/// +/// # The `poll` method +/// +/// The core method of `Async`, `poll`, *attempts* to resolve the computation 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 an async value, 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, async values 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 Async { + /// The result of the async computation + type Output; + + /// Attempt to resolve the computation 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 value is not ready yet + /// - `Poll::Ready(val)` with the result `val` on completion + /// + /// Once the computation has completed, clients should not `poll` it again. + /// + /// When an async value is not ready yet, `poll` returns + /// [`Poll::Pending`](::Poll). Polling will will *also* register the + /// interest of the current task in the value being produced. For example, + /// if the computation 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 async value 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 + /// + /// Async values 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 computations that it still has an interest in. + /// Usually this is done by building up a large computation as a single + /// async value (using combinators), then spawning that computation as a + /// *task* onto an + /// [executor](../futures_core/executor/trait.Executor.html). Executors + /// ensure that each task is `poll`ed every time a computation internal to + /// that task is ready to make progress. + /// + /// The `poll` function is not called repeatedly in a tight loop, but only + /// whenever the async computation is ready to make progress, 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 computation has completed (returned `Ready` from `poll`), + /// then any future calls to `poll` may panic, block forever, or otherwise + /// cause bad behavior. The `Async` trait itself provides no guarantees + /// about the behavior of `poll` after an `Async` 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: Pin, cx: &mut task::Context) -> Poll; +} + +impl<'a, F: ?Sized + Async> Async for &'a mut F { + type Output = F::Output; + + fn poll(mut self: Pin, cx: &mut task::Context) -> Poll { + unsafe { pinned_deref!(self).poll(cx) } + } +} + +if_std! { + use std::boxed::{Box, PinBox}; + + impl<'a, F: ?Sized + Async> Async for Box { + type Output = F::Output; + + fn poll(mut self: Pin, cx: &mut task::Context) -> Poll { + unsafe { pinned_deref!(self).poll(cx) } + } + } + + impl<'a, F: ?Sized + Async> Async for PinBox { + type Output = F::Output; + + fn poll(mut self: Pin, cx: &mut task::Context) -> Poll { + unsafe { + let this = PinBox::get_mut(Pin::get_mut(&mut self)); + let re_pinned = Pin::new_unchecked(this); + re_pinned.poll(cx) + } + } + } + + impl<'a, F: Async> Async for ::std::panic::AssertUnwindSafe { + type Output = F::Output; + + fn poll(mut self: Pin, cx: &mut task::Context) -> Poll { + unsafe { pinned_field!(self, 0).poll(cx) } + } + } +} + +/// An immediately-ready async value +#[derive(Debug, Clone)] +#[must_use = "async values do nothing unless polled"] +pub struct Ready(Option); + +unsafe impl Unpin for Ready {} + +impl Async for Ready { + type Output = T; + + fn poll(mut self: Pin, _cx: &mut task::Context) -> Poll { + Poll::Ready(self.0.take().unwrap()) + } +} + +/// Create an immediately-ready async value. +pub fn ready(t: T) -> Ready { + Ready(Some(t)) +} + +impl Async for Option { + type Output = Option; + + fn poll(mut self: Pin, cx: &mut task::Context) -> Poll { + unsafe { + match Pin::get_mut(&mut self) { + None => Poll::Ready(None), + Some(ref mut x) => Pin::new_unchecked(x).poll(cx).map(Some), + } + } + } +} diff --git a/futures-core/src/future/either.rs b/futures-core/src/future/either.rs index 5266de4b83..65ca80017b 100644 --- a/futures-core/src/future/either.rs +++ b/futures-core/src/future/either.rs @@ -1,37 +1,33 @@ -use {task, Future, Stream, Poll}; - -use core::mem::Pin; +use {task, Future, PollResult, Stream}; use either::Either; impl Future for Either where A: Future, - B: Future + B: Future { - type Output = A::Output; + type Item = A::Item; + type Error = A::Error; - fn poll(mut self: Pin, cx: &mut task::Context) -> Poll { - unsafe { - match *(Pin::get_mut(&mut self)) { - Either::Left(ref mut a) => Pin::new_unchecked(a).poll(cx), - Either::Right(ref mut b) => Pin::new_unchecked(b).poll(cx), - } + fn poll(&mut self, cx: &mut task::Context) -> PollResult { + match *self { + Either::Left(ref mut a) => a.poll(cx), + Either::Right(ref mut b) => b.poll(cx), } } } impl Stream for Either where A: Stream, - B: Stream + B: Stream { type Item = A::Item; + type Error = A::Error; - fn poll_next(mut self: Pin, cx: &mut task::Context) -> Poll> { - unsafe { - match *(Pin::get_mut(&mut self)) { - Either::Left(ref mut a) => Pin::new_unchecked(a).poll_next(cx), - Either::Right(ref mut b) => Pin::new_unchecked(b).poll_next(cx), - } + fn poll_next(&mut self, cx: &mut task::Context) -> PollResult, A::Error> { + match *self { + Either::Left(ref mut a) => a.poll_next(cx), + Either::Right(ref mut b) => b.poll_next(cx), } } } diff --git a/futures-core/src/future/mod.rs b/futures-core/src/future/mod.rs index 7920a3164c..6ce9362971 100644 --- a/futures-core/src/future/mod.rs +++ b/futures-core/src/future/mod.rs @@ -1,22 +1,20 @@ //! Futures. -use core::mem::Pin; -use core::marker::Unpin; - -use Poll; -use task; +use {PollResult, task}; mod option; pub use self::option::FutureOption; - +#[path = "result.rs"] +mod result_; +pub use self::result_::{result, ok, err, FutureResult}; #[cfg(feature = "either")] mod either; -/// A future represents an asychronous computation. +/// A future represents an asychronous computation that may fail. /// -/// 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. +/// A future is like a `Result` 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 @@ -46,8 +44,11 @@ mod either; /// 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; + /// A successful value + type Item; + + /// An error + type Error; /// Attempt to resolve the future to a final value, registering /// the current task for wakeup if the value is not yet available. @@ -57,8 +58,7 @@ pub trait Future { /// 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. + /// - `Poll::Ready(res)` with the result `res` of this future. /// /// Once a future has finished, clients should not `poll` it again. /// @@ -100,9 +100,15 @@ pub trait Future { /// thread pool (or something similar) to ensure that `poll` can return /// quickly. /// + /// # Errors + /// + /// This future may have failed to finish the computation, in which case + /// the `Err` variant will be returned with an appropriate payload of an + /// error. + /// /// # Panics /// - /// Once a future has completed (returned `Ready` from `poll`), + /// Once a future has completed (returned `Ready` or `Err` 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. @@ -110,65 +116,67 @@ pub trait Future { /// 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: Pin, cx: &mut task::Context) -> Poll; + fn poll(&mut self, cx: &mut task::Context) -> PollResult; } impl<'a, F: ?Sized + Future> Future for &'a mut F { - type Output = F::Output; + type Item = F::Item; + type Error = F::Error; - fn poll(mut self: Pin, cx: &mut task::Context) -> Poll { - unsafe { pinned_deref!(self).poll(cx) } + fn poll(&mut self, cx: &mut task::Context) -> PollResult { + (**self).poll(cx) } } if_std! { - use std::boxed::{Box, PinBox}; - - impl<'a, F: ?Sized + Future> Future for Box { - type Output = F::Output; + impl Future for ::std::boxed::Box { + type Item = F::Item; + type Error = F::Error; - fn poll(mut self: Pin, cx: &mut task::Context) -> Poll { - unsafe { pinned_deref!(self).poll(cx) } + fn poll(&mut self, cx: &mut task::Context) -> PollResult { + (**self).poll(cx) } } - impl<'a, F: ?Sized + Future> Future for PinBox { - type Output = F::Output; + #[cfg(feature = "nightly")] + impl Future for ::std::boxed::PinBox { + type Item = F::Item; + type Error = F::Error; - fn poll(mut self: Pin, cx: &mut task::Context) -> Poll { - unsafe { - let this = PinBox::get_mut(Pin::get_mut(&mut self)); - let re_pinned = Pin::new_unchecked(this); - re_pinned.poll(cx) - } + fn poll(&mut self, cx: &mut task::Context) -> PollResult { + unsafe { ::core::mem::Pin::get_mut(&mut self.as_pin()).poll(cx) } } } - impl<'a, F: Future> Future for ::std::panic::AssertUnwindSafe { - type Output = F::Output; + impl Future for ::std::panic::AssertUnwindSafe { + type Item = F::Item; + type Error = F::Error; - fn poll(mut self: Pin, cx: &mut task::Context) -> Poll { - unsafe { pinned_field!(self, 0).poll(cx) } + fn poll(&mut self, cx: &mut task::Context) -> PollResult { + self.0.poll(cx) } } } -/// A future that is immediately ready with a value -#[derive(Debug, Clone)] -#[must_use = "futures do nothing unless polled"] -pub struct ReadyFuture(Option); - -unsafe impl Unpin for ReadyFuture {} - -impl Future for ReadyFuture { - type Output = T; - - fn poll(mut self: Pin, _cx: &mut task::Context) -> Poll { - Poll::Ready(self.0.take().unwrap()) - } +/// Types that can be converted into a future. +/// +/// This trait is very similar to the `IntoIterator` trait. +pub trait IntoFuture { + /// The future that this type can be converted into. + type Future: Future; + + /// The item that the future may resolve with. + type Item; + /// The error that the future may resolve with. + type Error; + + /// Consumes this object and produces a future. + fn into_future(self) -> Self::Future; } -/// Create a future that is immediately ready with a value. -pub fn ready(t: T) -> ReadyFuture { - ReadyFuture(Some(t)) +impl IntoFuture for F where F: Future { + type Future = Self; + type Item = ::Item; + type Error = ::Error; + fn into_future(self) -> Self { self } } diff --git a/futures-core/src/future/option.rs b/futures-core/src/future/option.rs index b4d82cfa61..a3db90ad5e 100644 --- a/futures-core/src/future/option.rs +++ b/futures-core/src/future/option.rs @@ -1,8 +1,7 @@ //! Definition of the `Option` (optional step) combinator -use {Future, Poll}; +use {Future, IntoFuture, Poll, PollResult}; use task; -use core::mem::Pin; /// A future representing a value which may or may not be present. /// @@ -13,15 +12,24 @@ pub struct FutureOption { inner: Option, } -impl Future for FutureOption { - type Output = Option; +impl IntoFuture for Option where T: IntoFuture { + type Future = FutureOption; + type Item = Option; + type Error = T::Error; - fn poll(mut self: Pin, cx: &mut task::Context) -> Poll { - unsafe { - match Pin::get_mut(&mut self).inner { - None => Poll::Ready(None), - Some(ref mut x) => Pin::new_unchecked(x).poll(cx).map(Some), - } + fn into_future(self) -> FutureOption { + FutureOption { inner: self.map(IntoFuture::into_future) } + } +} + +impl Future for FutureOption where F: Future { + type Item = Option; + type Error = E; + + fn poll(&mut self, cx: &mut task::Context) -> PollResult, E> { + match self.inner { + None => Poll::Ready(Ok(None)), + Some(ref mut x) => x.poll(cx).map(|x| x.map(Some)), } } } diff --git a/futures-core/src/future/result.rs b/futures-core/src/future/result.rs new file mode 100644 index 0000000000..46819e9672 --- /dev/null +++ b/futures-core/src/future/result.rs @@ -0,0 +1,77 @@ +use {Future, IntoFuture, Poll, PollResult}; +use task; + +/// A future representing a value that is immediately ready. +/// +/// Created by the [`result`](::future::result), [`ok`](::future::ok) or +/// [`err`](::future::err) functions. +#[derive(Debug, Clone)] +#[must_use = "futures do nothing unless polled"] +pub struct FutureResult { + inner: Option>, +} + +impl IntoFuture for Result { + type Future = FutureResult; + type Item = T; + type Error = E; + + fn into_future(self) -> Self::Future { + result(self) + } +} + +/// Creates a new future that will immediate resolve with the given result. +/// +/// # Examples +/// +/// ``` +/// use futures_core::future::*; +/// +/// let future_of_1 = result::(Ok(1)); +/// let future_of_err_2 = result::(Err(2)); +/// ``` +pub fn result(r: Result) -> FutureResult { + FutureResult { inner: Some(r) } +} + +/// Creates a new future that will immediately resolve successfully to the given value. +/// +/// # Examples +/// +/// ``` +/// use futures_core::future::*; +/// +/// let future_of_1 = ok::(1); +/// ``` +pub fn ok(t: T) -> FutureResult { + result(Ok(t)) +} + +/// Creates a new future that will immediately fail with the given error. +/// +/// # Examples +/// +/// ``` +/// use futures_core::future::*; +/// +/// let future_of_err_1 = err::(1); +/// ``` +pub fn err(e: E) -> FutureResult { + result(Err(e)) +} + +impl Future for FutureResult { + type Item = T; + type Error = E; + + fn poll(&mut self, _: &mut task::Context) -> PollResult { + Poll::Ready(self.inner.take().expect("cannot poll Result twice")) + } +} + +impl From> for FutureResult { + fn from(r: Result) -> Self { + result(r) + } +} diff --git a/futures-core/src/lib.rs b/futures-core/src/lib.rs index 78ef6e54bf..239f9c98a9 100644 --- a/futures-core/src/lib.rs +++ b/futures-core/src/lib.rs @@ -41,10 +41,13 @@ macro_rules! pinned_field { } mod poll; -pub use poll::Poll; +pub use poll::{Poll, PollResult}; pub mod future; -pub use future::Future; +pub use future::{Future, IntoFuture}; + +mod async_trait; +pub use async_trait::{Async, Ready, ready}; pub mod stream; pub use stream::Stream; @@ -52,3 +55,6 @@ pub use stream::Stream; pub mod task; pub mod executor; + +pub mod never; +pub use never::Never; diff --git a/futures-core/src/never.rs b/futures-core/src/never.rs new file mode 100644 index 0000000000..39893af9fe --- /dev/null +++ b/futures-core/src/never.rs @@ -0,0 +1,39 @@ +//! Definition and trait implementations for the `Never` type, +//! a stand-in for the `!` type until it becomes stable. + +use {Future, Stream, PollResult}; +use task; + +/// A type with no possible values. +/// +/// This is used to indicate values which can never be created, such as the +/// error type of infallible futures. +/// +/// This type is a stable equivalent to the `!` type from `std`. +#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)] +pub enum Never {} + +impl Never { + /// Convert the `Never` type into any other type. + pub fn never_into(self) -> T { + match self {} + } +} + +impl Future for Never { + type Item = Never; + type Error = Never; + + fn poll(&mut self, _: &mut task::Context) -> PollResult { + match *self {} + } +} + +impl Stream for Never { + type Item = Never; + type Error = Never; + + fn poll_next(&mut self, _: &mut task::Context) -> PollResult, Never> { + match *self {} + } +} diff --git a/futures-core/src/poll.rs b/futures-core/src/poll.rs index 4f6ed1636c..1dfcfa884e 100644 --- a/futures-core/src/poll.rs +++ b/futures-core/src/poll.rs @@ -43,3 +43,6 @@ impl From for Poll { Poll::Ready(t) } } + +/// Shorthand for a `Poll>` value. +pub type PollResult = Poll>; diff --git a/futures-core/src/stream/mod.rs b/futures-core/src/stream/mod.rs index 86fb30ee99..7d7d283570 100644 --- a/futures-core/src/stream/mod.rs +++ b/futures-core/src/stream/mod.rs @@ -1,24 +1,32 @@ //! Asynchronous streams. -use core::mem::Pin; - -use Poll; -use task; +use {Poll, PollResult, task}; /// A stream of values produced asynchronously. /// -/// If `Future` is an asynchronous version of `T`, then `Stream` is an asynchronous version of `Iterator`. A stream -/// represents a sequence of value-producing events that occur asynchronously to -/// the caller. +/// If `Future` is an asynchronous version of `Result`, then `Stream` is an +/// asynchronous version of `Iterator`. A stream represents a sequence of +/// value-producing events that occur asynchronously to the caller. /// /// The trait is modeled after `Future`, but allows `poll_next` to be called /// even after a value has been produced, yielding `None` once the stream has /// been fully exhausted. +/// +/// # Errors +/// +/// Streams, like futures, also bake in errors through an associated `Error` +/// type. An error on a stream **does not terminate the stream**. That is, +/// after one error is received, another value may be received from the same +/// stream (it's valid to keep polling). Thus a stream is somewhat like an +/// `Iterator>`, and is always terminated by returning +/// `None`. pub trait Stream { /// Values yielded by the stream. type Item; + /// Errors yielded by the stream. + type Error; + /// Attempt to pull out the next value of this stream, registering the /// current task for wakeup if the value is not yet available, and returning /// `None` if the stream is exhausted. @@ -28,71 +36,76 @@ pub trait Stream { /// There are several possible return values, each indicating a distinct /// stream state: /// - /// - [`Pending`](::Poll) means that this stream's next value is not ready - /// yet. Implementations will ensure that the current task will be notified - /// when the next value may be ready. + /// - [`Ok(Pending)`](::Async) means that this stream's next value is not + /// ready yet. Implementations will ensure that the current task will be + /// notified when the next value may be ready. /// - /// - [`Ready(Some(val))`](::Poll) means that the stream has successfully - /// produced a value, `val`, and may produce further values on subsequent - /// `poll_next` calls. + /// - [`Ok(Ready(Some(val)))`](::Async) means that the stream has + /// successfully produced a value, `val`, and may produce further values + /// on subsequent `poll_next` calls. /// - /// - [`Ready(None)`](::Poll) means that the stream has terminated, and + /// - [`Ok(Ready(None))`](::Async) means that the stream has terminated, and /// `poll_next` should not be invoked again. /// + /// - `Err(err)` means that the stream encountered an error while trying to + /// `poll_next`. Subsequent calls to `poll_next` *are* allowed, and may + /// return further values or errors. + /// /// # Panics /// /// Once a stream is finished, i.e. `Ready(None)` has been returned, further /// calls to `poll_next` may result in a panic or other "bad behavior". If this /// is difficult to guard against then the `fuse` adapter can be used to /// ensure that `poll_next` always returns `Ready(None)` in subsequent calls. - fn poll_next(self: Pin, cx: &mut task::Context) -> Poll>; + fn poll_next(&mut self, cx: &mut task::Context) -> PollResult, Self::Error>; } impl<'a, S: ?Sized + Stream> Stream for &'a mut S { type Item = S::Item; + type Error = S::Error; - fn poll_next(mut self: Pin, cx: &mut task::Context) -> Poll> { - unsafe { pinned_deref!(self).poll_next(cx) } + fn poll_next(&mut self, cx: &mut task::Context) -> PollResult, Self::Error> { + (**self).poll_next(cx) } } if_std! { - use std::boxed::{Box, PinBox}; - use std::marker::Unpin; + use never::Never; - impl Stream for Box { + impl Stream for ::std::boxed::Box { type Item = S::Item; + type Error = S::Error; - fn poll_next(mut self: Pin, cx: &mut task::Context) -> Poll> { - unsafe { pinned_deref!(self).poll_next(cx) } + fn poll_next(&mut self, cx: &mut task::Context) -> PollResult, Self::Error> { + (**self).poll_next(cx) } } - impl Stream for PinBox { + #[cfg(feature = "nightly")] + impl Stream for ::std::boxed::PinBox { type Item = S::Item; + type Error = S::Error; - fn poll_next(mut self: Pin, cx: &mut task::Context) -> Poll> { - unsafe { - let this = PinBox::get_mut(Pin::get_mut(&mut self)); - let re_pinned = Pin::new_unchecked(this); - re_pinned.poll_next(cx) - } + fn poll_next(&mut self, cx: &mut task::Context) -> PollResult, Self::Error> { + unsafe { ::core::mem::Pin::get_mut(&mut self.as_pin()).poll_next(cx) } } } impl Stream for ::std::panic::AssertUnwindSafe { type Item = S::Item; + type Error = S::Error; - fn poll_next(mut self: Pin, cx: &mut task::Context) -> Poll> { - unsafe { pinned_field!(self, 0).poll_next(cx) } + fn poll_next(&mut self, cx: &mut task::Context) -> PollResult, S::Error> { + self.0.poll_next(cx) } } - impl Stream for ::std::collections::VecDeque { + impl Stream for ::std::collections::VecDeque { type Item = T; + type Error = Never; - fn poll_next(mut self: Pin, _cx: &mut task::Context) -> Poll> { - Poll::Ready(self.pop_front()) + fn poll_next(&mut self, _cx: &mut task::Context) -> PollResult, Self::Error> { + Poll::Ready(Ok(self.pop_front())) } } } diff --git a/futures-core/src/task/context.rs b/futures-core/src/task/context.rs index 5672679cd2..2b9203ea3a 100644 --- a/futures-core/src/task/context.rs +++ b/futures-core/src/task/context.rs @@ -1,7 +1,7 @@ use core::fmt; use executor::Executor; -use task::{TaskObj, Waker}; +use task::Waker; /// Information about the currently-running task. /// @@ -70,10 +70,11 @@ impl<'a> fmt::Debug for Context<'a> { } if_std! { - use Future; + use task::TaskObj; + use Async; impl<'a> Context<'a> { - /// Spawn a future onto the default executor. + /// Spawn an async computation onto the default executor. /// /// # Panics /// @@ -81,7 +82,7 @@ if_std! { /// /// To handle executor errors, use [executor()](self::Context::executor) /// instead. - pub fn spawn(&mut self, f: F) where F: Future + 'static + Send { + pub fn spawn(&mut self, f: A) where A: Async + '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 825e6462ee..5c3f3b3ba3 100644 --- a/futures-core/src/task/mod.rs +++ b/futures-core/src/task/mod.rs @@ -1,9 +1,8 @@ //! Task notification. -use core::mem::{self, Pin}; use core::fmt; -use {Future, Poll}; +use Poll; mod wake; pub use self::wake::{UnsafeWake, Waker}; @@ -98,9 +97,12 @@ impl Drop for TaskObj { } if_std! { + use Async; + + use core::mem::{self, Pin}; use std::boxed::Box; - unsafe impl + Send + 'static> UnsafePoll for Box { + unsafe impl + Send + 'static> UnsafePoll for Box { fn into_raw(self) -> *mut () { unsafe { mem::transmute(self) @@ -121,8 +123,8 @@ if_std! { } impl TaskObj { - /// Create a new `TaskObj` by boxing the given future. - pub fn new + Send + 'static>(f: F) -> TaskObj { + /// Create a new `TaskObj` by boxing + pub fn new + Send + 'static>(f: F) -> TaskObj { TaskObj::from_poll_task(Box::new(f)) } } From eca734b30f8e854147c50ce1ce26df53889465ef Mon Sep 17 00:00:00 2001 From: Aaron Turon Date: Tue, 24 Apr 2018 20:15:11 -0700 Subject: [PATCH 2/7] Bring futures-channel up to date with new RFC --- futures-channel/src/mpsc/mod.rs | 15 ++++++++------- futures-channel/src/oneshot.rs | 13 +++++++++++-- 2 files changed, 19 insertions(+), 9 deletions(-) diff --git a/futures-channel/src/mpsc/mod.rs b/futures-channel/src/mpsc/mod.rs index 5d65d2ea80..613620443c 100644 --- a/futures-channel/src/mpsc/mod.rs +++ b/futures-channel/src/mpsc/mod.rs @@ -74,7 +74,6 @@ // happens-before semantics required for the acquire / release semantics used // by the queue structure. -use std::mem::Pin; use std::marker::Unpin; use std::fmt; use std::error::Error; @@ -86,7 +85,7 @@ use std::thread; use std::usize; use futures_core::task::{self, Waker}; -use futures_core::{Poll, Stream}; +use futures_core::{Poll, PollResult, Stream, Never}; use mpsc::queue::{Queue, PopResult}; @@ -947,8 +946,9 @@ impl Receiver { impl Stream for Receiver { type Item = T; + type Error = Never; - fn poll_next(mut self: Pin, cx: &mut task::Context) -> Poll> { + fn poll_next(&mut self, cx: &mut task::Context) -> PollResult, Never> { loop { // Try to read a message off of the message queue. let msg = match self.next_message() { @@ -966,7 +966,7 @@ impl Stream for Receiver { TryPark::Closed => { // The channel is closed, there will be no further // messages. - return Poll::Ready(None); + return Poll::Ready(Ok(None)); } TryPark::NotEmpty => { // A message has been sent while attempting to @@ -978,7 +978,7 @@ impl Stream for Receiver { } }; // Return the message - return Poll::Ready(msg); + return Poll::Ready(Ok(msg)); } } } @@ -1014,9 +1014,10 @@ impl UnboundedReceiver { impl Stream for UnboundedReceiver { type Item = T; + type Error = Never; - fn poll_next(mut self: Pin, cx: &mut task::Context) -> Poll> { - Pin::new(&mut self.0).poll_next(cx) + fn poll_next(&mut self, cx: &mut task::Context) -> PollResult, Never> { + self.0.poll_next(cx) } } diff --git a/futures-channel/src/oneshot.rs b/futures-channel/src/oneshot.rs index 54d39152c6..19e85c5e7b 100644 --- a/futures-channel/src/oneshot.rs +++ b/futures-channel/src/oneshot.rs @@ -7,7 +7,7 @@ use std::sync::atomic::Ordering::SeqCst; use std::error::Error; use std::fmt; -use futures_core::{Future, Poll}; +use futures_core::{Async, Future, Poll, PollResult}; use futures_core::task::{self, Waker}; use lock::Lock; @@ -419,7 +419,7 @@ impl Receiver { } } -impl Future for Receiver { +impl Async for Receiver { type Output = Result; fn poll(self: Pin, cx: &mut task::Context) -> Poll> { @@ -427,6 +427,15 @@ impl Future for Receiver { } } +impl Future for Receiver { + type Item = T; + type Error = Canceled; + + fn poll(&mut self, cx: &mut task::Context) -> PollResult { + self.inner.recv(cx) + } +} + impl Drop for Receiver { fn drop(&mut self) { self.inner.drop_rx() From 67d08ffc73e2db8687da3a117bae0148cd5b254f Mon Sep 17 00:00:00 2001 From: Aaron Turon Date: Tue, 24 Apr 2018 20:20:06 -0700 Subject: [PATCH 3/7] Add AsyncResult trait --- futures-core/src/async_trait/mod.rs | 29 ++++++++++++++++++++++++++++- futures-core/src/lib.rs | 2 +- 2 files changed, 29 insertions(+), 2 deletions(-) diff --git a/futures-core/src/async_trait/mod.rs b/futures-core/src/async_trait/mod.rs index 078aa3f09b..2100ac9d53 100644 --- a/futures-core/src/async_trait/mod.rs +++ b/futures-core/src/async_trait/mod.rs @@ -3,7 +3,7 @@ use core::mem::Pin; use core::marker::Unpin; -use {Poll, task}; +use {Poll, PollResult, task}; #[cfg(feature = "either")] mod either; @@ -181,3 +181,30 @@ impl Async for Option { } } } + +/// A convenience for async `Result`s. +pub trait AsyncResult { + /// The type of successful values + type Item; + + /// The type of failures + type Error; + + /// Poll this `AsyncResult` as if it were an `Async`. + /// + /// This method is a stopgap for a compiler limitation that prevents us from + /// directly inheriting from the `Async` trait; in the future it won't be + /// needed. + fn poll(self: Pin, cx: &mut task::Context) -> PollResult; +} + +impl AsyncResult for F + where F: Async> +{ + type Item = T; + type Error = E; + + fn poll(self: Pin, cx: &mut task::Context) -> Poll { + self.poll(cx) + } +} diff --git a/futures-core/src/lib.rs b/futures-core/src/lib.rs index 239f9c98a9..5c68fa385c 100644 --- a/futures-core/src/lib.rs +++ b/futures-core/src/lib.rs @@ -47,7 +47,7 @@ pub mod future; pub use future::{Future, IntoFuture}; mod async_trait; -pub use async_trait::{Async, Ready, ready}; +pub use async_trait::{Async, AsyncResult, Ready, ready}; pub mod stream; pub use stream::Stream; From 1a3565fb0d7c5a9bb29c13d4a6f3437908dc86d5 Mon Sep 17 00:00:00 2001 From: Aaron Turon Date: Tue, 24 Apr 2018 20:30:59 -0700 Subject: [PATCH 4/7] Update Async{Result} combinators --- .../and_then.rs | 18 +- .../err_into.rs | 14 +- .../src/{future => async_result}/join.rs | 58 +++--- .../src/{future => async_result}/join_all.rs | 18 +- .../map_err.rs | 14 +- .../{future_result => async_result}/map_ok.rs | 14 +- .../{future_result => async_result}/mod.rs | 100 ++++------ .../or_else.rs | 18 +- .../recover.rs | 12 +- .../src/{future => async_result}/select.rs | 10 +- .../{future => async_result}/select_all.rs | 14 +- .../src/{future => async_result}/select_ok.rs | 12 +- .../{future => async_trait}/catch_unwind.rs | 14 +- .../src/{future => async_trait}/chain.rs | 6 +- .../src/{future => async_trait}/empty.rs | 4 +- .../src/{future => async_trait}/flatten.rs | 26 +-- .../{future => async_trait}/flatten_sink.rs | 22 +-- .../src/{future => async_trait}/fuse.rs | 10 +- .../src/{future => async_trait}/inspect.rs | 12 +- futures-util/src/async_trait/join.rs | 176 ++++++++++++++++++ futures-util/src/async_trait/join_all.rs | 145 +++++++++++++++ .../src/{future => async_trait}/lazy.rs | 4 +- .../src/{future => async_trait}/map.rs | 14 +- .../src/{future => async_trait}/mod.rs | 151 +++++---------- .../src/{future => async_trait}/poll_fn.rs | 4 +- futures-util/src/async_trait/select.rs | 41 ++++ futures-util/src/async_trait/select_all.rs | 72 +++++++ futures-util/src/async_trait/select_ok.rs | 82 ++++++++ .../src/{future => async_trait}/shared.rs | 28 +-- .../src/{future => async_trait}/then.rs | 18 +- .../{future => async_trait}/with_executor.rs | 14 +- futures-util/src/future/flatten_stream.rs | 81 -------- futures-util/src/future/into_stream.rs | 40 ---- futures-util/src/lib.rs | 14 +- 34 files changed, 791 insertions(+), 489 deletions(-) rename futures-util/src/{future_result => async_result}/and_then.rs (85%) rename futures-util/src/{future_result => async_result}/err_into.rs (66%) rename futures-util/src/{future => async_result}/join.rs (71%) rename futures-util/src/{future => async_result}/join_all.rs (90%) rename futures-util/src/{future_result => async_result}/map_err.rs (70%) rename futures-util/src/{future_result => async_result}/map_ok.rs (70%) rename futures-util/src/{future_result => async_result}/mod.rs (81%) rename futures-util/src/{future_result => async_result}/or_else.rs (85%) rename futures-util/src/{future_result => async_result}/recover.rs (74%) rename futures-util/src/{future => async_result}/select.rs (78%) rename futures-util/src/{future => async_result}/select_all.rs (84%) rename futures-util/src/{future => async_result}/select_ok.rs (88%) rename futures-util/src/{future => async_trait}/catch_unwind.rs (70%) rename futures-util/src/{future => async_trait}/chain.rs (95%) rename futures-util/src/{future => async_trait}/empty.rs (91%) rename futures-util/src/{future => async_trait}/flatten.rs (55%) rename futures-util/src/{future => async_trait}/flatten_sink.rs (74%) rename futures-util/src/{future => async_trait}/fuse.rs (87%) rename futures-util/src/{future => async_trait}/inspect.rs (79%) create mode 100644 futures-util/src/async_trait/join.rs create mode 100644 futures-util/src/async_trait/join_all.rs rename futures-util/src/{future => async_trait}/lazy.rs (94%) rename futures-util/src/{future => async_trait}/map.rs (72%) rename futures-util/src/{future => async_trait}/mod.rs (79%) rename futures-util/src/{future => async_trait}/poll_fn.rs (94%) create mode 100644 futures-util/src/async_trait/select.rs create mode 100644 futures-util/src/async_trait/select_all.rs create mode 100644 futures-util/src/async_trait/select_ok.rs rename futures-util/src/{future => async_trait}/shared.rs (94%) rename futures-util/src/{future => async_trait}/then.rs (62%) rename futures-util/src/{future => async_trait}/with_executor.rs (69%) delete mode 100644 futures-util/src/future/flatten_stream.rs delete mode 100644 futures-util/src/future/into_stream.rs diff --git a/futures-util/src/future_result/and_then.rs b/futures-util/src/async_result/and_then.rs similarity index 85% rename from futures-util/src/future_result/and_then.rs rename to futures-util/src/async_result/and_then.rs index 86d2d3c785..610fece96d 100644 --- a/futures-util/src/future_result/and_then.rs +++ b/futures-util/src/async_result/and_then.rs @@ -1,14 +1,14 @@ use core::mem::Pin; -use futures_core::{Future, Poll}; +use futures_core::{Async, Poll}; use futures_core::task; -use FutureResult; +use futures_core::AsyncResult; -/// Future for the `and_then` combinator, chaining a computation onto the end of +/// Async for the `and_then` combinator, chaining a computation onto the end of /// another future which completes successfully. /// -/// This is created by the `Future::and_then` method. +/// This is created by the `Async::and_then` method. #[derive(Debug)] #[must_use = "futures do nothing unless polled"] pub struct AndThen { @@ -27,9 +27,9 @@ pub fn new(future: A, f: F) -> AndThen { } } -impl Future for AndThen - where A: FutureResult, - B: FutureResult, +impl Async for AndThen + where A: AsyncResult, + B: AsyncResult, F: FnOnce(A::Item) -> B, { type Output = Result; @@ -41,7 +41,7 @@ impl Future for AndThen State::First(ref mut fut1, ref mut data) => { // safe to create a new `Pin` because `fut1` will never move // before it's dropped. - match unsafe { Pin::new_unchecked(fut1) }.poll_result(cx) { + match unsafe { Pin::new_unchecked(fut1) }.poll(cx) { Poll::Pending => return Poll::Pending, Poll::Ready(Err(e)) => return Poll::Ready(Err(e)), Poll::Ready(Ok(v)) => { @@ -53,7 +53,7 @@ impl Future for AndThen // safe to create a new `Pin` because `fut2` will never move // before it's dropped; once we're in `Chain::Second` we stay // there forever. - return unsafe { Pin::new_unchecked(fut2) }.poll_result(cx) + return unsafe { Pin::new_unchecked(fut2) }.poll(cx) } }; diff --git a/futures-util/src/future_result/err_into.rs b/futures-util/src/async_result/err_into.rs similarity index 66% rename from futures-util/src/future_result/err_into.rs rename to futures-util/src/async_result/err_into.rs index cdb57a0899..c201e66ce5 100644 --- a/futures-util/src/future_result/err_into.rs +++ b/futures-util/src/async_result/err_into.rs @@ -1,14 +1,14 @@ use core::mem::Pin; use core::marker::PhantomData; -use futures_core::{Future, Poll}; +use futures_core::{Async, Poll}; use futures_core::task; -use FutureResult; +use futures_core::AsyncResult; -/// Future for the `err_into` combinator, changing the error type of a future. +/// Async for the `err_into` combinator, changing the error type of a future. /// -/// This is created by the `Future::err_into` method. +/// This is created by the `Async::err_into` method. #[derive(Debug)] #[must_use = "futures do nothing unless polled"] pub struct ErrInto { @@ -23,14 +23,14 @@ pub fn new(future: A) -> ErrInto { } } -impl Future for ErrInto - where A: FutureResult, +impl Async for ErrInto + where A: AsyncResult, A::Error: Into, { type Output = Result; fn poll(mut self: Pin, cx: &mut task::Context) -> Poll { - match unsafe { pinned_field!(self, future) }.poll_result(cx) { + match unsafe { pinned_field!(self, future) }.poll(cx) { Poll::Pending => return Poll::Pending, Poll::Ready(e) => { Poll::Ready(e.map_err(Into::into)) diff --git a/futures-util/src/future/join.rs b/futures-util/src/async_result/join.rs similarity index 71% rename from futures-util/src/future/join.rs rename to futures-util/src/async_result/join.rs index e32470c26a..684eebf183 100644 --- a/futures-util/src/future/join.rs +++ b/futures-util/src/async_result/join.rs @@ -3,7 +3,7 @@ use core::fmt; use core::mem; -use futures_core::{Future, Poll, Async}; +use futures_core::{Async, Poll, Async}; use futures_core::task; macro_rules! generate { @@ -14,18 +14,18 @@ macro_rules! generate { $(#[$doc])* #[must_use = "futures do nothing unless polled"] pub struct $Join - where A: Future, - $($B: Future),* + where A: Async, + $($B: Async),* { a: MaybeDone, $($B: MaybeDone<$B>,)* } impl fmt::Debug for $Join - where A: Future + fmt::Debug, + where A: Async + fmt::Debug, A::Item: fmt::Debug, $( - $B: Future + fmt::Debug, + $B: Async + fmt::Debug, $B::Item: fmt::Debug ),* { @@ -38,8 +38,8 @@ macro_rules! generate { } pub fn $new(a: A, $($B: $B),*) -> $Join - where A: Future, - $($B: Future),* + where A: Async, + $($B: Async),* { $Join { a: MaybeDone::NotYet(a), @@ -48,8 +48,8 @@ macro_rules! generate { } impl $Join - where A: Future, - $($B: Future),* + where A: Async, + $($B: Async),* { fn erase(&mut self) { self.a = MaybeDone::Gone; @@ -57,9 +57,9 @@ macro_rules! generate { } } - impl Future for $Join - where A: Future, - $($B: Future),* + impl Async for $Join + where A: Async, + $($B: Async),* { type Item = (A::Item, $($B::Item),*); type Error = A::Error; @@ -92,22 +92,22 @@ macro_rules! generate { // Incoherent-- add to futures-core when stable. /* - impl IntoFuture for (A, $($B),*) - where A: IntoFuture, + impl IntoAsync for (A, $($B),*) + where A: IntoAsync, $( - $B: IntoFuture + $B: IntoAsync ),* { - type Future = $Join; + type Async = $Join; type Item = (A::Item, $($B::Item),*); type Error = A::Error; - fn into_future(self) -> Self::Future { + fn into_future(self) -> Self::Async { match self { (a, $($B),+) => { $new( - IntoFuture::into_future(a), - $(IntoFuture::into_future($B)),+ + IntoAsync::into_future(a), + $(IntoAsync::into_future($B)),+ ) } } @@ -119,39 +119,39 @@ macro_rules! generate { } generate! { - /// Future for the `join` combinator, waiting for two futures to + /// Async for the `join` combinator, waiting for two futures to /// complete. /// - /// This is created by the `Future::join` method. + /// This is created by the `Async::join` method. (Join, new, ), - /// Future for the `join3` combinator, waiting for three futures to + /// Async for the `join3` combinator, waiting for three futures to /// complete. /// - /// This is created by the `Future::join3` method. + /// This is created by the `Async::join3` method. (Join3, new3, ), - /// Future for the `join4` combinator, waiting for four futures to + /// Async for the `join4` combinator, waiting for four futures to /// complete. /// - /// This is created by the `Future::join4` method. + /// This is created by the `Async::join4` method. (Join4, new4, ), - /// Future for the `join5` combinator, waiting for five futures to + /// Async for the `join5` combinator, waiting for five futures to /// complete. /// - /// This is created by the `Future::join5` method. + /// This is created by the `Async::join5` method. (Join5, new5, ), } #[derive(Debug)] -enum MaybeDone { +enum MaybeDone { NotYet(A), Done(A::Item), Gone, } -impl MaybeDone { +impl MaybeDone { fn poll(&mut self, cx: &mut task::Context) -> Result { let res = match *self { MaybeDone::NotYet(ref mut a) => a.poll(cx)?, diff --git a/futures-util/src/future/join_all.rs b/futures-util/src/async_result/join_all.rs similarity index 90% rename from futures-util/src/future/join_all.rs rename to futures-util/src/async_result/join_all.rs index e6c20ffdd6..1d5e7dd55e 100644 --- a/futures-util/src/future/join_all.rs +++ b/futures-util/src/async_result/join_all.rs @@ -7,11 +7,11 @@ use std::fmt; use std::mem; use std::iter::FromIterator; -use futures_core::{Future, IntoFuture, Poll, Async}; +use futures_core::{Async, IntoAsync, Poll, Async}; use futures_core::task; #[derive(Debug)] -enum ElemState where F: Future { +enum ElemState where F: Async { Pending(F), Done(F::Item), } @@ -22,13 +22,13 @@ enum ElemState where F: Future { /// This future is created with the `join_all` method. #[must_use = "futures do nothing unless polled"] pub struct JoinAll - where F: Future, + where F: Async, { elems: Vec>, } impl fmt::Debug for JoinAll - where F: Future + fmt::Debug, + where F: Async + fmt::Debug, F::Item: fmt::Debug, { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { @@ -77,9 +77,9 @@ impl fmt::Debug for JoinAll /// }); /// # } /// ``` -pub fn join_all(i: I) -> JoinAll<::Future> +pub fn join_all(i: I) -> JoinAll<::Async> where I: IntoIterator, - I::Item: IntoFuture, + I::Item: IntoAsync, { let elems = i.into_iter().map(|f| { ElemState::Pending(f.into_future()) @@ -87,8 +87,8 @@ pub fn join_all(i: I) -> JoinAll<::Future> JoinAll { elems } } -impl Future for JoinAll - where F: Future, +impl Async for JoinAll + where F: Async, { type Item = Vec; type Error = F::Error; @@ -138,7 +138,7 @@ impl Future for JoinAll } } -impl FromIterator for JoinAll { +impl FromIterator for JoinAll { fn from_iter>(iter: T) -> Self { join_all(iter) } diff --git a/futures-util/src/future_result/map_err.rs b/futures-util/src/async_result/map_err.rs similarity index 70% rename from futures-util/src/future_result/map_err.rs rename to futures-util/src/async_result/map_err.rs index 229ce9dd8b..6fdcf22a30 100644 --- a/futures-util/src/future_result/map_err.rs +++ b/futures-util/src/async_result/map_err.rs @@ -1,13 +1,13 @@ use core::mem::Pin; -use futures_core::{Future, Poll}; +use futures_core::{Async, Poll}; use futures_core::task; -use FutureResult; +use futures_core::AsyncResult; -/// Future for the `map_err` combinator, changing the type of a future. +/// Async for the `map_err` combinator, changing the type of a future. /// -/// This is created by the `Future::map_err` method. +/// This is created by the `Async::map_err` method. #[derive(Debug)] #[must_use = "futures do nothing unless polled"] pub struct MapErr { @@ -22,14 +22,14 @@ pub fn new(future: A, f: F) -> MapErr { } } -impl Future for MapErr - where A: FutureResult, +impl Async for MapErr + where A: AsyncResult, F: FnOnce(A::Error) -> U, { type Output = Result; fn poll(mut self: Pin, cx: &mut task::Context) -> Poll { - match unsafe { pinned_field!(self, future) }.poll_result(cx) { + match unsafe { pinned_field!(self, future) }.poll(cx) { Poll::Pending => return Poll::Pending, Poll::Ready(e) => { let f = unsafe { diff --git a/futures-util/src/future_result/map_ok.rs b/futures-util/src/async_result/map_ok.rs similarity index 70% rename from futures-util/src/future_result/map_ok.rs rename to futures-util/src/async_result/map_ok.rs index c8b97582fb..0c99c82c2e 100644 --- a/futures-util/src/future_result/map_ok.rs +++ b/futures-util/src/async_result/map_ok.rs @@ -1,13 +1,13 @@ use core::mem::Pin; -use futures_core::{Future, Poll}; +use futures_core::{Async, Poll}; use futures_core::task; -use FutureResult; +use futures_core::AsyncResult; -/// Future for the `map_ok` combinator, changing the type of a future. +/// Async for the `map_ok` combinator, changing the type of a future. /// -/// This is created by the `Future::map_ok` method. +/// This is created by the `Async::map_ok` method. #[derive(Debug)] #[must_use = "futures do nothing unless polled"] pub struct MapOk { @@ -22,14 +22,14 @@ pub fn new(future: A, f: F) -> MapOk { } } -impl Future for MapOk - where A: FutureResult, +impl Async for MapOk + where A: AsyncResult, F: FnOnce(A::Item) -> U, { type Output = Result; fn poll(mut self: Pin, cx: &mut task::Context) -> Poll { - match unsafe { pinned_field!(self, future) }.poll_result(cx) { + match unsafe { pinned_field!(self, future) }.poll(cx) { Poll::Pending => return Poll::Pending, Poll::Ready(e) => { let f = unsafe { diff --git a/futures-util/src/future_result/mod.rs b/futures-util/src/async_result/mod.rs similarity index 81% rename from futures-util/src/future_result/mod.rs rename to futures-util/src/async_result/mod.rs index 2a2080148a..0809395f24 100644 --- a/futures-util/src/future_result/mod.rs +++ b/futures-util/src/async_result/mod.rs @@ -1,11 +1,9 @@ -//! Futures +//! Asyncs //! -//! This module contains a number of functions for working with `Future`s, -//! including the `FutureExt` trait which adds methods to `Future` types. +//! This module contains a number of functions for working with `Async`s, +//! including the `AsyncExt` trait which adds methods to `Async` types. -use core::mem::Pin; - -use futures_core::{task, Future, Poll}; +use futures_core::AsyncResult; // combinators mod and_then; @@ -38,33 +36,9 @@ pub use self::err_into::ErrInto; pub use self::or_else::OrElse; pub use self::recover::Recover; -impl FutureResult for F - where F: Future> -{ - type Item = T; - type Error = E; - - fn poll_result(self: Pin, cx: &mut task::Context) -> Poll { - self.poll(cx) - } -} - /// A convenience for futures that return `Result` values that includes /// a variety of adapters tailored to such futures. -pub trait FutureResult { - /// The type of successful values yielded by this future - type Item; - - /// The type of failures yielded by this future - type Error; - - /// Poll this `FutureResult` as if it were a `Future`. - /// - /// This method is a stopgap for a compiler limitation that prevents us from - /// directly inheriting from the `Future` trait; in the future it won't be - /// needed. - fn poll_result(self: Pin, cx: &mut task::Context) -> Poll>; - +pub trait AsyncResultExt: AsyncResult { /// Map this future's result to a different type, returning a new future of /// the resulting type. /// @@ -96,7 +70,7 @@ pub trait FutureResult { /// # } /// ``` /// - /// Calling `map` on an errored `Future` has no effect: + /// Calling `map` on an errored `Async` has no effect: /// /// ``` /// # extern crate futures; @@ -148,7 +122,7 @@ pub trait FutureResult { /// # } /// ``` /// - /// Calling `map_err` on a successful `Future` has no effect: + /// Calling `map_err` on a successful `Async` has no effect: /// /// ``` /// # extern crate futures; @@ -207,7 +181,7 @@ pub trait FutureResult { /// provided is yielded the successful result of this future and returns /// another value which can be converted into a future. /// - /// Note that because `Result` implements the `IntoFuture` trait this method + /// Note that because `Result` implements the `IntoAsync` trait this method /// can also be useful for chaining fallible and serial computations onto /// the end of one future. /// @@ -222,7 +196,7 @@ pub trait FutureResult { /// ``` /// # extern crate futures; /// use futures::prelude::*; - /// use futures::future::{self, FutureResult}; + /// use futures::future::{self, AsyncResult}; /// /// # fn main() { /// let future_of_1 = future::ok::(1); @@ -231,14 +205,14 @@ pub trait FutureResult { /// }); /// /// let future_of_err_1 = future::err::(1); - /// future_of_err_1.and_then(|_| -> FutureResult { + /// future_of_err_1.and_then(|_| -> AsyncResult { /// panic!("should not be called in case of an error"); /// }); /// # } /// ``` fn and_then(self, f: F) -> AndThen where F: FnOnce(Self::Item) -> B, - B: FutureResult, + B: AsyncResult, Self: Sized, { and_then::new(self, f) @@ -251,7 +225,7 @@ pub trait FutureResult { /// future it returns. The closure may also simply return a value that can /// be converted into a future. /// - /// Note that because `Result` implements the `IntoFuture` trait this method + /// Note that because `Result` implements the `IntoAsync` trait this method /// can also be useful for chaining together fallback computations, where /// when one fails, the next is attempted. /// @@ -266,7 +240,7 @@ pub trait FutureResult { /// ``` /// # extern crate futures; /// use futures::prelude::*; - /// use futures::future::{self, FutureResult}; + /// use futures::future::{self, AsyncResult}; /// /// # fn main() { /// let future_of_err_1 = future::err::(1); @@ -275,14 +249,14 @@ pub trait FutureResult { /// }); /// /// let future_of_1 = future::ok::(1); - /// future_of_1.or_else(|_| -> FutureResult { + /// future_of_1.or_else(|_| -> AsyncResult { /// panic!("should not be called in case of success"); /// }); /// # } /// ``` fn or_else(self, f: F) -> OrElse where F: FnOnce(Self::Error) -> B, - B: FutureResult, + B: AsyncResult, Self: Sized, { or_else::new(self, f) @@ -312,12 +286,12 @@ pub trait FutureResult { /// /// // A poor-man's join implemented on top of select /// - /// fn join(a: A, b: B) -> Box> - /// where A: Future + 'static, - /// B: Future + 'static, + /// fn join(a: A, b: B) -> Box> + /// where A: Async + 'static, + /// B: Async + 'static, /// E: 'static, /// { - /// Box::new(a.select(b).then(|res| -> Box> { + /// Box::new(a.select(b).then(|res| -> Box> { /// match res { /// Ok(Either::Left((x, b))) => Box::new(b.map(move |y| (x, y))), /// Ok(Either::Right((y, a))) => Box::new(a.map(move |x| (x, y))), @@ -328,8 +302,8 @@ pub trait FutureResult { /// } /// # fn main() {} /// ``` - fn select(self, other: B) -> Select - where B: IntoFuture, Self: Sized + fn select(self, other: B) -> Select + where B: IntoAsync, Self: Sized { select::new(self, other.into_future()) } @@ -365,8 +339,8 @@ pub trait FutureResult { /// # } /// ``` /// - /// If one or both of the joined `Future`s is errored, the resulting - /// `Future` will be errored: + /// If one or both of the joined `Async`s is errored, the resulting + /// `Async` will be errored: /// /// ``` /// # extern crate futures; @@ -383,8 +357,8 @@ pub trait FutureResult { /// assert_eq!(block_on(pair), Err(2)); /// # } /// ``` - fn join(self, other: B) -> Join - where B: IntoFuture, + fn join(self, other: B) -> Join + where B: IntoAsync, Self: Sized, { let f = join::new(self, other.into_future()); @@ -392,9 +366,9 @@ pub trait FutureResult { } /// Same as `join`, but with more futures. - fn join3(self, b: B, c: C) -> Join3 - where B: IntoFuture, - C: IntoFuture, + fn join3(self, b: B, c: C) -> Join3 + where B: IntoAsync, + C: IntoAsync, Self: Sized, { join::new3(self, b.into_future(), c.into_future()) @@ -402,10 +376,10 @@ pub trait FutureResult { /// Same as `join`, but with more futures. fn join4(self, b: B, c: C, d: D) - -> Join4 - where B: IntoFuture, - C: IntoFuture, - D: IntoFuture, + -> Join4 + where B: IntoAsync, + C: IntoAsync, + D: IntoAsync, Self: Sized, { join::new4(self, b.into_future(), c.into_future(), d.into_future()) @@ -413,11 +387,11 @@ pub trait FutureResult { /// Same as `join`, but with more futures. fn join5(self, b: B, c: C, d: D, e: E) - -> Join5 - where B: IntoFuture, - C: IntoFuture, - D: IntoFuture, - E: IntoFuture, + -> Join5 + where B: IntoAsync, + C: IntoAsync, + D: IntoAsync, + E: IntoAsync, Self: Sized, { join::new5(self, b.into_future(), c.into_future(), d.into_future(), diff --git a/futures-util/src/future_result/or_else.rs b/futures-util/src/async_result/or_else.rs similarity index 85% rename from futures-util/src/future_result/or_else.rs rename to futures-util/src/async_result/or_else.rs index a7188c8279..ee039f65a5 100644 --- a/futures-util/src/future_result/or_else.rs +++ b/futures-util/src/async_result/or_else.rs @@ -1,14 +1,14 @@ use core::mem::Pin; -use futures_core::{Future, Poll}; +use futures_core::{Async, Poll}; use futures_core::task; -use FutureResult; +use futures_core::AsyncResult; -/// Future for the `or_else` combinator, chaining a computation onto the end of +/// Async for the `or_else` combinator, chaining a computation onto the end of /// a future which fails with an error. /// -/// This is created by the `Future::or_else` method. +/// This is created by the `Async::or_else` method. #[derive(Debug)] #[must_use = "futures do nothing unless polled"] pub struct OrElse { @@ -27,9 +27,9 @@ pub fn new(future: A, f: F) -> OrElse { } } -impl Future for OrElse - where A: FutureResult, - B: FutureResult, +impl Async for OrElse + where A: AsyncResult, + B: AsyncResult, F: FnOnce(A::Error) -> B, { type Output = Result; @@ -41,7 +41,7 @@ impl Future for OrElse State::First(ref mut fut1, ref mut data) => { // safe to create a new `Pin` because `fut1` will never move // before it's dropped. - match unsafe { Pin::new_unchecked(fut1) }.poll_result(cx) { + match unsafe { Pin::new_unchecked(fut1) }.poll(cx) { Poll::Pending => return Poll::Pending, Poll::Ready(Ok(v)) => return Poll::Ready(Ok(v)), Poll::Ready(Err(e)) => { @@ -53,7 +53,7 @@ impl Future for OrElse // safe to create a new `Pin` because `fut2` will never move // before it's dropped; once we're in `Chain::Second` we stay // there forever. - return unsafe { Pin::new_unchecked(fut2) }.poll_result(cx) + return unsafe { Pin::new_unchecked(fut2) }.poll(cx) } }; diff --git a/futures-util/src/future_result/recover.rs b/futures-util/src/async_result/recover.rs similarity index 74% rename from futures-util/src/future_result/recover.rs rename to futures-util/src/async_result/recover.rs index 7ec1e43c02..74f74f27d6 100644 --- a/futures-util/src/future_result/recover.rs +++ b/futures-util/src/async_result/recover.rs @@ -1,11 +1,11 @@ use core::mem::Pin; -use futures_core::{Future, Poll}; +use futures_core::{Async, Poll}; use futures_core::task; -use FutureResult; +use futures_core::AsyncResult; -/// Future for the `recover` combinator, handling errors by converting them into +/// Async for the `recover` combinator, handling errors by converting them into /// an `Item`, compatible with any error type of the caller's choosing. #[must_use = "futures do nothing unless polled"] #[derive(Debug)] @@ -18,14 +18,14 @@ pub fn new(future: A, f: F) -> Recover { Recover { inner: future, f: Some(f) } } -impl Future for Recover - where A: FutureResult, +impl Async for Recover + where A: AsyncResult, F: FnOnce(A::Error) -> A::Item, { type Output = A::Item; fn poll(mut self: Pin, cx: &mut task::Context) -> Poll { - unsafe { pinned_field!(self, inner) }.poll_result(cx) + unsafe { pinned_field!(self, inner) }.poll(cx) .map(|res| res.unwrap_or_else(|e| { let f = unsafe { Pin::get_mut(&mut self).f.take() diff --git a/futures-util/src/future/select.rs b/futures-util/src/async_result/select.rs similarity index 78% rename from futures-util/src/future/select.rs rename to futures-util/src/async_result/select.rs index cf994d4ce3..5ea1a77399 100644 --- a/futures-util/src/future/select.rs +++ b/futures-util/src/async_result/select.rs @@ -1,14 +1,14 @@ -use futures_core::{Future, Poll, Async}; +use futures_core::{Async, Poll, Async}; use futures_core::task; use either::Either; -/// Future for the `select` combinator, waiting for one of two differently-typed +/// Async for the `select` combinator, waiting for one of two differently-typed /// futures to complete. /// -/// This is created by the [`Future::select`] method. +/// This is created by the [`Async::select`] method. /// -/// [`Future::select`]: trait.Future.html#method.select +/// [`Async::select`]: trait.Async.html#method.select #[must_use = "futures do nothing unless polled"] #[derive(Debug)] pub struct Select { @@ -19,7 +19,7 @@ pub fn new(a: A, b: B) -> Select { Select { inner: Some((a, b)) } } -impl Future for Select where A: Future, B: Future { +impl Async for Select where A: Async, B: Async { type Item = Either<(A::Item, B), (B::Item, A)>; type Error = Either<(A::Error, B), (B::Error, A)>; diff --git a/futures-util/src/future/select_all.rs b/futures-util/src/async_result/select_all.rs similarity index 84% rename from futures-util/src/future/select_all.rs rename to futures-util/src/async_result/select_all.rs index 38c2594a32..4798e6da4d 100644 --- a/futures-util/src/future/select_all.rs +++ b/futures-util/src/async_result/select_all.rs @@ -4,16 +4,16 @@ use std::mem; use std::prelude::v1::*; -use futures_core::{Future, IntoFuture, Poll, Async}; +use futures_core::{Async, IntoAsync, Poll, Async}; use futures_core::task; -/// Future for the `select_all` combinator, waiting for one of any of a list of +/// Async for the `select_all` combinator, waiting for one of any of a list of /// futures to complete. /// /// This is created by the `select_all` function. #[derive(Debug)] #[must_use = "futures do nothing unless polled"] -pub struct SelectAll where A: Future { +pub struct SelectAll where A: Async { inner: Vec, } @@ -30,9 +30,9 @@ pub type SelectAllNext = A; /// # Panics /// /// This function will panic if the iterator specified contains no items. -pub fn select_all(iter: I) -> SelectAll<::Future> +pub fn select_all(iter: I) -> SelectAll<::Async> where I: IntoIterator, - I::Item: IntoFuture, + I::Item: IntoAsync, { let ret = SelectAll { inner: iter.into_iter() @@ -43,8 +43,8 @@ pub fn select_all(iter: I) -> SelectAll<::Future> ret } -impl Future for SelectAll - where A: Future, +impl Async for SelectAll + where A: Async, { type Item = (A::Item, usize, Vec); type Error = (A::Error, usize, Vec); diff --git a/futures-util/src/future/select_ok.rs b/futures-util/src/async_result/select_ok.rs similarity index 88% rename from futures-util/src/future/select_ok.rs rename to futures-util/src/async_result/select_ok.rs index 24a7200f96..b7ed52f3b8 100644 --- a/futures-util/src/future/select_ok.rs +++ b/futures-util/src/async_result/select_ok.rs @@ -4,17 +4,17 @@ use std::mem; use std::prelude::v1::*; -use futures_core::{Future, IntoFuture, Poll, Async}; +use futures_core::{Async, IntoAsync, Poll, Async}; use futures_core::task; -/// Future for the `select_ok` combinator, waiting for one of any of a list of +/// Async for the `select_ok` combinator, waiting for one of any of a list of /// futures to successfully complete. Unlike `select_all`, this future ignores all /// but the last error, if there are any. /// /// This is created by the `select_ok` function. #[derive(Debug)] #[must_use = "futures do nothing unless polled"] -pub struct SelectOk where A: Future { +pub struct SelectOk where A: Async { inner: Vec, } @@ -28,9 +28,9 @@ pub struct SelectOk where A: Future { /// # Panics /// /// This function will panic if the iterator specified contains no items. -pub fn select_ok(iter: I) -> SelectOk<::Future> +pub fn select_ok(iter: I) -> SelectOk<::Async> where I: IntoIterator, - I::Item: IntoFuture, + I::Item: IntoAsync, { let ret = SelectOk { inner: iter.into_iter() @@ -41,7 +41,7 @@ pub fn select_ok(iter: I) -> SelectOk<::Future> ret } -impl Future for SelectOk where A: Future { +impl Async for SelectOk where A: Async { type Item = (A::Item, Vec); type Error = A::Error; diff --git a/futures-util/src/future/catch_unwind.rs b/futures-util/src/async_trait/catch_unwind.rs similarity index 70% rename from futures-util/src/future/catch_unwind.rs rename to futures-util/src/async_trait/catch_unwind.rs index c6a5800d5b..bb59f36156 100644 --- a/futures-util/src/future/catch_unwind.rs +++ b/futures-util/src/async_trait/catch_unwind.rs @@ -3,26 +3,26 @@ use std::prelude::v1::*; use std::any::Any; use std::panic::{catch_unwind, UnwindSafe, AssertUnwindSafe}; -use futures_core::{Future, Poll}; +use futures_core::{Async, Poll}; use futures_core::task; -/// Future for the `catch_unwind` combinator. +/// Async for the `catch_unwind` combinator. /// -/// This is created by the `Future::catch_unwind` method. +/// This is created by the `Async::catch_unwind` method. #[derive(Debug)] #[must_use = "futures do nothing unless polled"] -pub struct CatchUnwind where F: Future { +pub struct CatchUnwind where F: Async { future: F, } pub fn new(future: F) -> CatchUnwind - where F: Future + UnwindSafe, + where F: Async + UnwindSafe, { CatchUnwind { future } } -impl Future for CatchUnwind - where F: Future + UnwindSafe, +impl Async for CatchUnwind + where F: Async + UnwindSafe, { type Output = Result>; diff --git a/futures-util/src/future/chain.rs b/futures-util/src/async_trait/chain.rs similarity index 95% rename from futures-util/src/future/chain.rs rename to futures-util/src/async_trait/chain.rs index faa25d3110..ff8e309101 100644 --- a/futures-util/src/future/chain.rs +++ b/futures-util/src/async_trait/chain.rs @@ -1,6 +1,6 @@ use core::mem::Pin; -use futures_core::{Future, Poll}; +use futures_core::{Async, Poll}; use futures_core::task; #[must_use = "futures do nothing unless polled"] @@ -11,8 +11,8 @@ pub enum Chain { } impl Chain - where Fut1: Future, - Fut2: Future, + where Fut1: Async, + Fut2: Async, { pub fn new(fut1: Fut1, data: Data) -> Chain { Chain::First(fut1, Some(data)) diff --git a/futures-util/src/future/empty.rs b/futures-util/src/async_trait/empty.rs similarity index 91% rename from futures-util/src/future/empty.rs rename to futures-util/src/async_trait/empty.rs index c79f87d6da..392526d1cb 100644 --- a/futures-util/src/future/empty.rs +++ b/futures-util/src/async_trait/empty.rs @@ -3,7 +3,7 @@ use core::mem::Pin; use core::marker; -use futures_core::{Future, Poll}; +use futures_core::{Async, Poll}; use futures_core::task; /// A future which is never resolved. @@ -23,7 +23,7 @@ pub fn empty() -> Empty { Empty { _data: marker::PhantomData } } -impl Future for Empty { +impl Async for Empty { type Output = T; fn poll(self: Pin, _: &mut task::Context) -> Poll { diff --git a/futures-util/src/future/flatten.rs b/futures-util/src/async_trait/flatten.rs similarity index 55% rename from futures-util/src/future/flatten.rs rename to futures-util/src/async_trait/flatten.rs index 9481f4d4d4..a10dcd7d26 100644 --- a/futures-util/src/future/flatten.rs +++ b/futures-util/src/async_trait/flatten.rs @@ -1,24 +1,24 @@ use core::fmt; use core::mem::Pin; -use futures_core::{Future, Poll}; +use futures_core::{Async, Poll}; use futures_core::task; use super::chain::Chain; -/// Future for the `flatten` combinator. +/// Async for the `flatten` combinator. /// -/// This combinator turns a `Future`-of-a-`Future` into a single `Future`. +/// This combinator turns a `Async`-of-a-`Async` into a single `Async`. /// -/// This is created by the `Future::flatten` method. +/// This is created by the `Async::flatten` method. #[must_use = "futures do nothing unless polled"] -pub struct Flatten where A: Future, A::Output: Future { +pub struct Flatten where A: Async, A::Output: Async { state: Chain, } impl fmt::Debug for Flatten - where A: Future + fmt::Debug, - A::Output: Future + fmt::Debug, + where A: Async + fmt::Debug, + A::Output: Async + fmt::Debug, { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { fmt.debug_struct("Flatten") @@ -28,19 +28,19 @@ impl fmt::Debug for Flatten } pub fn new(future: A) -> Flatten - where A: Future, - A::Output: Future, + where A: Async, + A::Output: Async, { Flatten { state: Chain::new(future, ()), } } -impl Future for Flatten - where A: Future, - A::Output: Future, +impl Async for Flatten + where A: Async, + A::Output: Async, { - type Output = ::Output; + type Output = ::Output; fn poll(mut self: Pin, cx: &mut task::Context) -> Poll { unsafe { pinned_field!(self, state) }.poll(cx, |a, ()| a) diff --git a/futures-util/src/future/flatten_sink.rs b/futures-util/src/async_trait/flatten_sink.rs similarity index 74% rename from futures-util/src/future/flatten_sink.rs rename to futures-util/src/async_trait/flatten_sink.rs index 5a29cb4e4a..b147c7cc5c 100644 --- a/futures-util/src/future/flatten_sink.rs +++ b/futures-util/src/async_trait/flatten_sink.rs @@ -1,26 +1,26 @@ use core::fmt; -use futures_core::{task, Async, Future}; +use futures_core::{task, Async, Async}; use futures_sink::Sink; #[derive(Debug)] -enum State where F: Future, ::Item: Sink { +enum State where F: Async, ::Item: Sink { Waiting(F), Ready(F::Item), Closed, } -/// Future for the `flatten_sink` combinator, flattening a +/// Async for the `flatten_sink` combinator, flattening a /// future-of-a-sink to get just the result of the final sink as a sink. /// -/// This is created by the `Future::flatten_sink` method. -pub struct FlattenSink where F: Future, ::Item: Sink { +/// This is created by the `Async::flatten_sink` method. +pub struct FlattenSink where F: Async, ::Item: Sink { st: State } impl fmt::Debug for FlattenSink - where F: Future + fmt::Debug, - ::Item: Sink + fmt::Debug, + where F: Async + fmt::Debug, + ::Item: Sink + fmt::Debug, { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { fmt.debug_struct("FlattenStream") @@ -29,9 +29,9 @@ impl fmt::Debug for FlattenSink } } -impl Sink for FlattenSink where F: Future, ::Item: Sink { - type SinkItem = <::Item as Sink>::SinkItem; - type SinkError = <::Item as Sink>::SinkError; +impl Sink for FlattenSink where F: Async, ::Item: Sink { + type SinkItem = <::Item as Sink>::SinkItem; + type SinkError = <::Item as Sink>::SinkError; fn poll_ready(&mut self, cx: &mut task::Context) -> Result, Self::SinkError> { let mut resolved_stream = match self.st { @@ -73,7 +73,7 @@ impl Sink for FlattenSink where F: Future, ::Item: Sink(fut: F) -> FlattenSink where F: Future, ::Item: Sink { +pub fn new(fut: F) -> FlattenSink where F: Async, ::Item: Sink { FlattenSink { st: State::Waiting(fut) } diff --git a/futures-util/src/future/fuse.rs b/futures-util/src/async_trait/fuse.rs similarity index 87% rename from futures-util/src/future/fuse.rs rename to futures-util/src/async_trait/fuse.rs index b98c321549..7c0ba3c2c3 100644 --- a/futures-util/src/future/fuse.rs +++ b/futures-util/src/async_trait/fuse.rs @@ -1,6 +1,6 @@ use core::mem::Pin; -use futures_core::{Future, Poll}; +use futures_core::{Async, Poll}; use futures_core::task; /// A future which "fuses" a future once it's been resolved. @@ -9,20 +9,20 @@ use futures_core::task; /// has been resolved, but `Fuse` is always defined to return `Async::Pending` /// from `poll` after it has resolved successfully or returned an error. /// -/// This is created by the `Future::fuse` method. +/// This is created by the `Async::fuse` method. #[derive(Debug)] #[must_use = "futures do nothing unless polled"] -pub struct Fuse { +pub struct Fuse { future: Option, } -pub fn new(f: A) -> Fuse { +pub fn new(f: A) -> Fuse { Fuse { future: Some(f), } } -impl Future for Fuse { +impl Async for Fuse { type Output = A::Output; fn poll(mut self: Pin, cx: &mut task::Context) -> Poll { diff --git a/futures-util/src/future/inspect.rs b/futures-util/src/async_trait/inspect.rs similarity index 79% rename from futures-util/src/future/inspect.rs rename to futures-util/src/async_trait/inspect.rs index f348734cff..4c2e2fb8d1 100644 --- a/futures-util/src/future/inspect.rs +++ b/futures-util/src/async_trait/inspect.rs @@ -1,20 +1,20 @@ use core::mem::Pin; -use futures_core::{Future, Poll}; +use futures_core::{Async, Poll}; use futures_core::task; /// Do something with the item of a future, passing it on. /// -/// This is created by the [`FutureExt::inspect`] method. +/// This is created by the [`AsyncExt::inspect`] method. #[derive(Debug)] #[must_use = "futures do nothing unless polled"] -pub struct Inspect where A: Future { +pub struct Inspect where A: Async { future: A, f: Option, } pub fn new(future: A, f: F) -> Inspect - where A: Future, + where A: Async, F: FnOnce(&A::Output), { Inspect { @@ -23,8 +23,8 @@ pub fn new(future: A, f: F) -> Inspect } } -impl Future for Inspect - where A: Future, +impl Async for Inspect + where A: Async, F: FnOnce(&A::Output), { type Output = A::Output; diff --git a/futures-util/src/async_trait/join.rs b/futures-util/src/async_trait/join.rs new file mode 100644 index 0000000000..684eebf183 --- /dev/null +++ b/futures-util/src/async_trait/join.rs @@ -0,0 +1,176 @@ +#![allow(non_snake_case)] + +use core::fmt; +use core::mem; + +use futures_core::{Async, Poll, Async}; +use futures_core::task; + +macro_rules! generate { + ($( + $(#[$doc:meta])* + ($Join:ident, $new:ident, ), + )*) => ($( + $(#[$doc])* + #[must_use = "futures do nothing unless polled"] + pub struct $Join + where A: Async, + $($B: Async),* + { + a: MaybeDone, + $($B: MaybeDone<$B>,)* + } + + impl fmt::Debug for $Join + where A: Async + fmt::Debug, + A::Item: fmt::Debug, + $( + $B: Async + fmt::Debug, + $B::Item: fmt::Debug + ),* + { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + fmt.debug_struct(stringify!($Join)) + .field("a", &self.a) + $(.field(stringify!($B), &self.$B))* + .finish() + } + } + + pub fn $new(a: A, $($B: $B),*) -> $Join + where A: Async, + $($B: Async),* + { + $Join { + a: MaybeDone::NotYet(a), + $($B: MaybeDone::NotYet($B)),* + } + } + + impl $Join + where A: Async, + $($B: Async),* + { + fn erase(&mut self) { + self.a = MaybeDone::Gone; + $(self.$B = MaybeDone::Gone;)* + } + } + + impl Async for $Join + where A: Async, + $($B: Async),* + { + type Item = (A::Item, $($B::Item),*); + type Error = A::Error; + + fn poll(&mut self, cx: &mut task::Context) -> Poll { + let mut all_done = match self.a.poll(cx) { + Ok(done) => done, + Err(e) => { + self.erase(); + return Err(e) + } + }; + $( + all_done = match self.$B.poll(cx) { + Ok(done) => all_done && done, + Err(e) => { + self.erase(); + return Err(e) + } + }; + )* + + if all_done { + Ok(Async::Ready((self.a.take(), $(self.$B.take()),*))) + } else { + Ok(Async::Pending) + } + } + } + + // Incoherent-- add to futures-core when stable. + /* + impl IntoAsync for (A, $($B),*) + where A: IntoAsync, + $( + $B: IntoAsync + ),* + { + type Async = $Join; + type Item = (A::Item, $($B::Item),*); + type Error = A::Error; + + fn into_future(self) -> Self::Async { + match self { + (a, $($B),+) => { + $new( + IntoAsync::into_future(a), + $(IntoAsync::into_future($B)),+ + ) + } + } + } + } + */ + + )*) +} + +generate! { + /// Async for the `join` combinator, waiting for two futures to + /// complete. + /// + /// This is created by the `Async::join` method. + (Join, new, ), + + /// Async for the `join3` combinator, waiting for three futures to + /// complete. + /// + /// This is created by the `Async::join3` method. + (Join3, new3, ), + + /// Async for the `join4` combinator, waiting for four futures to + /// complete. + /// + /// This is created by the `Async::join4` method. + (Join4, new4, ), + + /// Async for the `join5` combinator, waiting for five futures to + /// complete. + /// + /// This is created by the `Async::join5` method. + (Join5, new5, ), +} + +#[derive(Debug)] +enum MaybeDone { + NotYet(A), + Done(A::Item), + Gone, +} + +impl MaybeDone { + fn poll(&mut self, cx: &mut task::Context) -> Result { + let res = match *self { + MaybeDone::NotYet(ref mut a) => a.poll(cx)?, + MaybeDone::Done(_) => return Ok(true), + MaybeDone::Gone => panic!("cannot poll Join twice"), + }; + match res { + Async::Ready(res) => { + *self = MaybeDone::Done(res); + Ok(true) + } + Async::Pending => Ok(false), + } + } + + fn take(&mut self) -> A::Item { + match mem::replace(self, MaybeDone::Gone) { + MaybeDone::Done(a) => a, + _ => panic!(), + } + } +} diff --git a/futures-util/src/async_trait/join_all.rs b/futures-util/src/async_trait/join_all.rs new file mode 100644 index 0000000000..1d5e7dd55e --- /dev/null +++ b/futures-util/src/async_trait/join_all.rs @@ -0,0 +1,145 @@ +//! Definition of the `JoinAll` combinator, waiting for all of a list of futures +//! to finish. + +use std::prelude::v1::*; + +use std::fmt; +use std::mem; +use std::iter::FromIterator; + +use futures_core::{Async, IntoAsync, Poll, Async}; +use futures_core::task; + +#[derive(Debug)] +enum ElemState where F: Async { + Pending(F), + Done(F::Item), +} + +/// A future which takes a list of futures and resolves with a vector of the +/// completed values. +/// +/// This future is created with the `join_all` method. +#[must_use = "futures do nothing unless polled"] +pub struct JoinAll + where F: Async, +{ + elems: Vec>, +} + +impl fmt::Debug for JoinAll + where F: Async + fmt::Debug, + F::Item: fmt::Debug, +{ + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + fmt.debug_struct("JoinAll") + .field("elems", &self.elems) + .finish() + } +} + +/// Creates a future which represents a collection of the results of the futures +/// given. +/// +/// The returned future will drive execution for all of its underlying futures, +/// collecting the results into a destination `Vec` in the same order as they +/// were provided. If any future returns an error then all other futures will be +/// canceled and an error will be returned immediately. If all futures complete +/// successfully, however, then the returned future will succeed with a `Vec` of +/// all the successful results. +/// +/// # Examples +/// +/// ``` +/// # extern crate futures; +/// use futures::prelude::*; +/// use futures::future::{join_all, ok, err}; +/// +/// # fn main() { +/// # +/// let f = join_all(vec![ +/// ok::(1), +/// ok::(2), +/// ok::(3), +/// ]); +/// let f = f.map(|x| { +/// assert_eq!(x, [1, 2, 3]); +/// }); +/// +/// let f = join_all(vec![ +/// Box::new(ok::(1)), +/// Box::new(err::(2)), +/// Box::new(ok::(3)), +/// ]); +/// let f = f.then(|x| { +/// assert_eq!(x, Err(2)); +/// x +/// }); +/// # } +/// ``` +pub fn join_all(i: I) -> JoinAll<::Async> + where I: IntoIterator, + I::Item: IntoAsync, +{ + let elems = i.into_iter().map(|f| { + ElemState::Pending(f.into_future()) + }).collect(); + JoinAll { elems } +} + +impl Async for JoinAll + where F: Async, +{ + type Item = Vec; + type Error = F::Error; + + + fn poll(&mut self, cx: &mut task::Context) -> Poll { + let mut all_done = true; + + for idx in 0 .. self.elems.len() { + let done_val = match self.elems[idx] { + ElemState::Pending(ref mut t) => { + match t.poll(cx) { + Ok(Async::Ready(v)) => Ok(v), + Ok(Async::Pending) => { + all_done = false; + continue + } + Err(e) => Err(e), + } + } + ElemState::Done(ref mut _v) => continue, + }; + + match done_val { + Ok(v) => self.elems[idx] = ElemState::Done(v), + Err(e) => { + // On completion drop all our associated resources + // ASAP. + self.elems = Vec::new(); + return Err(e) + } + } + } + + if all_done { + let elems = mem::replace(&mut self.elems, Vec::new()); + let result = elems.into_iter().map(|e| { + match e { + ElemState::Done(t) => t, + _ => unreachable!(), + } + }).collect(); + Ok(Async::Ready(result)) + } else { + Ok(Async::Pending) + } + } +} + +impl FromIterator for JoinAll { + fn from_iter>(iter: T) -> Self { + join_all(iter) + } +} diff --git a/futures-util/src/future/lazy.rs b/futures-util/src/async_trait/lazy.rs similarity index 94% rename from futures-util/src/future/lazy.rs rename to futures-util/src/async_trait/lazy.rs index 5732363b44..ac604224c3 100644 --- a/futures-util/src/future/lazy.rs +++ b/futures-util/src/async_trait/lazy.rs @@ -4,7 +4,7 @@ use core::mem::Pin; use core::marker::Unpin; -use futures_core::{Future, Poll}; +use futures_core::{Async, Poll}; use futures_core::task; /// A future which, when polled, invokes a closure and yields its result. @@ -45,7 +45,7 @@ pub fn lazy(f: F) -> Lazy Lazy { f: Some(f) } } -impl Future for Lazy +impl Async for Lazy where F: FnOnce(&mut task::Context) -> R, { type Output = R; diff --git a/futures-util/src/future/map.rs b/futures-util/src/async_trait/map.rs similarity index 72% rename from futures-util/src/future/map.rs rename to futures-util/src/async_trait/map.rs index 3117698f15..960edfce9e 100644 --- a/futures-util/src/future/map.rs +++ b/futures-util/src/async_trait/map.rs @@ -1,20 +1,20 @@ use core::mem::Pin; -use futures_core::{Future, Poll}; +use futures_core::{Async, Poll}; use futures_core::task; -/// Future for the `map` combinator, changing the type of a future. +/// Async for the `map` combinator, changing the type of a future. /// -/// This is created by the `Future::map` method. +/// This is created by the `Async::map` method. #[derive(Debug)] #[must_use = "futures do nothing unless polled"] -pub struct Map where A: Future { +pub struct Map where A: Async { future: A, f: Option, } pub fn new(future: A, f: F) -> Map - where A: Future, + where A: Async, { Map { future: future, @@ -22,8 +22,8 @@ pub fn new(future: A, f: F) -> Map } } -impl Future for Map - where A: Future, +impl Async for Map + where A: Async, F: FnOnce(A::Output) -> U, { type Output = U; diff --git a/futures-util/src/future/mod.rs b/futures-util/src/async_trait/mod.rs similarity index 79% rename from futures-util/src/future/mod.rs rename to futures-util/src/async_trait/mod.rs index 0524fe4cf7..4455a60adc 100644 --- a/futures-util/src/future/mod.rs +++ b/futures-util/src/async_trait/mod.rs @@ -1,9 +1,9 @@ -//! Futures +//! Asyncs //! -//! This module contains a number of functions for working with `Future`s, -//! including the `FutureExt` trait which adds methods to `Future` types. +//! This module contains a number of functions for working with `Async`s, +//! including the `AsyncExt` trait which adds methods to `Async` types. -use futures_core::{Future, Stream}; +use futures_core::Async; // use futures_sink::Sink; // Primitive futures @@ -17,9 +17,7 @@ pub use self::poll_fn::{poll_fn, PollFn}; // combinators mod flatten; // mod flatten_sink; -mod flatten_stream; mod fuse; -mod into_stream; // mod join; mod map; // mod select; @@ -31,9 +29,7 @@ mod chain; pub use self::flatten::Flatten; // pub use self::flatten_sink::FlattenSink; -pub use self::flatten_stream::FlattenStream; pub use self::fuse::Fuse; -pub use self::into_stream::IntoStream; // pub use self::join::{Join, Join3, Join4, Join5}; pub use self::map::Map; // pub use self::select::Select; @@ -62,11 +58,11 @@ if_std! { pub use self::with_executor::WithExecutor; } -impl FutureExt for T where T: Future {} +impl AsyncExt for T where T: Async {} -/// An extension trait for `Future`s that provides a variety of convenient +/// An extension trait for `Async`s that provides a variety of convenient /// adapters. -pub trait FutureExt: Future { +pub trait AsyncExt: Async { /// Map this future's result to a different type, returning a new future of /// the resulting type. /// @@ -103,7 +99,7 @@ pub trait FutureExt: Future { /// Chain on a computation for when a future finished, passing the result of /// the future to the provided closure `f`. /// - /// The returned value of the closure must implement the `Future` trait + /// The returned value of the closure must implement the `Async` trait /// and can represent some more work to be done before the composed future /// is finished. /// @@ -127,7 +123,7 @@ pub trait FutureExt: Future { /// ``` fn then(self, f: F) -> Then where F: FnOnce(Self::Output) -> B, - B: Future, + B: Async, Self: Sized, { assert_future::(then::new(self, f)) @@ -157,12 +153,12 @@ pub trait FutureExt: Future { /// /// // A poor-man's join implemented on top of select /// - /// fn join(a: A, b: B) -> Box> - /// where A: Future + 'static, - /// B: Future + 'static, + /// fn join(a: A, b: B) -> Box> + /// where A: Async + 'static, + /// B: Async + 'static, /// E: 'static, /// { - /// Box::new(a.select(b).then(|res| -> Box> { + /// Box::new(a.select(b).then(|res| -> Box> { /// match res { /// Ok(Either::Left((x, b))) => Box::new(b.map(move |y| (x, y))), /// Ok(Either::Right((y, a))) => Box::new(a.map(move |x| (x, y))), @@ -173,8 +169,8 @@ pub trait FutureExt: Future { /// } /// # fn main() {} /// ``` - fn select(self, other: B) -> Select - where B: IntoFuture, Self: Sized + fn select(self, other: B) -> Select + where B: IntoAsync, Self: Sized { select::new(self, other.into_future()) } @@ -210,8 +206,8 @@ pub trait FutureExt: Future { /// # } /// ``` /// - /// If one or both of the joined `Future`s is errored, the resulting - /// `Future` will be errored: + /// If one or both of the joined `Async`s is errored, the resulting + /// `Async` will be errored: /// /// ``` /// # extern crate futures; @@ -228,8 +224,8 @@ pub trait FutureExt: Future { /// assert_eq!(block_on(pair), Err(2)); /// # } /// ``` - fn join(self, other: B) -> Join - where B: IntoFuture, + fn join(self, other: B) -> Join + where B: IntoAsync, Self: Sized, { let f = join::new(self, other.into_future()); @@ -237,9 +233,9 @@ pub trait FutureExt: Future { } /// Same as `join`, but with more futures. - fn join3(self, b: B, c: C) -> Join3 - where B: IntoFuture, - C: IntoFuture, + fn join3(self, b: B, c: C) -> Join3 + where B: IntoAsync, + C: IntoAsync, Self: Sized, { join::new3(self, b.into_future(), c.into_future()) @@ -247,10 +243,10 @@ pub trait FutureExt: Future { /// Same as `join`, but with more futures. fn join4(self, b: B, c: C, d: D) - -> Join4 - where B: IntoFuture, - C: IntoFuture, - D: IntoFuture, + -> Join4 + where B: IntoAsync, + C: IntoAsync, + D: IntoAsync, Self: Sized, { join::new4(self, b.into_future(), c.into_future(), d.into_future()) @@ -258,11 +254,11 @@ pub trait FutureExt: Future { /// Same as `join`, but with more futures. fn join5(self, b: B, c: C, d: D, e: E) - -> Join5 - where B: IntoFuture, - C: IntoFuture, - D: IntoFuture, - E: IntoFuture, + -> Join5 + where B: IntoAsync, + C: IntoAsync, + D: IntoAsync, + E: IntoAsync, Self: Sized, { join::new5(self, b.into_future(), c.into_future(), d.into_future(), @@ -295,7 +291,7 @@ pub trait FutureExt: Future { /// # } /// ``` fn left_future(self) -> Either - where B: Future, + where B: Async, Self: Sized { Either::Left(self) @@ -325,46 +321,19 @@ pub trait FutureExt: Future { /// assert_eq!(false, block_on(future)); /// # } fn right_future(self) -> Either - where A: Future, + where A: Async, Self: Sized, { Either::Right(self) } - /// Convert this future into a single element stream. - /// - /// The returned stream contains single success if this future resolves to - /// success or single error if this future resolves into error. - /// - /// # Examples - /// - /// ``` - /// # extern crate futures; - /// # extern crate futures_executor; - /// use futures::prelude::*; - /// use futures::future; - /// use futures_executor::block_on; - /// - /// # fn main() { - /// let future = future::ready::(17); - /// let stream = future.into_stream(); - /// let collected: Vec<_> = block_on(stream.collect()); - /// assert_eq!(collected, vec![17]); - /// # } - /// ``` - fn into_stream(self) -> IntoStream - where Self: Sized - { - into_stream::new(self) - } - /// Flatten the execution of this future when the successful result of this /// future is itself another future. /// /// This can be useful when combining futures together to flatten the /// computation out the final result. This method can only be called /// when the successful result of this future itself implements the - /// `IntoFuture` trait and the error can be created from this future's error + /// `IntoAsync` trait and the error can be created from this future's error /// type. /// /// This method is roughly equivalent to `self.and_then(|x| x)`. @@ -388,11 +357,11 @@ pub trait FutureExt: Future { /// # } /// ``` fn flatten(self) -> Flatten - where Self::Output: Future, + where Self::Output: Async, Self: Sized { let f = flatten::new(self); - assert_future::<<::Output as Future>::Output, _>(f) + assert_future::<<::Output as Async>::Output, _>(f) } /* TODO @@ -406,49 +375,13 @@ pub trait FutureExt: Future { /// Note that this function consumes this future and returns a wrapped /// version of it. fn flatten_sink(self) -> FlattenSink - where ::Item: Sink, + where ::Item: Sink, Self: Sized { flatten_sink::new(self) } */ - /// Flatten the execution of this future when the successful result of this - /// future is a stream. - /// - /// This can be useful when stream initialization is deferred, and it is - /// convenient to work with that stream as if stream was available at the - /// call site. - /// - /// Note that this function consumes this future and returns a wrapped - /// version of it. - /// - /// # Examples - /// - /// ``` - /// # extern crate futures; - /// # extern crate futures_executor; - /// use futures::prelude::*; - /// use futures::future; - /// use futures::stream; - /// use futures_executor::block_on; - /// - /// # fn main() { - /// let stream_items = vec![17, 18, 19]; - /// let future_of_a_stream = future::ready(stream::iter_ok(stream_items)); - /// - /// let stream = future_of_a_stream.flatten_stream(); - /// let list: Vec<_> = block_on(stream.collect()); - /// assert_eq!(list, vec![17, 18, 19]); - /// # } - /// ``` - fn flatten_stream(self) -> FlattenStream - where Self::Output: Stream, - Self: Sized - { - flatten_stream::new(self) - } - /// Fuse a future such that `poll` will never again be called once it has /// completed. /// @@ -510,8 +443,8 @@ pub trait FutureExt: Future { /// Note that this method requires the `UnwindSafe` bound from the standard /// library. This isn't always applied automatically, and the standard /// library provides an `AssertUnwindSafe` wrapper type to apply it - /// after-the fact. To assist using this method, the `Future` trait is also - /// implemented for `AssertUnwindSafe` where `F` implements `Future`. + /// after-the fact. To assist using this method, the `Async` trait is also + /// implemented for `AssertUnwindSafe` where `F` implements `Async`. /// /// This method is only available when the `std` feature of this /// library is activated, and it is activated by default. @@ -522,14 +455,14 @@ pub trait FutureExt: Future { /// # extern crate futures; /// # extern crate futures_executor; /// use futures::prelude::*; - /// use futures::future::{self, FutureResult}; + /// use futures::future::{self, AsyncResult}; /// use futures_executor::block_on; /// /// # fn main() { /// let mut future = future::ready(2); /// assert!(block_on(future.catch_unwind()).is_ok()); /// - /// let mut future = future::lazy(|_| -> ReadyFuture { + /// let mut future = future::lazy(|_| -> ReadyAsync { /// panic!(); /// future::ready(2) /// }); @@ -635,7 +568,7 @@ pub trait FutureExt: Future { // Just a helper function to ensure the futures we're returning all have the // right implementations. fn assert_future(t: F) -> F - where F: Future, + where F: Async, { t } diff --git a/futures-util/src/future/poll_fn.rs b/futures-util/src/async_trait/poll_fn.rs similarity index 94% rename from futures-util/src/future/poll_fn.rs rename to futures-util/src/async_trait/poll_fn.rs index db8302a906..dcac6a5c2d 100644 --- a/futures-util/src/future/poll_fn.rs +++ b/futures-util/src/async_trait/poll_fn.rs @@ -2,7 +2,7 @@ use core::mem::Pin; -use futures_core::{Future, Poll}; +use futures_core::{Async, Poll}; use futures_core::task; /// A future which adapts a function returning `Poll`. @@ -41,7 +41,7 @@ pub fn poll_fn(f: F) -> PollFn PollFn { inner: f } } -impl Future for PollFn +impl Async for PollFn where F: FnMut(&mut task::Context) -> Poll { type Output = T; diff --git a/futures-util/src/async_trait/select.rs b/futures-util/src/async_trait/select.rs new file mode 100644 index 0000000000..5ea1a77399 --- /dev/null +++ b/futures-util/src/async_trait/select.rs @@ -0,0 +1,41 @@ +use futures_core::{Async, Poll, Async}; +use futures_core::task; + +use either::Either; + +/// Async for the `select` combinator, waiting for one of two differently-typed +/// futures to complete. +/// +/// This is created by the [`Async::select`] method. +/// +/// [`Async::select`]: trait.Async.html#method.select +#[must_use = "futures do nothing unless polled"] +#[derive(Debug)] +pub struct Select { + inner: Option<(A, B)>, +} + +pub fn new(a: A, b: B) -> Select { + Select { inner: Some((a, b)) } +} + +impl Async for Select where A: Async, B: Async { + type Item = Either<(A::Item, B), (B::Item, A)>; + type Error = Either<(A::Error, B), (B::Error, A)>; + + fn poll(&mut self, cx: &mut task::Context) -> Poll { + let (mut a, mut b) = self.inner.take().expect("cannot poll Select twice"); + match a.poll(cx) { + Err(e) => Err(Either::Left((e, b))), + Ok(Async::Ready(x)) => Ok(Async::Ready(Either::Left((x, b)))), + Ok(Async::Pending) => match b.poll(cx) { + Err(e) => Err(Either::Right((e, a))), + Ok(Async::Ready(x)) => Ok(Async::Ready(Either::Right((x, a)))), + Ok(Async::Pending) => { + self.inner = Some((a, b)); + Ok(Async::Pending) + } + } + } + } +} diff --git a/futures-util/src/async_trait/select_all.rs b/futures-util/src/async_trait/select_all.rs new file mode 100644 index 0000000000..4798e6da4d --- /dev/null +++ b/futures-util/src/async_trait/select_all.rs @@ -0,0 +1,72 @@ +//! Definition of the `SelectAll`, finding the first future in a list that +//! finishes. + +use std::mem; +use std::prelude::v1::*; + +use futures_core::{Async, IntoAsync, Poll, Async}; +use futures_core::task; + +/// Async for the `select_all` combinator, waiting for one of any of a list of +/// futures to complete. +/// +/// This is created by the `select_all` function. +#[derive(Debug)] +#[must_use = "futures do nothing unless polled"] +pub struct SelectAll where A: Async { + inner: Vec, +} + +#[doc(hidden)] +pub type SelectAllNext = A; + +/// Creates a new future which will select over a list of futures. +/// +/// The returned future will wait for any future within `iter` to be ready. Upon +/// completion or failure the item resolved will be returned, along with the +/// index of the future that was ready and the list of all the remaining +/// futures. +/// +/// # Panics +/// +/// This function will panic if the iterator specified contains no items. +pub fn select_all(iter: I) -> SelectAll<::Async> + where I: IntoIterator, + I::Item: IntoAsync, +{ + let ret = SelectAll { + inner: iter.into_iter() + .map(|a| a.into_future()) + .collect(), + }; + assert!(ret.inner.len() > 0); + ret +} + +impl Async for SelectAll + where A: Async, +{ + type Item = (A::Item, usize, Vec); + type Error = (A::Error, usize, Vec); + + fn poll(&mut self, cx: &mut task::Context) -> Poll { + let item = self.inner.iter_mut().enumerate().filter_map(|(i, f)| { + match f.poll(cx) { + Ok(Async::Pending) => None, + Ok(Async::Ready(e)) => Some((i, Ok(e))), + Err(e) => Some((i, Err(e))), + } + }).next(); + match item { + Some((idx, res)) => { + self.inner.remove(idx); + let rest = mem::replace(&mut self.inner, Vec::new()); + match res { + Ok(e) => Ok(Async::Ready((e, idx, rest))), + Err(e) => Err((e, idx, rest)), + } + } + None => Ok(Async::Pending), + } + } +} diff --git a/futures-util/src/async_trait/select_ok.rs b/futures-util/src/async_trait/select_ok.rs new file mode 100644 index 0000000000..b7ed52f3b8 --- /dev/null +++ b/futures-util/src/async_trait/select_ok.rs @@ -0,0 +1,82 @@ +//! Definition of the `SelectOk` combinator, finding the first successful future +//! in a list. + +use std::mem; +use std::prelude::v1::*; + +use futures_core::{Async, IntoAsync, Poll, Async}; +use futures_core::task; + +/// Async for the `select_ok` combinator, waiting for one of any of a list of +/// futures to successfully complete. Unlike `select_all`, this future ignores all +/// but the last error, if there are any. +/// +/// This is created by the `select_ok` function. +#[derive(Debug)] +#[must_use = "futures do nothing unless polled"] +pub struct SelectOk where A: Async { + inner: Vec, +} + +/// Creates a new future which will select the first successful future over a list of futures. +/// +/// The returned future will wait for any future within `iter` to be ready and Ok. Unlike +/// `select_all`, this will only return the first successful completion, or the last +/// failure. This is useful in contexts where any success is desired and failures +/// are ignored, unless all the futures fail. +/// +/// # Panics +/// +/// This function will panic if the iterator specified contains no items. +pub fn select_ok(iter: I) -> SelectOk<::Async> + where I: IntoIterator, + I::Item: IntoAsync, +{ + let ret = SelectOk { + inner: iter.into_iter() + .map(|a| a.into_future()) + .collect(), + }; + assert!(ret.inner.len() > 0); + ret +} + +impl Async for SelectOk where A: Async { + type Item = (A::Item, Vec); + type Error = A::Error; + + fn poll(&mut self, cx: &mut task::Context) -> Poll { + // loop until we've either exhausted all errors, a success was hit, or nothing is ready + loop { + let item = self.inner.iter_mut().enumerate().filter_map(|(i, f)| { + match f.poll(cx) { + Ok(Async::Pending) => None, + Ok(Async::Ready(e)) => Some((i, Ok(e))), + Err(e) => Some((i, Err(e))), + } + }).next(); + + match item { + Some((idx, res)) => { + // always remove Ok or Err, if it's not the last Err continue looping + drop(self.inner.remove(idx)); + match res { + Ok(e) => { + let rest = mem::replace(&mut self.inner, Vec::new()); + return Ok(Async::Ready((e, rest))) + }, + Err(e) => { + if self.inner.is_empty() { + return Err(e) + } + }, + } + } + None => { + // based on the filter above, nothing is ready, return + return Ok(Async::Pending) + }, + } + } + } +} diff --git a/futures-util/src/future/shared.rs b/futures-util/src/async_trait/shared.rs similarity index 94% rename from futures-util/src/future/shared.rs rename to futures-util/src/async_trait/shared.rs index c7b10adf00..5ac159630c 100644 --- a/futures-util/src/future/shared.rs +++ b/futures-util/src/async_trait/shared.rs @@ -26,19 +26,19 @@ use std::sync::atomic::AtomicUsize; use std::sync::atomic::Ordering::SeqCst; use std::collections::HashMap; -use futures_core::{Future, Poll, Async}; +use futures_core::{Async, Poll, Async}; use futures_core::task::{self, Wake, Waker, LocalMap}; /// A future that is cloneable and can be polled in multiple threads. -/// Use `Future::shared()` method to convert any future into a `Shared` future. +/// Use `Async::shared()` method to convert any future into a `Shared` future. #[must_use = "futures do nothing unless polled"] -pub struct Shared { +pub struct Shared { inner: Arc>, waiter: usize, } impl fmt::Debug for Shared - where F: Future + fmt::Debug, + where F: Async + fmt::Debug, F::Item: fmt::Debug, F::Error: fmt::Debug, { @@ -50,7 +50,7 @@ impl fmt::Debug for Shared } } -struct Inner { +struct Inner { next_clone_id: AtomicUsize, future: UnsafeCell>, result: UnsafeCell, SharedError>>>, @@ -68,7 +68,7 @@ const REPOLL: usize = 2; const COMPLETE: usize = 3; const POISONED: usize = 4; -pub fn new(future: F) -> Shared { +pub fn new(future: F) -> Shared { Shared { inner: Arc::new(Inner { next_clone_id: AtomicUsize::new(1), @@ -83,7 +83,7 @@ pub fn new(future: F) -> Shared { } } -impl Shared where F: Future { +impl Shared where F: Async { /// If any clone of this `Shared` has completed execution, returns its result immediately /// without blocking. Otherwise, returns None without triggering the work represented by /// this `Shared`. @@ -117,8 +117,8 @@ impl Shared where F: Future { } } -impl Future for Shared - where F: Future +impl Async for Shared + where F: Async { type Item = SharedItem; type Error = SharedError; @@ -204,7 +204,7 @@ impl Future for Shared } } -impl Clone for Shared where F: Future { +impl Clone for Shared where F: Async { fn clone(&self) -> Self { let next_clone_id = self.inner.next_clone_id.fetch_add(1, SeqCst); @@ -215,7 +215,7 @@ impl Clone for Shared where F: Future { } } -impl Drop for Shared where F: Future { +impl Drop for Shared where F: Async { fn drop(&mut self) { let mut waiters = self.inner.notifier.waiters.lock().unwrap(); waiters.remove(&self.waiter); @@ -235,19 +235,19 @@ impl Wake for Notifier { } unsafe impl Sync for Inner - where F: Future + Send, + where F: Async + Send, F::Item: Send + Sync, F::Error: Send + Sync {} unsafe impl Send for Inner - where F: Future + Send, + where F: Async + Send, F::Item: Send + Sync, F::Error: Send + Sync {} impl fmt::Debug for Inner - where F: Future + fmt::Debug, + where F: Async + fmt::Debug, F::Item: fmt::Debug, F::Error: fmt::Debug, { diff --git a/futures-util/src/future/then.rs b/futures-util/src/async_trait/then.rs similarity index 62% rename from futures-util/src/future/then.rs rename to futures-util/src/async_trait/then.rs index a26feba262..492c06205d 100644 --- a/futures-util/src/future/then.rs +++ b/futures-util/src/async_trait/then.rs @@ -1,31 +1,31 @@ use core::mem::Pin; -use futures_core::{Future, Poll}; +use futures_core::{Async, Poll}; use futures_core::task; use super::chain::Chain; -/// Future for the `then` combinator, chaining computations on the end of +/// Async for the `then` combinator, chaining computations on the end of /// another future regardless of its outcome. /// -/// This is created by the `Future::then` method. +/// This is created by the `Async::then` method. #[derive(Debug)] #[must_use = "futures do nothing unless polled"] -pub struct Then where A: Future, B: Future { +pub struct Then where A: Async, B: Async { state: Chain, } pub fn new(future: A, f: F) -> Then - where A: Future, - B: Future, + where A: Async, + B: Async, { Then { state: Chain::new(future, f), } } -impl Future for Then - where A: Future, - B: Future, +impl Async for Then + where A: Async, + B: Async, F: FnOnce(A::Output) -> B, { type Output = B::Output; diff --git a/futures-util/src/future/with_executor.rs b/futures-util/src/async_trait/with_executor.rs similarity index 69% rename from futures-util/src/future/with_executor.rs rename to futures-util/src/async_trait/with_executor.rs index 4f1310c691..74a6318f06 100644 --- a/futures-util/src/future/with_executor.rs +++ b/futures-util/src/async_trait/with_executor.rs @@ -1,29 +1,29 @@ use core::mem::Pin; -use futures_core::{Future, Poll}; +use futures_core::{Async, Poll}; use futures_core::task; use futures_core::executor::Executor; -/// Future for the `with_executor` combinator, assigning an executor +/// Async for the `with_executor` combinator, assigning an executor /// to be used when spawning other futures. /// -/// This is created by the `Future::with_executor` method. +/// This is created by the `Async::with_executor` method. #[derive(Debug)] #[must_use = "futures do nothing unless polled"] -pub struct WithExecutor where F: Future, E: Executor { +pub struct WithExecutor where F: Async, E: Executor { executor: E, future: F } pub fn new(future: F, executor: E) -> WithExecutor - where F: Future, + where F: Async, E: Executor, { WithExecutor { executor, future } } -impl Future for WithExecutor - where F: Future, +impl Async for WithExecutor + where F: Async, E: Executor, { type Output = F::Output; diff --git a/futures-util/src/future/flatten_stream.rs b/futures-util/src/future/flatten_stream.rs deleted file mode 100644 index b6d71bac67..0000000000 --- a/futures-util/src/future/flatten_stream.rs +++ /dev/null @@ -1,81 +0,0 @@ -use core::fmt; -use core::mem::Pin; - -use futures_core::{Future, Poll, Stream}; -use futures_core::task; - -/// Future for the `flatten_stream` combinator, flattening a -/// future-of-a-stream to get just the result of the final stream as a stream. -/// -/// This is created by the `Future::flatten_stream` method. -#[must_use = "streams do nothing unless polled"] -pub struct FlattenStream { - state: State -} - -impl fmt::Debug for FlattenStream - where F: Future + fmt::Debug, - F::Output: fmt::Debug, -{ - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - fmt.debug_struct("FlattenStream") - .field("state", &self.state) - .finish() - } -} - -pub fn new(f: F) -> FlattenStream { - FlattenStream { - state: State::Future(f) - } -} - -#[derive(Debug)] -enum State { - // future is not yet called or called and not ready - Future(F), - // future resolved to Stream - Stream(F::Output), -} - -impl Stream for FlattenStream - where F: Future, - F::Output: Stream, -{ - type Item = ::Item; - - fn poll_next(mut self: Pin, cx: &mut task::Context) -> Poll> { - loop { - // safety: data is never moved via the resulting &mut reference - let stream = match unsafe { Pin::get_mut(&mut self) }.state { - State::Future(ref mut f) => { - // safety: the future we're re-pinning here will never be moved; - // it will just be polled, then dropped in place - match unsafe { Pin::new_unchecked(f) }.poll(cx) { - Poll::Pending => { - // State is not changed, early return. - return Poll::Pending - }, - Poll::Ready(stream) => { - // Future resolved to stream. - // We do not return, but poll that - // stream in the next loop iteration. - stream - } - } - } - State::Stream(ref mut s) => { - // safety: the stream we're repinning here will never be moved; - // it will just be polled, then dropped in place - return unsafe { Pin::new_unchecked(s) }.poll_next(cx); - } - }; - - unsafe { - // safety: we use the &mut only for an assignment, which causes - // only an in-place drop - Pin::get_mut(&mut self).state = State::Stream(stream); - } - } - } -} diff --git a/futures-util/src/future/into_stream.rs b/futures-util/src/future/into_stream.rs deleted file mode 100644 index 57779fed51..0000000000 --- a/futures-util/src/future/into_stream.rs +++ /dev/null @@ -1,40 +0,0 @@ -use core::mem::Pin; - -use futures_core::{Poll, Future, Stream}; -use futures_core::task; - -/// A type which converts a `Future` into a `Stream` -/// containing a single element. -#[must_use = "futures do nothing unless polled"] -#[derive(Debug)] -pub struct IntoStream { - future: Option -} - -pub fn new(future: F) -> IntoStream { - IntoStream { - future: Some(future) - } -} - -impl Stream for IntoStream { - type Item = F::Output; - - fn poll_next(mut self: Pin, cx: &mut task::Context) -> Poll> { - // safety: we use this &mut only for matching, not for movement - let v = match unsafe { Pin::get_mut(&mut self) }.future { - Some(ref mut fut) => { - // safety: this re-pinned future will never move before being dropped - match unsafe { Pin::new_unchecked(fut) }.poll(cx) { - Poll::Pending => return Poll::Pending, - Poll::Ready(v) => v - } - } - None => return Poll::Ready(None), - }; - - // safety: we use this &mut only for a replacement, which drops the future in place - unsafe { Pin::get_mut(&mut self) }.future = None; - Poll::Ready(Some(v)) - } -} diff --git a/futures-util/src/lib.rs b/futures-util/src/lib.rs index 39afba0a5e..916a8ce57f 100644 --- a/futures-util/src/lib.rs +++ b/futures-util/src/lib.rs @@ -1,4 +1,4 @@ -//! Combinators and utilities for working with `Future`s, `Stream`s, `Sink`s, +//! Combinators and utilities for working with `Async`s, `Stream`s, `Sink`s, //! and the `AsyncRead` and `AsyncWrite` traits. #![feature(pin, arbitrary_self_types)] @@ -20,7 +20,7 @@ extern crate futures_executor; extern crate either; //#[cfg(feature = "std")] -//use futures_core::{Future, Poll, task}; +//use futures_core::{Async, Poll, task}; macro_rules! if_std { ($($i:item)*) => ($( @@ -63,11 +63,11 @@ pub mod lock; mod lock; */ -pub mod future; -pub use future::FutureExt; +pub mod async_trait; +pub use async_trait::AsyncExt; -pub mod future_result; -pub use future_result::FutureResult; +pub mod async_result; +pub use async_result::AsyncResultExt; // #[cfg(feature = "std")] // pub mod io; @@ -83,7 +83,7 @@ pub use future_result::FutureResult; pub mod prelude { //! Prelude containing the extension traits, which add functionality to //! existing asynchronous types. - // pub use {FutureExt, StreamExt, SinkExt}; + // pub use {AsyncExt, StreamExt, SinkExt}; // #[cfg(feature = "std")] // pub use {AsyncReadExt, AsyncWriteExt}; } From c4139ea15d7497c5b916966965def657d965ff91 Mon Sep 17 00:00:00 2001 From: Aaron Turon Date: Tue, 24 Apr 2018 20:58:49 -0700 Subject: [PATCH 5/7] Update futures-sink to 0.3-alpha --- Cargo.toml | 2 +- futures-sink/Cargo.toml | 6 ++-- futures-sink/src/channel_impls.rs | 32 +++++++++---------- futures-sink/src/lib.rs | 52 +++++++++++++++---------------- 4 files changed, 46 insertions(+), 46 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 2d26b6d00f..26909c2b55 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,7 +8,7 @@ members = [ # "futures-io", # "futures-macro-async", # "futures-macro-await", -# "futures-sink", + "futures-sink", # "futures-stable", "futures-util", ] diff --git a/futures-sink/Cargo.toml b/futures-sink/Cargo.toml index 72cfd79e24..502472b375 100644 --- a/futures-sink/Cargo.toml +++ b/futures-sink/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "futures-sink" -version = "0.2.0" +version = "0.3.0-alpha" authors = ["Alex Crichton "] license = "MIT/Apache-2.0" repository = "https://github.com/rust-lang-nursery/futures-rs" @@ -16,5 +16,5 @@ default = ["std"] [dependencies] either = { version = "1.4", default-features = false, optional = true } -futures-core = { path = "../futures-core", version = "0.2.0", default-features = false } -futures-channel = { path = "../futures-channel", version = "0.2.0", default-features = false } +futures-core = { path = "../futures-core", version = "0.3.0-alpha", default-features = false } +futures-channel = { path = "../futures-channel", version = "0.3.0-alpha", default-features = false } diff --git a/futures-sink/src/channel_impls.rs b/futures-sink/src/channel_impls.rs index f79c4b6bab..bfbc5128dd 100644 --- a/futures-sink/src/channel_impls.rs +++ b/futures-sink/src/channel_impls.rs @@ -1,4 +1,4 @@ -use {Async, Sink, Poll}; +use {Sink, Poll, PollResult}; use futures_core::task; use futures_channel::mpsc::{Sender, SendError, UnboundedSender}; @@ -6,7 +6,7 @@ impl Sink for Sender { type SinkItem = T; type SinkError = SendError; - fn poll_ready(&mut self, cx: &mut task::Context) -> Poll<(), Self::SinkError> { + fn poll_ready(&mut self, cx: &mut task::Context) -> PollResult<(), Self::SinkError> { self.poll_ready(cx) } @@ -14,13 +14,13 @@ impl Sink for Sender { self.start_send(msg) } - fn poll_flush(&mut self, _: &mut task::Context) -> Poll<(), Self::SinkError> { - Ok(Async::Ready(())) + fn poll_flush(&mut self, _: &mut task::Context) -> PollResult<(), Self::SinkError> { + Poll::Ready(Ok(())) } - fn poll_close(&mut self, _: &mut task::Context) -> Poll<(), Self::SinkError> { + fn poll_close(&mut self, _: &mut task::Context) -> PollResult<(), Self::SinkError> { self.close_channel(); - Ok(Async::Ready(())) + Poll::Ready(Ok(())) } } @@ -28,7 +28,7 @@ impl Sink for UnboundedSender { type SinkItem = T; type SinkError = SendError; - fn poll_ready(&mut self, cx: &mut task::Context) -> Poll<(), Self::SinkError> { + fn poll_ready(&mut self, cx: &mut task::Context) -> PollResult<(), Self::SinkError> { UnboundedSender::poll_ready(&*self, cx) } @@ -36,13 +36,13 @@ impl Sink for UnboundedSender { self.start_send(msg) } - fn poll_flush(&mut self, _: &mut task::Context) -> Poll<(), Self::SinkError> { - Ok(Async::Ready(())) + fn poll_flush(&mut self, _: &mut task::Context) -> PollResult<(), Self::SinkError> { + Poll::Ready(Ok(())) } - fn poll_close(&mut self, _: &mut task::Context) -> Poll<(), Self::SinkError> { + fn poll_close(&mut self, _: &mut task::Context) -> PollResult<(), Self::SinkError> { self.close_channel(); - Ok(Async::Ready(())) + Poll::Ready(Ok(())) } } @@ -50,7 +50,7 @@ impl<'a, T> Sink for &'a UnboundedSender { type SinkItem = T; type SinkError = SendError; - fn poll_ready(&mut self, cx: &mut task::Context) -> Poll<(), Self::SinkError> { + fn poll_ready(&mut self, cx: &mut task::Context) -> PollResult<(), Self::SinkError> { UnboundedSender::poll_ready(*self, cx) } @@ -59,12 +59,12 @@ impl<'a, T> Sink for &'a UnboundedSender { .map_err(|err| err.into_send_error()) } - fn poll_flush(&mut self, _: &mut task::Context) -> Poll<(), Self::SinkError> { - Ok(Async::Ready(())) + fn poll_flush(&mut self, _: &mut task::Context) -> PollResult<(), Self::SinkError> { + Poll::Ready(Ok(())) } - fn poll_close(&mut self, _: &mut task::Context) -> Poll<(), Self::SinkError> { + fn poll_close(&mut self, _: &mut task::Context) -> PollResult<(), Self::SinkError> { self.close_channel(); - Ok(Async::Ready(())) + Poll::Ready(Ok(())) } } diff --git a/futures-sink/src/lib.rs b/futures-sink/src/lib.rs index 0da8a92215..2c10ad04bc 100644 --- a/futures-sink/src/lib.rs +++ b/futures-sink/src/lib.rs @@ -21,7 +21,7 @@ macro_rules! if_std { )*) } -use futures_core::{Poll, task}; +use futures_core::{PollResult, task}; #[cfg(feature = "either")] extern crate either; @@ -36,7 +36,7 @@ impl Sink for Either type SinkItem = ::SinkItem; type SinkError = ::SinkError; - fn poll_ready(&mut self, cx: &mut task::Context) -> Poll<(), Self::SinkError> { + fn poll_ready(&mut self, cx: &mut task::Context) -> PollResult<(), Self::SinkError> { match *self { Either::Left(ref mut x) => x.poll_ready(cx), Either::Right(ref mut x) => x.poll_ready(cx), @@ -50,14 +50,14 @@ impl Sink for Either } } - fn poll_flush(&mut self, cx: &mut task::Context) -> Poll<(), Self::SinkError> { + fn poll_flush(&mut self, cx: &mut task::Context) -> PollResult<(), Self::SinkError> { match *self { Either::Left(ref mut x) => x.poll_flush(cx), Either::Right(ref mut x) => x.poll_flush(cx), } } - fn poll_close(&mut self, cx: &mut task::Context) -> Poll<(), Self::SinkError> { + fn poll_close(&mut self, cx: &mut task::Context) -> PollResult<(), Self::SinkError> { match *self { Either::Left(ref mut x) => x.poll_close(cx), Either::Right(ref mut x) => x.poll_close(cx), @@ -68,15 +68,15 @@ impl Sink for Either if_std! { mod channel_impls; - use futures_core::Async; + use futures_core::Poll; use futures_core::never::Never; impl Sink for ::std::vec::Vec { type SinkItem = T; type SinkError = Never; - fn poll_ready(&mut self, _: &mut task::Context) -> Poll<(), Self::SinkError> { - Ok(Async::Ready(())) + fn poll_ready(&mut self, _: &mut task::Context) -> PollResult<(), Self::SinkError> { + Poll::Ready(Ok(())) } fn start_send(&mut self, item: Self::SinkItem) -> Result<(), Self::SinkError> { @@ -84,12 +84,12 @@ if_std! { Ok(()) } - fn poll_flush(&mut self, _: &mut task::Context) -> Poll<(), Self::SinkError> { - Ok(Async::Ready(())) + fn poll_flush(&mut self, _: &mut task::Context) -> PollResult<(), Self::SinkError> { + Poll::Ready(Ok(())) } - fn poll_close(&mut self, _: &mut task::Context) -> Poll<(), Self::SinkError> { - Ok(Async::Ready(())) + fn poll_close(&mut self, _: &mut task::Context) -> PollResult<(), Self::SinkError> { + Poll::Ready(Ok(())) } } @@ -97,8 +97,8 @@ if_std! { type SinkItem = T; type SinkError = Never; - fn poll_ready(&mut self, _: &mut task::Context) -> Poll<(), Self::SinkError> { - Ok(Async::Ready(())) + fn poll_ready(&mut self, _: &mut task::Context) -> PollResult<(), Self::SinkError> { + Poll::Ready(Ok(())) } fn start_send(&mut self, item: Self::SinkItem) -> Result<(), Self::SinkError> { @@ -106,12 +106,12 @@ if_std! { Ok(()) } - fn poll_flush(&mut self, _: &mut task::Context) -> Poll<(), Self::SinkError> { - Ok(Async::Ready(())) + fn poll_flush(&mut self, _: &mut task::Context) -> PollResult<(), Self::SinkError> { + Poll::Ready(Ok(())) } - fn poll_close(&mut self, _: &mut task::Context) -> Poll<(), Self::SinkError> { - Ok(Async::Ready(())) + fn poll_close(&mut self, _: &mut task::Context) -> PollResult<(), Self::SinkError> { + Poll::Ready(Ok(())) } } @@ -119,7 +119,7 @@ if_std! { type SinkItem = S::SinkItem; type SinkError = S::SinkError; - fn poll_ready(&mut self, cx: &mut task::Context) -> Poll<(), Self::SinkError> { + fn poll_ready(&mut self, cx: &mut task::Context) -> PollResult<(), Self::SinkError> { (**self).poll_ready(cx) } @@ -127,11 +127,11 @@ if_std! { (**self).start_send(item) } - fn poll_flush(&mut self, cx: &mut task::Context) -> Poll<(), Self::SinkError> { + fn poll_flush(&mut self, cx: &mut task::Context) -> PollResult<(), Self::SinkError> { (**self).poll_flush(cx) } - fn poll_close(&mut self, cx: &mut task::Context) -> Poll<(), Self::SinkError> { + fn poll_close(&mut self, cx: &mut task::Context) -> PollResult<(), Self::SinkError> { (**self).poll_close(cx) } } @@ -182,7 +182,7 @@ pub trait Sink { /// /// In most cases, if the sink encounters an error, the sink will /// permanently be unable to receive items. - fn poll_ready(&mut self, cx: &mut task::Context) -> Poll<(), Self::SinkError>; + fn poll_ready(&mut self, cx: &mut task::Context) -> PollResult<(), Self::SinkError>; /// Begin the process of sending a value to the sink. /// Each call to this function must be proceeded by a successful call to @@ -218,7 +218,7 @@ pub trait Sink { /// /// In most cases, if the sink encounters an error, the sink will /// permanently be unable to receive items. - fn poll_flush(&mut self, cx: &mut task::Context) -> Poll<(), Self::SinkError>; + fn poll_flush(&mut self, cx: &mut task::Context) -> PollResult<(), Self::SinkError>; /// Flush any remaining output and close this sink, if necessary. /// @@ -231,14 +231,14 @@ pub trait Sink { /// /// If this function encounters an error, the sink should be considered to /// have failed permanently, and no more `Sink` methods should be called. - fn poll_close(&mut self, cx: &mut task::Context) -> Poll<(), Self::SinkError>; + fn poll_close(&mut self, cx: &mut task::Context) -> PollResult<(), Self::SinkError>; } impl<'a, S: ?Sized + Sink> Sink for &'a mut S { type SinkItem = S::SinkItem; type SinkError = S::SinkError; - fn poll_ready(&mut self, cx: &mut task::Context) -> Poll<(), Self::SinkError> { + fn poll_ready(&mut self, cx: &mut task::Context) -> PollResult<(), Self::SinkError> { (**self).poll_ready(cx) } @@ -246,11 +246,11 @@ impl<'a, S: ?Sized + Sink> Sink for &'a mut S { (**self).start_send(item) } - fn poll_flush(&mut self, cx: &mut task::Context) -> Poll<(), Self::SinkError> { + fn poll_flush(&mut self, cx: &mut task::Context) -> PollResult<(), Self::SinkError> { (**self).poll_flush(cx) } - fn poll_close(&mut self, cx: &mut task::Context) -> Poll<(), Self::SinkError> { + fn poll_close(&mut self, cx: &mut task::Context) -> PollResult<(), Self::SinkError> { (**self).poll_close(cx) } } From e3f478162ae2d1d7a97281a44477c156ae3ef111 Mon Sep 17 00:00:00 2001 From: Aaron Turon Date: Tue, 24 Apr 2018 21:08:24 -0700 Subject: [PATCH 6/7] Add back try_ready! --- futures-core/src/poll.rs | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/futures-core/src/poll.rs b/futures-core/src/poll.rs index 1dfcfa884e..76e129b1fd 100644 --- a/futures-core/src/poll.rs +++ b/futures-core/src/poll.rs @@ -46,3 +46,16 @@ impl From for Poll { /// Shorthand for a `Poll>` value. pub type PollResult = Poll>; + +/// A macro for extracting the successful type of a `Poll`. +/// +/// This macro bakes in propagation of *both* errors and `Pending` signals by +/// returning early. +#[macro_export] +macro_rules! try_ready { + ($e:expr) => (match $e { + $crate::Poll::Pending => return $crate::Poll::Pending, + $crate::Poll::Ready(Ok(t)) => t, + $crate::Poll::Ready(Err(e)) => return $crate::Poll::Ready(Err(From::from(e))), + }) +} From 8b70f49c6e1b4a7094388e02fadcfb2d069e01e8 Mon Sep 17 00:00:00 2001 From: Aaron Turon Date: Tue, 24 Apr 2018 21:59:52 -0700 Subject: [PATCH 7/7] Pull in Future combinators (but do not update to new combinator names etc) --- futures-core/src/poll.rs | 26 +- futures-util/Cargo.toml | 2 +- futures-util/src/future/and_then.rs | 40 + futures-util/src/future/catch_unwind.rs | 45 + futures-util/src/future/chain.rs | 50 ++ futures-util/src/future/empty.rs | 32 + futures-util/src/future/err_into.rs | 38 + futures-util/src/future/flatten.rs | 53 ++ futures-util/src/future/flatten_sink.rs | 80 ++ futures-util/src/future/flatten_stream.rs | 99 ++ futures-util/src/future/fuse.rs | 34 + futures-util/src/future/inspect.rs | 38 + futures-util/src/future/inspect_err.rs | 38 + futures-util/src/future/into_stream.rs | 35 + futures-util/src/future/join.rs | 176 ++++ futures-util/src/future/join_all.rs | 144 +++ futures-util/src/future/lazy.rs | 88 ++ futures-util/src/future/loop_fn.rs | 105 +++ futures-util/src/future/map.rs | 37 + futures-util/src/future/map_err.rs | 37 + futures-util/src/future/mod.rs | 1000 +++++++++++++++++++++ futures-util/src/future/or_else.rs | 40 + futures-util/src/future/poll_fn.rs | 51 ++ futures-util/src/future/recover.rs | 36 + futures-util/src/future/select.rs | 41 + futures-util/src/future/select_all.rs | 71 ++ futures-util/src/future/select_ok.rs | 81 ++ futures-util/src/future/shared.rs | 308 +++++++ futures-util/src/future/then.rs | 37 + futures-util/src/future/with_executor.rs | 33 + futures-util/src/lib.rs | 13 +- 31 files changed, 2901 insertions(+), 7 deletions(-) create mode 100644 futures-util/src/future/and_then.rs create mode 100644 futures-util/src/future/catch_unwind.rs create mode 100644 futures-util/src/future/chain.rs create mode 100644 futures-util/src/future/empty.rs create mode 100644 futures-util/src/future/err_into.rs create mode 100644 futures-util/src/future/flatten.rs create mode 100644 futures-util/src/future/flatten_sink.rs create mode 100644 futures-util/src/future/flatten_stream.rs create mode 100644 futures-util/src/future/fuse.rs create mode 100644 futures-util/src/future/inspect.rs create mode 100644 futures-util/src/future/inspect_err.rs create mode 100644 futures-util/src/future/into_stream.rs create mode 100755 futures-util/src/future/join.rs create mode 100644 futures-util/src/future/join_all.rs create mode 100644 futures-util/src/future/lazy.rs create mode 100644 futures-util/src/future/loop_fn.rs create mode 100644 futures-util/src/future/map.rs create mode 100644 futures-util/src/future/map_err.rs create mode 100644 futures-util/src/future/mod.rs create mode 100644 futures-util/src/future/or_else.rs create mode 100644 futures-util/src/future/poll_fn.rs create mode 100644 futures-util/src/future/recover.rs create mode 100644 futures-util/src/future/select.rs create mode 100644 futures-util/src/future/select_all.rs create mode 100644 futures-util/src/future/select_ok.rs create mode 100644 futures-util/src/future/shared.rs create mode 100644 futures-util/src/future/then.rs create mode 100644 futures-util/src/future/with_executor.rs diff --git a/futures-core/src/poll.rs b/futures-core/src/poll.rs index 76e129b1fd..0bb1899f74 100644 --- a/futures-core/src/poll.rs +++ b/futures-core/src/poll.rs @@ -38,6 +38,17 @@ impl Poll { } } +impl Poll> { + /// Convenience for with with a `PollResult` as a `Result` + pub fn ok(self) -> Result, E> { + match self { + Poll::Pending => Ok(Poll::Pending), + Poll::Ready(Ok(t)) => Ok(Poll::Ready(t)), + Poll::Ready(Err(e)) => Err(e), + } + } +} + impl From for Poll { fn from(t: T) -> Poll { Poll::Ready(t) @@ -47,7 +58,7 @@ impl From for Poll { /// Shorthand for a `Poll>` value. pub type PollResult = Poll>; -/// A macro for extracting the successful type of a `Poll`. +/// A macro for extracting the successful type of a `PollResult`. /// /// This macro bakes in propagation of *both* errors and `Pending` signals by /// returning early. @@ -59,3 +70,16 @@ macro_rules! try_ready { $crate::Poll::Ready(Err(e)) => return $crate::Poll::Ready(Err(From::from(e))), }) } + +/// A macro for extracting the successful type of a `PollResult`. +/// +/// This macro bakes in propagation of errors, but not `Pending` signals, by +/// returning early. +#[macro_export] +macro_rules! try_poll { + ($e:expr) => (match $e { + $crate::Poll::Pending => $crate::Poll::Pending, + $crate::Poll::Ready(Ok(t)) => $crate::Poll::Ready(t), + $crate::Poll::Ready(Err(e)) => return $crate::Poll::Ready(Err(From::from(e))), + }) +} diff --git a/futures-util/Cargo.toml b/futures-util/Cargo.toml index 510f72cd32..1092e281aa 100644 --- a/futures-util/Cargo.toml +++ b/futures-util/Cargo.toml @@ -21,7 +21,7 @@ bench = [] futures-core = { path = "../futures-core", version = "0.3.0-alpha", default-features = false } futures-channel = { path = "../futures-channel", version = "0.3.0-alpha", default-features = false } # futures-io = { path = "../futures-io", version = "0.2.0", default-features = false } -# futures-sink = { path = "../futures-sink", version = "0.2.0", default-features = false} +futures-sink = { path = "../futures-sink", version = "0.3.0-alpha", default-features = false} either = { version = "1.4", default-features = false } [dev-dependencies] diff --git a/futures-util/src/future/and_then.rs b/futures-util/src/future/and_then.rs new file mode 100644 index 0000000000..8b49960925 --- /dev/null +++ b/futures-util/src/future/and_then.rs @@ -0,0 +1,40 @@ +use futures_core::{Future, IntoFuture, PollResult}; +use futures_core::task; + +use super::chain::Chain; + +/// Future for the `and_then` combinator, chaining a computation onto the end of +/// another future which completes successfully. +/// +/// This is created by the `Future::and_then` method. +#[derive(Debug)] +#[must_use = "futures do nothing unless polled"] +pub struct AndThen where A: Future, B: IntoFuture { + state: Chain, +} + +pub fn new(future: A, f: F) -> AndThen + where A: Future, + B: IntoFuture, +{ + AndThen { + state: Chain::new(future, f), + } +} + +impl Future for AndThen + where A: Future, + B: IntoFuture, + F: FnOnce(A::Item) -> B, +{ + type Item = B::Item; + type Error = B::Error; + + fn poll(&mut self, cx: &mut task::Context) -> PollResult { + self.state.poll(cx, |result, f| { + result.map(|e| { + Err(f(e).into_future()) + }) + }) + } +} diff --git a/futures-util/src/future/catch_unwind.rs b/futures-util/src/future/catch_unwind.rs new file mode 100644 index 0000000000..7a6fcb9ce9 --- /dev/null +++ b/futures-util/src/future/catch_unwind.rs @@ -0,0 +1,45 @@ +use std::prelude::v1::*; +use std::any::Any; +use std::panic::{catch_unwind, UnwindSafe, AssertUnwindSafe}; + +use futures_core::{Future, PollResult, Poll}; +use futures_core::task; + +/// Future for the `catch_unwind` combinator. +/// +/// This is created by the `Future::catch_unwind` method. +#[derive(Debug)] +#[must_use = "futures do nothing unless polled"] +pub struct CatchUnwind where F: Future { + future: Option, +} + +pub fn new(future: F) -> CatchUnwind + where F: Future + UnwindSafe, +{ + CatchUnwind { + future: Some(future), + } +} + +impl Future for CatchUnwind + where F: Future + UnwindSafe, +{ + type Item = Result; + type Error = Box; + + fn poll(&mut self, cx: &mut task::Context) -> PollResult { + let mut future = self.future.take().expect("cannot poll twice"); + let outcome = catch_unwind(AssertUnwindSafe(|| { + (future.poll(cx), future) + })); + match outcome { + Err(e) => Poll::Ready(Err(e)), + Ok((Poll::Pending, future)) => { + self.future = Some(future); + Poll::Pending + }, + Ok((Poll::Ready(r), _)) => Poll::Ready(Ok(r)), + } + } +} diff --git a/futures-util/src/future/chain.rs b/futures-util/src/future/chain.rs new file mode 100644 index 0000000000..fe75f98f32 --- /dev/null +++ b/futures-util/src/future/chain.rs @@ -0,0 +1,50 @@ +use core::mem; + +use futures_core::{Future, PollResult, Poll}; +use futures_core::task; + +#[must_use = "futures do nothing unless polled"] +#[derive(Debug)] +pub enum Chain where A: Future { + First(A, C), + Second(B), + Done, +} + +impl Chain + where A: Future, + B: Future, +{ + pub fn new(a: A, c: C) -> Chain { + Chain::First(a, c) + } + + pub fn poll(&mut self, cx: &mut task::Context, f: F) -> PollResult + where F: FnOnce(Result, C) + -> Result, B::Error>, + { + let a_result = match *self { + Chain::First(ref mut a, _) => { + match a.poll(cx) { + Poll::Pending => return Poll::Pending, + Poll::Ready(r) => r, + } + } + Chain::Second(ref mut b) => return b.poll(cx), + Chain::Done => panic!("cannot poll a chained future twice"), + }; + let data = match mem::replace(self, Chain::Done) { + Chain::First(_, c) => c, + _ => panic!(), + }; + match f(a_result, data) { + Err(e) => Poll::Ready(Err(e)), + Ok(Ok(e)) => Poll::Ready(Ok(e)), + Ok(Err(mut b)) => { + let ret = b.poll(cx); + *self = Chain::Second(b); + ret + } + } + } +} diff --git a/futures-util/src/future/empty.rs b/futures-util/src/future/empty.rs new file mode 100644 index 0000000000..aaddb8025a --- /dev/null +++ b/futures-util/src/future/empty.rs @@ -0,0 +1,32 @@ +//! Definition of the Empty combinator, a future that's never ready. + +use core::marker; + +use futures_core::{Future, PollResult, Poll}; +use futures_core::task; + +/// A future which is never resolved. +/// +/// This future can be created with the `empty` function. +#[derive(Debug)] +#[must_use = "futures do nothing unless polled"] +pub struct Empty { + _data: marker::PhantomData<(T, E)>, +} + +/// Creates a future which never resolves, representing a computation that never +/// finishes. +/// +/// The returned future will forever return `Async::Pending`. +pub fn empty() -> Empty { + Empty { _data: marker::PhantomData } +} + +impl Future for Empty { + type Item = T; + type Error = E; + + fn poll(&mut self, _: &mut task::Context) -> PollResult { + Poll::Pending + } +} diff --git a/futures-util/src/future/err_into.rs b/futures-util/src/future/err_into.rs new file mode 100644 index 0000000000..059e50aa68 --- /dev/null +++ b/futures-util/src/future/err_into.rs @@ -0,0 +1,38 @@ +use core::marker::PhantomData; + +use futures_core::{Future, PollResult, Poll}; +use futures_core::task; + +/// Future for the `err_into` combinator, changing the error type of a future. +/// +/// This is created by the `Future::err_into` method. +#[derive(Debug)] +#[must_use = "futures do nothing unless polled"] +pub struct ErrInto where A: Future { + future: A, + f: PhantomData +} + +pub fn new(future: A) -> ErrInto + where A: Future +{ + ErrInto { + future: future, + f: PhantomData + } +} + +impl Future for ErrInto + where A::Error: Into +{ + type Item = A::Item; + type Error = E; + + fn poll(&mut self, cx: &mut task::Context) -> PollResult { + let e = match self.future.poll(cx) { + Poll::Pending => return Poll::Pending, + Poll::Ready(r) => r, + }; + Poll::Ready(e.map_err(Into::into)) + } +} diff --git a/futures-util/src/future/flatten.rs b/futures-util/src/future/flatten.rs new file mode 100644 index 0000000000..42674b8e77 --- /dev/null +++ b/futures-util/src/future/flatten.rs @@ -0,0 +1,53 @@ +use core::fmt; + +use futures_core::{Future, IntoFuture, PollResult}; +use futures_core::task; + +use super::chain::Chain; + +/// Future for the `flatten` combinator. +/// +/// This combinator turns a `Future`-of-a-`Future` into a single `Future`. +/// +/// This is created by the `Future::flatten` method. +#[must_use = "futures do nothing unless polled"] +pub struct Flatten where A: Future, A::Item: IntoFuture { + state: Chain::Future, ()>, +} + +impl fmt::Debug for Flatten + where A: Future + fmt::Debug, + A::Item: IntoFuture, + <::Item as IntoFuture>::Future: fmt::Debug, +{ + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + fmt.debug_struct("Flatten") + .field("state", &self.state) + .finish() + } +} + +pub fn new(future: A) -> Flatten + where A: Future, + A::Item: IntoFuture, +{ + Flatten { + state: Chain::new(future, ()), + } +} + +impl Future for Flatten + where A: Future, + A::Item: IntoFuture, + <::Item as IntoFuture>::Error: From<::Error> +{ + type Item = <::Item as IntoFuture>::Item; + type Error = <::Item as IntoFuture>::Error; + + fn poll(&mut self, cx: &mut task::Context) -> PollResult { + self.state.poll(cx, |a, ()| { + let future = a?.into_future(); + Ok(Err(future)) + }) + } +} diff --git a/futures-util/src/future/flatten_sink.rs b/futures-util/src/future/flatten_sink.rs new file mode 100644 index 0000000000..5839d05d09 --- /dev/null +++ b/futures-util/src/future/flatten_sink.rs @@ -0,0 +1,80 @@ +use core::fmt; + +use futures_core::{task, Poll, PollResult, Future}; +use futures_sink::Sink; + +#[derive(Debug)] +enum State where F: Future, ::Item: Sink { + Waiting(F), + Ready(F::Item), + Closed, +} + +/// Future for the `flatten_sink` combinator, flattening a +/// future-of-a-sink to get just the result of the final sink as a sink. +/// +/// This is created by the `Future::flatten_sink` method. +pub struct FlattenSink where F: Future, ::Item: Sink { + st: State +} + +impl fmt::Debug for FlattenSink + where F: Future + fmt::Debug, + ::Item: Sink + fmt::Debug, +{ + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + fmt.debug_struct("FlattenStream") + .field("state", &self.st) + .finish() + } +} + +impl Sink for FlattenSink where F: Future, ::Item: Sink { + type SinkItem = <::Item as Sink>::SinkItem; + type SinkError = <::Item as Sink>::SinkError; + + fn poll_ready(&mut self, cx: &mut task::Context) -> PollResult<(), Self::SinkError> { + let mut resolved_stream = match self.st { + State::Ready(ref mut s) => return s.poll_ready(cx), + State::Waiting(ref mut f) => match try_poll!(f.poll(cx)) { + Poll::Pending => return Poll::Pending, + Poll::Ready(s) => s, + }, + State::Closed => panic!("poll_ready called after eof"), + }; + let result = resolved_stream.poll_ready(cx); + self.st = State::Ready(resolved_stream); + result + } + + fn start_send(&mut self, item: Self::SinkItem) -> Result<(), Self::SinkError> { + match self.st { + State::Ready(ref mut s) => s.start_send(item), + State::Waiting(_) => panic!("poll_ready not called first"), + State::Closed => panic!("start_send called after eof"), + } + } + + fn poll_flush(&mut self, cx: &mut task::Context) -> PollResult<(), Self::SinkError> { + match self.st { + State::Ready(ref mut s) => s.poll_flush(cx), + // if sink not yet resolved, nothing written ==> everything flushed + State::Waiting(_) => Poll::Ready(Ok(())), + State::Closed => panic!("poll_flush called after eof"), + } + } + + fn poll_close(&mut self, cx: &mut task::Context) -> PollResult<(), Self::SinkError> { + if let State::Ready(ref mut s) = self.st { + try_poll!(s.poll_close(cx)); + } + self.st = State::Closed; + return Poll::Ready(Ok(())); + } +} + +pub fn new(fut: F) -> FlattenSink where F: Future, ::Item: Sink { + FlattenSink { + st: State::Waiting(fut) + } +} diff --git a/futures-util/src/future/flatten_stream.rs b/futures-util/src/future/flatten_stream.rs new file mode 100644 index 0000000000..c3a1cacefd --- /dev/null +++ b/futures-util/src/future/flatten_stream.rs @@ -0,0 +1,99 @@ +use core::fmt; + +use futures_core::{Poll, Future, PollResult, Stream}; +use futures_core::task; + +/// Future for the `flatten_stream` combinator, flattening a +/// future-of-a-stream to get just the result of the final stream as a stream. +/// +/// This is created by the `Future::flatten_stream` method. +#[must_use = "streams do nothing unless polled"] +pub struct FlattenStream + where F: Future, + ::Item: Stream, +{ + state: State +} + +impl fmt::Debug for FlattenStream + where F: Future + fmt::Debug, + ::Item: Stream + fmt::Debug, +{ + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + fmt.debug_struct("FlattenStream") + .field("state", &self.state) + .finish() + } +} + +pub fn new(f: F) -> FlattenStream + where F: Future, + ::Item: Stream, +{ + FlattenStream { + state: State::Future(f) + } +} + +#[derive(Debug)] +enum State + where F: Future, + ::Item: Stream, +{ + // future is not yet called or called and not ready + Future(F), + // future resolved to Stream + Stream(F::Item), + // EOF after future resolved to error + Eof, + // after EOF after future resolved to error + Done, +} + +impl Stream for FlattenStream + where F: Future, + ::Item: Stream, +{ + type Item = ::Item; + type Error = ::Error; + + fn poll_next(&mut self, cx: &mut task::Context) -> PollResult, Self::Error> { + loop { + let (next_state, ret_opt) = match self.state { + State::Future(ref mut f) => { + match f.poll(cx) { + Poll::Pending => { + // State is not changed, early return. + return Poll::Pending + }, + Poll::Ready(Ok(stream)) => { + // Future resolved to stream. + // We do not return, but poll that + // stream in the next loop iteration. + (State::Stream(stream), None) + } + Poll::Ready(Err(e)) => { + (State::Eof, Some(Poll::Ready(Err(e)))) + } + } + } + State::Stream(ref mut s) => { + // Just forward call to the stream, + // do not track its state. + return s.poll_next(cx); + } + State::Eof => { + (State::Done, Some(Poll::Ready(Ok(None)))) + } + State::Done => { + panic!("poll called after eof"); + } + }; + + self.state = next_state; + if let Some(ret) = ret_opt { + return ret; + } + } + } +} diff --git a/futures-util/src/future/fuse.rs b/futures-util/src/future/fuse.rs new file mode 100644 index 0000000000..d1e428f58d --- /dev/null +++ b/futures-util/src/future/fuse.rs @@ -0,0 +1,34 @@ +use futures_core::{Future, PollResult, Poll}; +use futures_core::task; + +/// A future which "fuses" a future once it's been resolved. +/// +/// Normally futures can behave unpredictable once they're used after a future +/// has been resolved, but `Fuse` is always defined to return `Async::Pending` +/// from `poll` after it has resolved successfully or returned an error. +/// +/// This is created by the `Future::fuse` method. +#[derive(Debug)] +#[must_use = "futures do nothing unless polled"] +pub struct Fuse { + future: Option, +} + +pub fn new(f: A) -> Fuse { + Fuse { + future: Some(f), + } +} + +impl Future for Fuse { + type Item = A::Item; + type Error = A::Error; + + fn poll(&mut self, cx: &mut task::Context) -> PollResult { + let res = self.future.as_mut().map(|f| f.poll(cx)); + res.unwrap_or(Poll::Pending).map(|res| { + self.future = None; + res + }) + } +} diff --git a/futures-util/src/future/inspect.rs b/futures-util/src/future/inspect.rs new file mode 100644 index 0000000000..38775ed72a --- /dev/null +++ b/futures-util/src/future/inspect.rs @@ -0,0 +1,38 @@ +use futures_core::{Future, PollResult, Poll}; +use futures_core::task; + +/// Do something with the item of a future, passing it on. +/// +/// This is created by the [`FutureExt::inspect`] method. +#[derive(Debug)] +#[must_use = "futures do nothing unless polled"] +pub struct Inspect where A: Future { + future: A, + f: Option, +} + +pub fn new(future: A, f: F) -> Inspect + where A: Future, + F: FnOnce(&A::Item), +{ + Inspect { + future: future, + f: Some(f), + } +} + +impl Future for Inspect + where A: Future, + F: FnOnce(&A::Item), +{ + type Item = A::Item; + type Error = A::Error; + + fn poll(&mut self, cx: &mut task::Context) -> PollResult { + let res = self.future.poll(cx); + if let Poll::Ready(Ok(ref e)) = res { + (self.f.take().expect("cannot poll Inspect twice"))(&e); + } + res + } +} diff --git a/futures-util/src/future/inspect_err.rs b/futures-util/src/future/inspect_err.rs new file mode 100644 index 0000000000..be15f41b80 --- /dev/null +++ b/futures-util/src/future/inspect_err.rs @@ -0,0 +1,38 @@ +use futures_core::{Future, PollResult, Poll}; +use futures_core::task; + +/// Do something with the error of a future, passing it on. +/// +/// This is created by the [`FutureExt::inspect_err`] method. +#[derive(Debug)] +#[must_use = "futures do nothing unless polled"] +pub struct InspectErr where A: Future { + future: A, + f: Option, +} + +pub fn new(future: A, f: F) -> InspectErr + where A: Future, + F: FnOnce(&A::Error), +{ + InspectErr { + future: future, + f: Some(f), + } +} + +impl Future for InspectErr + where A: Future, + F: FnOnce(&A::Error), +{ + type Item = A::Item; + type Error = A::Error; + + fn poll(&mut self, cx: &mut task::Context) -> PollResult { + let res = self.future.poll(cx); + if let Poll::Ready(Err(ref e)) = res { + (self.f.take().expect("cannot poll InspectErr twice"))(&e); + } + res + } +} diff --git a/futures-util/src/future/into_stream.rs b/futures-util/src/future/into_stream.rs new file mode 100644 index 0000000000..ab4542060f --- /dev/null +++ b/futures-util/src/future/into_stream.rs @@ -0,0 +1,35 @@ +use futures_core::{Poll, PollResult, Future, Stream}; +use futures_core::task; + +/// A type which converts a `Future` into a `Stream` +/// containing a single element. +#[must_use = "futures do nothing unless polled"] +#[derive(Debug)] +pub struct IntoStream { + future: Option +} + +pub fn new(future: F) -> IntoStream { + IntoStream { + future: Some(future) + } +} + +impl Stream for IntoStream { + type Item = F::Item; + type Error = F::Error; + + fn poll_next(&mut self, cx: &mut task::Context) -> PollResult, Self::Error> { + let ret = match self.future { + None => return Poll::Ready(Ok(None)), + Some(ref mut future) => { + match future.poll(cx) { + Poll::Pending => return Poll::Pending, + Poll::Ready(r) => r, + } + } + }; + self.future = None; + Poll::Ready(ret.map(Some)) + } +} diff --git a/futures-util/src/future/join.rs b/futures-util/src/future/join.rs new file mode 100755 index 0000000000..4b0de33372 --- /dev/null +++ b/futures-util/src/future/join.rs @@ -0,0 +1,176 @@ +#![allow(non_snake_case)] + +use core::fmt; +use core::mem; + +use futures_core::{Future, PollResult, Poll}; +use futures_core::task; + +macro_rules! generate { + ($( + $(#[$doc:meta])* + ($Join:ident, $new:ident, ), + )*) => ($( + $(#[$doc])* + #[must_use = "futures do nothing unless polled"] + pub struct $Join + where A: Future, + $($B: Future),* + { + a: MaybeDone, + $($B: MaybeDone<$B>,)* + } + + impl fmt::Debug for $Join + where A: Future + fmt::Debug, + A::Item: fmt::Debug, + $( + $B: Future + fmt::Debug, + $B::Item: fmt::Debug + ),* + { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + fmt.debug_struct(stringify!($Join)) + .field("a", &self.a) + $(.field(stringify!($B), &self.$B))* + .finish() + } + } + + pub fn $new(a: A, $($B: $B),*) -> $Join + where A: Future, + $($B: Future),* + { + $Join { + a: MaybeDone::NotYet(a), + $($B: MaybeDone::NotYet($B)),* + } + } + + impl $Join + where A: Future, + $($B: Future),* + { + fn erase(&mut self) { + self.a = MaybeDone::Gone; + $(self.$B = MaybeDone::Gone;)* + } + } + + impl Future for $Join + where A: Future, + $($B: Future),* + { + type Item = (A::Item, $($B::Item),*); + type Error = A::Error; + + fn poll(&mut self, cx: &mut task::Context) -> PollResult { + let mut all_done = match self.a.poll(cx) { + Ok(done) => done, + Err(e) => { + self.erase(); + return Poll::Ready(Err(e)) + } + }; + $( + all_done = match self.$B.poll(cx) { + Ok(done) => all_done && done, + Err(e) => { + self.erase(); + return Poll::Ready(Err(e)) + } + }; + )* + + if all_done { + Poll::Ready(Ok((self.a.take(), $(self.$B.take()),*))) + } else { + Poll::Pending + } + } + } + + // Incoherent-- add to futures-core when stable. + /* + impl IntoFuture for (A, $($B),*) + where A: IntoFuture, + $( + $B: IntoFuture + ),* + { + type Future = $Join; + type Item = (A::Item, $($B::Item),*); + type Error = A::Error; + + fn into_future(self) -> Self::Future { + match self { + (a, $($B),+) => { + $new( + IntoFuture::into_future(a), + $(IntoFuture::into_future($B)),+ + ) + } + } + } + } + */ + + )*) +} + +generate! { + /// Future for the `join` combinator, waiting for two futures to + /// complete. + /// + /// This is created by the `Future::join` method. + (Join, new, ), + + /// Future for the `join3` combinator, waiting for three futures to + /// complete. + /// + /// This is created by the `Future::join3` method. + (Join3, new3, ), + + /// Future for the `join4` combinator, waiting for four futures to + /// complete. + /// + /// This is created by the `Future::join4` method. + (Join4, new4, ), + + /// Future for the `join5` combinator, waiting for five futures to + /// complete. + /// + /// This is created by the `Future::join5` method. + (Join5, new5, ), +} + +#[derive(Debug)] +enum MaybeDone { + NotYet(A), + Done(A::Item), + Gone, +} + +impl MaybeDone { + fn poll(&mut self, cx: &mut task::Context) -> Result { + let res = match *self { + MaybeDone::NotYet(ref mut a) => a.poll(cx).ok()?, + MaybeDone::Done(_) => return Ok(true), + MaybeDone::Gone => panic!("cannot poll Join twice"), + }; + match res { + Poll::Ready(res) => { + *self = MaybeDone::Done(res); + Ok(true) + } + Poll::Pending => Ok(false), + } + } + + fn take(&mut self) -> A::Item { + match mem::replace(self, MaybeDone::Gone) { + MaybeDone::Done(a) => a, + _ => panic!(), + } + } +} diff --git a/futures-util/src/future/join_all.rs b/futures-util/src/future/join_all.rs new file mode 100644 index 0000000000..0e8710d817 --- /dev/null +++ b/futures-util/src/future/join_all.rs @@ -0,0 +1,144 @@ +//! Definition of the `JoinAll` combinator, waiting for all of a list of futures +//! to finish. + +use std::prelude::v1::*; + +use std::fmt; +use std::mem; +use std::iter::FromIterator; + +use futures_core::{Future, IntoFuture, PollResult, Poll}; +use futures_core::task; + +#[derive(Debug)] +enum ElemState where F: Future { + Pending(F), + Done(F::Item), +} + +/// A future which takes a list of futures and resolves with a vector of the +/// completed values. +/// +/// This future is created with the `join_all` method. +#[must_use = "futures do nothing unless polled"] +pub struct JoinAll + where F: Future, +{ + elems: Vec>, +} + +impl fmt::Debug for JoinAll + where F: Future + fmt::Debug, + F::Item: fmt::Debug, +{ + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + fmt.debug_struct("JoinAll") + .field("elems", &self.elems) + .finish() + } +} + +/// Creates a future which represents a collection of the results of the futures +/// given. +/// +/// The returned future will drive execution for all of its underlying futures, +/// collecting the results into a destination `Vec` in the same order as they +/// were provided. If any future returns an error then all other futures will be +/// canceled and an error will be returned immediately. If all futures complete +/// successfully, however, then the returned future will succeed with a `Vec` of +/// all the successful results. +/// +/// # Examples +/// +/// ``` +/// # extern crate futures; +/// use futures::prelude::*; +/// use futures::future::{join_all, ok, err}; +/// +/// # fn main() { +/// # +/// let f = join_all(vec![ +/// ok::(1), +/// ok::(2), +/// ok::(3), +/// ]); +/// let f = f.map(|x| { +/// assert_eq!(x, [1, 2, 3]); +/// }); +/// +/// let f = join_all(vec![ +/// Box::new(ok::(1)), +/// Box::new(err::(2)), +/// Box::new(ok::(3)), +/// ]); +/// let f = f.then(|x| { +/// assert_eq!(x, Err(2)); +/// x +/// }); +/// # } +/// ``` +pub fn join_all(i: I) -> JoinAll<::Future> + where I: IntoIterator, + I::Item: IntoFuture, +{ + let elems = i.into_iter().map(|f| { + ElemState::Pending(f.into_future()) + }).collect(); + JoinAll { elems } +} + +impl Future for JoinAll + where F: Future, +{ + type Item = Vec; + type Error = F::Error; + + + fn poll(&mut self, cx: &mut task::Context) -> PollResult { + let mut all_done = true; + + for idx in 0 .. self.elems.len() { + let done_val = match self.elems[idx] { + ElemState::Pending(ref mut t) => { + match t.poll(cx) { + Poll::Pending => { + all_done = false; + continue + } + Poll::Ready(r) => r, + } + } + ElemState::Done(ref mut _v) => continue, + }; + + match done_val { + Ok(v) => self.elems[idx] = ElemState::Done(v), + Err(e) => { + // On completion drop all our associated resources + // ASAP. + self.elems = Vec::new(); + return Poll::Ready(Err(e)) + } + } + } + + if all_done { + let elems = mem::replace(&mut self.elems, Vec::new()); + let result = elems.into_iter().map(|e| { + match e { + ElemState::Done(t) => t, + _ => unreachable!(), + } + }).collect(); + Poll::Ready(Ok(result)) + } else { + Poll::Pending + } + } +} + +impl FromIterator for JoinAll { + fn from_iter>(iter: T) -> Self { + join_all(iter) + } +} diff --git a/futures-util/src/future/lazy.rs b/futures-util/src/future/lazy.rs new file mode 100644 index 0000000000..34f852c1da --- /dev/null +++ b/futures-util/src/future/lazy.rs @@ -0,0 +1,88 @@ +//! Definition of the Lazy combinator, deferring execution of a function until +//! the future is polled. + +use core::mem; + +use futures_core::{Future, IntoFuture, PollResult}; +use futures_core::task; + +/// A future which defers creation of the actual future until the future +/// is `poll`ed. +/// +/// This is created by the `lazy` function. +#[derive(Debug)] +#[must_use = "futures do nothing unless polled"] +pub struct Lazy { + inner: _Lazy, +} + +#[derive(Debug)] +enum _Lazy { + First(F), + Second(R), + Moved, +} + +/// Creates a new future which will eventually be the same as the one created +/// by the closure provided. +/// +/// The provided closure is only run once the future is polled. +/// Once run, however, this future is the same as the one the closure creates. +/// +/// # Examples +/// +/// ``` +/// # extern crate futures; +/// use futures::prelude::*; +/// use futures::future::{self, FutureResult}; +/// +/// # fn main() { +/// let a = future::lazy(|_| future::ok::(1)); +/// +/// let b = future::lazy(|_| -> FutureResult { +/// panic!("oh no!") +/// }); +/// drop(b); // closure is never run +/// # } +/// ``` +pub fn lazy(f: F) -> Lazy + where F: FnOnce(&mut task::Context) -> R, + R: IntoFuture +{ + Lazy { + inner: _Lazy::First(f), + } +} + +impl Lazy + where F: FnOnce(&mut task::Context) -> R, + R: IntoFuture, +{ + fn get(&mut self, cx: &mut task::Context) -> &mut R::Future { + match self.inner { + _Lazy::First(_) => {} + _Lazy::Second(ref mut f) => return f, + _Lazy::Moved => panic!(), // can only happen if `f()` panics + } + match mem::replace(&mut self.inner, _Lazy::Moved) { + _Lazy::First(f) => self.inner = _Lazy::Second(f(cx).into_future()), + _ => panic!(), // we already found First + } + match self.inner { + _Lazy::Second(ref mut f) => f, + _ => panic!(), // we just stored Second + } + } +} + +impl Future for Lazy + where F: FnOnce(&mut task::Context) -> R, + R: IntoFuture, +{ + type Item = R::Item; + type Error = R::Error; + + fn poll(&mut self, cx: &mut task::Context) -> PollResult { + self.get(cx).poll(cx) + } +} diff --git a/futures-util/src/future/loop_fn.rs b/futures-util/src/future/loop_fn.rs new file mode 100644 index 0000000000..fcc31ed5c0 --- /dev/null +++ b/futures-util/src/future/loop_fn.rs @@ -0,0 +1,105 @@ +//! Definition of the `LoopFn` combinator, implementing `Future` loops. + +use futures_core::{Poll, Future, IntoFuture, PollResult}; +use futures_core::task; + +/// An enum describing whether to `break` or `continue` a `loop_fn` loop. +#[derive(Debug)] +pub enum Loop { + /// Indicates that the loop has completed with output `T`. + Break(T), + + /// Indicates that the loop function should be called again with input + /// state `S`. + Continue(S), +} + +/// A future implementing a tail-recursive loop. +/// +/// Created by the `loop_fn` function. +#[must_use = "futures do nothing unless polled"] +#[derive(Debug)] +pub struct LoopFn where A: IntoFuture { + future: A::Future, + func: F, +} + +/// Creates a new future implementing a tail-recursive loop. +/// +/// The loop function is immediately called with `initial_state` and should +/// return a value that can be converted to a future. On successful completion, +/// this future should output a `Loop` to indicate the status of the +/// loop. +/// +/// `Loop::Break(T)` halts the loop and completes the future with output `T`. +/// +/// `Loop::Continue(S)` reinvokes the loop function with state `S`. The returned +/// future will be subsequently polled for a new `Loop` value. +/// +/// # Examples +/// +/// ``` +/// # extern crate futures; +/// use futures::prelude::*; +/// use futures::future::{self, ok, loop_fn, Loop, FutureResult}; +/// use futures::never::Never; +/// +/// struct Client { +/// ping_count: u8, +/// } +/// +/// impl Client { +/// fn new() -> Self { +/// Client { ping_count: 0 } +/// } +/// +/// fn send_ping(self) -> FutureResult { +/// ok(Client { ping_count: self.ping_count + 1 }) +/// } +/// +/// fn receive_pong(self) -> FutureResult<(Self, bool), Never> { +/// let done = self.ping_count >= 5; +/// ok((self, done)) +/// } +/// } +/// +/// # fn main() { +/// let ping_til_done = loop_fn(Client::new(), |client| { +/// client.send_ping() +/// .and_then(|client| client.receive_pong()) +/// .and_then(|(client, done)| { +/// if done { +/// Ok(Loop::Break(client)) +/// } else { +/// Ok(Loop::Continue(client)) +/// } +/// }) +/// }); +/// # } +/// ``` +pub fn loop_fn(initial_state: S, mut func: F) -> LoopFn + where F: FnMut(S) -> A, + A: IntoFuture>, +{ + LoopFn { + future: func(initial_state).into_future(), + func: func, + } +} + +impl Future for LoopFn + where F: FnMut(S) -> A, + A: IntoFuture>, +{ + type Item = T; + type Error = A::Error; + + fn poll(&mut self, cx: &mut task::Context) -> PollResult { + loop { + match try_ready!(self.future.poll(cx)) { + Loop::Break(x) => return Poll::Ready(Ok(x)), + Loop::Continue(s) => self.future = (self.func)(s).into_future(), + } + } + } +} diff --git a/futures-util/src/future/map.rs b/futures-util/src/future/map.rs new file mode 100644 index 0000000000..9182271a2c --- /dev/null +++ b/futures-util/src/future/map.rs @@ -0,0 +1,37 @@ +use futures_core::{Future, PollResult, Poll}; +use futures_core::task; + +/// Future for the `map` combinator, changing the type of a future. +/// +/// This is created by the `Future::map` method. +#[derive(Debug)] +#[must_use = "futures do nothing unless polled"] +pub struct Map where A: Future { + future: A, + f: Option, +} + +pub fn new(future: A, f: F) -> Map + where A: Future, +{ + Map { + future: future, + f: Some(f), + } +} + +impl Future for Map + where A: Future, + F: FnOnce(A::Item) -> U, +{ + type Item = U; + type Error = A::Error; + + fn poll(&mut self, cx: &mut task::Context) -> PollResult { + let e = match self.future.poll(cx) { + Poll::Pending => return Poll::Pending, + Poll::Ready(r) => r, + }; + Poll::Ready(e.map(self.f.take().expect("cannot poll Map twice"))) + } +} diff --git a/futures-util/src/future/map_err.rs b/futures-util/src/future/map_err.rs new file mode 100644 index 0000000000..baef271ffa --- /dev/null +++ b/futures-util/src/future/map_err.rs @@ -0,0 +1,37 @@ +use futures_core::{Future, PollResult, Poll}; +use futures_core::task; + +/// Future for the `map_err` combinator, changing the error type of a future. +/// +/// This is created by the `Future::map_err` method. +#[derive(Debug)] +#[must_use = "futures do nothing unless polled"] +pub struct MapErr where A: Future { + future: A, + f: Option, +} + +pub fn new(future: A, f: F) -> MapErr + where A: Future +{ + MapErr { + future: future, + f: Some(f), + } +} + +impl Future for MapErr + where A: Future, + F: FnOnce(A::Error) -> U, +{ + type Item = A::Item; + type Error = U; + + fn poll(&mut self, cx: &mut task::Context) -> PollResult { + let e = match self.future.poll(cx) { + Poll::Pending => return Poll::Pending, + Poll::Ready(r) => r + }; + Poll::Ready(e.map_err(self.f.take().expect("cannot poll MapErr twice"))) + } +} diff --git a/futures-util/src/future/mod.rs b/futures-util/src/future/mod.rs new file mode 100644 index 0000000000..8b6af3c7bb --- /dev/null +++ b/futures-util/src/future/mod.rs @@ -0,0 +1,1000 @@ +//! Futures +//! +//! This module contains a number of functions for working with `Future`s, +//! including the `FutureExt` trait which adds methods to `Future` types. + +use core::result; + +use futures_core::{Future, IntoFuture, Stream}; +use futures_sink::Sink; + +// Primitive futures +mod empty; +mod lazy; +mod poll_fn; +mod loop_fn; +pub use self::empty::{empty, Empty}; +pub use self::lazy::{lazy, Lazy}; +pub use self::poll_fn::{poll_fn, PollResultFn}; +pub use self::loop_fn::{loop_fn, Loop, LoopFn}; + +// combinators +mod and_then; +mod flatten; +mod flatten_sink; +mod flatten_stream; +mod fuse; +mod into_stream; +mod join; +mod map; +mod map_err; +mod err_into; +mod or_else; +mod select; +mod then; +mod inspect; +mod inspect_err; +mod recover; + +// impl details +mod chain; + +pub use self::and_then::AndThen; +pub use self::flatten::Flatten; +pub use self::flatten_sink::FlattenSink; +pub use self::flatten_stream::FlattenStream; +pub use self::fuse::Fuse; +pub use self::into_stream::IntoStream; +pub use self::join::{Join, Join3, Join4, Join5}; +pub use self::map::Map; +pub use self::map_err::MapErr; +pub use self::err_into::ErrInto; +pub use self::or_else::OrElse; +pub use self::select::Select; +pub use self::then::Then; +pub use self::inspect::Inspect; +pub use self::inspect_err::InspectErr; +pub use self::recover::Recover; + +pub use either::Either; + +if_std! { + mod catch_unwind; + mod join_all; + mod select_all; + mod select_ok; + //mod shared; + mod with_executor; + pub use self::catch_unwind::CatchUnwind; + pub use self::join_all::{join_all, JoinAll}; + pub use self::select_all::{SelectAll, SelectAllNext, select_all}; + pub use self::select_ok::{SelectOk, select_ok}; + //pub use self::shared::{Shared, SharedItem, SharedError}; + pub use self::with_executor::WithExecutor; +} + +impl FutureExt for T where T: Future {} + +/// An extension trait for `Future`s that provides a variety of convenient +/// combinator functions. +pub trait FutureExt: Future { + /// Map this future's result to a different type, returning a new future of + /// the resulting type. + /// + /// This function is similar to the `Option::map` or `Iterator::map` where + /// it will change the type of the underlying future. This is useful to + /// chain along a computation once a future has been resolved. + /// + /// The closure provided will only be called if this future is resolved + /// successfully. If this future returns an error, panics, or is dropped, + /// then the closure provided will never be invoked. + /// + /// Note that this function consumes the receiving future and returns a + /// wrapped version of it, similar to the existing `map` methods in the + /// standard library. + /// + /// # Examples + /// + /// ``` + /// # extern crate futures; + /// # extern crate futures_executor; + /// use futures::prelude::*; + /// use futures::future; + /// use futures_executor::block_on; + /// + /// # fn main() { + /// let future = future::ok::(1); + /// let new_future = future.map(|x| x + 3); + /// assert_eq!(block_on(new_future), Ok(4)); + /// # } + /// ``` + /// + /// Calling `map` on an errored `Future` has no effect: + /// + /// ``` + /// # extern crate futures; + /// # extern crate futures_executor; + /// use futures::prelude::*; + /// use futures::future; + /// use futures_executor::block_on; + /// + /// # fn main() { + /// let future = future::err::(1); + /// let new_future = future.map(|x| x + 3); + /// assert_eq!(block_on(new_future), Err(1)); + /// # } + /// ``` + fn map(self, f: F) -> Map + where F: FnOnce(Self::Item) -> U, + Self: Sized, + { + assert_future::(map::new(self, f)) + } + + /// Map this future's error to a different error, returning a new future. + /// + /// This function is similar to the `Result::map_err` where it will change + /// the error type of the underlying future. This is useful for example to + /// ensure that futures have the same error type when used with combinators + /// like `select` and `join`. + /// + /// The closure provided will only be called if this future is resolved + /// with an error. If this future returns a success, panics, or is + /// dropped, then the closure provided will never be invoked. + /// + /// Note that this function consumes the receiving future and returns a + /// wrapped version of it. + /// + /// # Examples + /// + /// ``` + /// # extern crate futures; + /// # extern crate futures_executor; + /// use futures::future::err; + /// use futures::prelude::*; + /// use futures_executor::block_on; + /// + /// # fn main() { + /// let future = err::(1); + /// let new_future = future.map_err(|x| x + 3); + /// assert_eq!(block_on(new_future), Err(4)); + /// # } + /// ``` + /// + /// Calling `map_err` on a successful `Future` has no effect: + /// + /// ``` + /// # extern crate futures; + /// # extern crate futures_executor; + /// use futures::future::ok; + /// use futures::prelude::*; + /// use futures_executor::block_on; + /// + /// # fn main() { + /// let future = ok::(1); + /// let new_future = future.map_err(|x| x + 3); + /// assert_eq!(block_on(new_future), Ok(1)); + /// # } + /// ``` + fn map_err(self, f: F) -> MapErr + where F: FnOnce(Self::Error) -> E, + Self: Sized, + { + assert_future::(map_err::new(self, f)) + } + + /// Map this future's error to a new error type using the `Into` trait. + /// + /// This function does for futures what `try!` does for `Result`, + /// by letting the compiler infer the type of the resulting error. + /// Just as `map_err` above, this is useful for example to ensure + /// that futures have the same error type when used with + /// combinators like `select` and `join`. + /// + /// Note that this function consumes the receiving future and returns a + /// wrapped version of it. + /// + /// # Examples + /// + /// ``` + /// # extern crate futures; + /// use futures::prelude::*; + /// use futures::future; + /// + /// # fn main() { + /// let future_with_err_u8 = future::err::<(), u8>(1); + /// let future_with_err_u32 = future_with_err_u8.err_into::(); + /// # } + /// ``` + fn err_into(self) -> ErrInto + where Self: Sized, + Self::Error: Into + { + assert_future::(err_into::new(self)) + } + + /// Chain on a computation for when a future finished, passing the result of + /// the future to the provided closure `f`. + /// + /// This function can be used to ensure a computation runs regardless of + /// the conclusion of the future. The closure provided will be yielded a + /// `Result` once the future is complete. + /// + /// The returned value of the closure must implement the `IntoFuture` trait + /// and can represent some more work to be done before the composed future + /// is finished. Note that the `Result` type implements the `IntoFuture` + /// trait so it is possible to simply alter the `Result` yielded to the + /// closure and return it. + /// + /// If this future is dropped or panics then the closure `f` will not be + /// run. + /// + /// Note that this function consumes the receiving future and returns a + /// wrapped version of it. + /// + /// # Examples + /// + /// ``` + /// # extern crate futures; + /// use futures::prelude::*; + /// use futures::future; + /// + /// # fn main() { + /// let future_of_1 = future::ok::(1); + /// let future_of_4 = future_of_1.then(|x| { + /// x.map(|y| y + 3) + /// }); + /// + /// let future_of_err_1 = future::err::(1); + /// let future_of_4 = future_of_err_1.then(|x| { + /// match x { + /// Ok(_) => panic!("expected an error"), + /// Err(y) => future::ok::(y + 3), + /// } + /// }); + /// # } + /// ``` + fn then(self, f: F) -> Then + where F: FnOnce(result::Result) -> B, + B: IntoFuture, + Self: Sized, + { + assert_future::(then::new(self, f)) + } + + /// Execute another future after this one has resolved successfully. + /// + /// This function can be used to chain two futures together and ensure that + /// the final future isn't resolved until both have finished. The closure + /// provided is yielded the successful result of this future and returns + /// another value which can be converted into a future. + /// + /// Note that because `Result` implements the `IntoFuture` trait this method + /// can also be useful for chaining fallible and serial computations onto + /// the end of one future. + /// + /// If this future is dropped, panics, or completes with an error then the + /// provided closure `f` is never called. + /// + /// Note that this function consumes the receiving future and returns a + /// wrapped version of it. + /// + /// # Examples + /// + /// ``` + /// # extern crate futures; + /// use futures::prelude::*; + /// use futures::future::{self, FutureResult}; + /// + /// # fn main() { + /// let future_of_1 = future::ok::(1); + /// let future_of_4 = future_of_1.and_then(|x| { + /// Ok(x + 3) + /// }); + /// + /// let future_of_err_1 = future::err::(1); + /// future_of_err_1.and_then(|_| -> FutureResult { + /// panic!("should not be called in case of an error"); + /// }); + /// # } + /// ``` + fn and_then(self, f: F) -> AndThen + where F: FnOnce(Self::Item) -> B, + B: IntoFuture, + Self: Sized, + { + assert_future::(and_then::new(self, f)) + } + + /// Execute another future if this one resolves with an error. + /// + /// Return a future that passes along this future's value if it succeeds, + /// and otherwise passes the error to the closure `f` and waits for the + /// future it returns. The closure may also simply return a value that can + /// be converted into a future. + /// + /// Note that because `Result` implements the `IntoFuture` trait this method + /// can also be useful for chaining together fallback computations, where + /// when one fails, the next is attempted. + /// + /// If this future is dropped, panics, or completes successfully then the + /// provided closure `f` is never called. + /// + /// Note that this function consumes the receiving future and returns a + /// wrapped version of it. + /// + /// # Examples + /// + /// ``` + /// # extern crate futures; + /// use futures::prelude::*; + /// use futures::future::{self, FutureResult}; + /// + /// # fn main() { + /// let future_of_err_1 = future::err::(1); + /// let future_of_4 = future_of_err_1.or_else(|x| -> Result { + /// Ok(x + 3) + /// }); + /// + /// let future_of_1 = future::ok::(1); + /// future_of_1.or_else(|_| -> FutureResult { + /// panic!("should not be called in case of success"); + /// }); + /// # } + /// ``` + fn or_else(self, f: F) -> OrElse + where F: FnOnce(Self::Error) -> B, + B: IntoFuture, + Self: Sized, + { + assert_future::(or_else::new(self, f)) + } + + /// Waits for either one of two differently-typed futures to complete. + /// + /// This function will return a new future which awaits for either this or + /// the `other` future to complete. The returned future will finish with + /// both the value resolved and a future representing the completion of the + /// other work. + /// + /// Note that this function consumes the receiving futures and returns a + /// wrapped version of them. + /// + /// Also note that if both this and the second future have the same + /// success/error type you can use the `Either::split` method to + /// conveniently extract out the value at the end. + /// + /// # Examples + /// + /// ``` + /// # extern crate futures; + /// use futures::prelude::*; + /// use futures::future::{self, Either}; + /// + /// // A poor-man's join implemented on top of select + /// + /// fn join(a: A, b: B) -> Box> + /// where A: Future + 'static, + /// B: Future + 'static, + /// E: 'static, + /// { + /// Box::new(a.select(b).then(|res| -> Box> { + /// match res { + /// Ok(Either::Left((x, b))) => Box::new(b.map(move |y| (x, y))), + /// Ok(Either::Right((y, a))) => Box::new(a.map(move |x| (x, y))), + /// Err(Either::Left((e, _))) => Box::new(future::err(e)), + /// Err(Either::Right((e, _))) => Box::new(future::err(e)), + /// } + /// })) + /// } + /// # fn main() {} + /// ``` + fn select(self, other: B) -> Select + where B: IntoFuture, Self: Sized + { + select::new(self, other.into_future()) + } + + /// Joins the result of two futures, waiting for them both to complete. + /// + /// This function will return a new future which awaits both this and the + /// `other` future to complete. The returned future will finish with a tuple + /// of both results. + /// + /// Both futures must have the same error type, and if either finishes with + /// an error then the other will be dropped and that error will be + /// returned. + /// + /// Note that this function consumes the receiving future and returns a + /// wrapped version of it. + /// + /// # Examples + /// + /// ``` + /// # extern crate futures; + /// # extern crate futures_executor; + /// use futures::prelude::*; + /// use futures::future; + /// use futures_executor::block_on; + /// + /// # fn main() { + /// let a = future::ok::(1); + /// let b = future::ok::(2); + /// let pair = a.join(b); + /// + /// assert_eq!(block_on(pair), Ok((1, 2))); + /// # } + /// ``` + /// + /// If one or both of the joined `Future`s is errored, the resulting + /// `Future` will be errored: + /// + /// ``` + /// # extern crate futures; + /// # extern crate futures_executor; + /// use futures::prelude::*; + /// use futures::future; + /// use futures_executor::block_on; + /// + /// # fn main() { + /// let a = future::ok::(1); + /// let b = future::err::(2); + /// let pair = a.join(b); + /// + /// assert_eq!(block_on(pair), Err(2)); + /// # } + /// ``` + fn join(self, other: B) -> Join + where B: IntoFuture, + Self: Sized, + { + let f = join::new(self, other.into_future()); + assert_future::<(Self::Item, B::Item), Self::Error, _>(f) + } + + /// Same as `join`, but with more futures. + fn join3(self, b: B, c: C) -> Join3 + where B: IntoFuture, + C: IntoFuture, + Self: Sized, + { + join::new3(self, b.into_future(), c.into_future()) + } + + /// Same as `join`, but with more futures. + fn join4(self, b: B, c: C, d: D) + -> Join4 + where B: IntoFuture, + C: IntoFuture, + D: IntoFuture, + Self: Sized, + { + join::new4(self, b.into_future(), c.into_future(), d.into_future()) + } + + /// Same as `join`, but with more futures. + fn join5(self, b: B, c: C, d: D, e: E) + -> Join5 + where B: IntoFuture, + C: IntoFuture, + D: IntoFuture, + E: IntoFuture, + Self: Sized, + { + join::new5(self, b.into_future(), c.into_future(), d.into_future(), + e.into_future()) + } + + /// Wrap this future in an `Either` future, making it the left-hand variant + /// of that `Either`. + /// + /// This can be used in combination with the `right` method to write `if` + /// statements that evaluate to different futures in different branches. + /// + /// # Examples + /// + /// ``` + /// # extern crate futures; + /// use futures::executor::block_on; + /// use futures::future::*; + /// + /// # fn main() { + /// let x = 6; + /// let future = if x < 10 { + /// ok::<_, bool>(x).left() + /// } else { + /// empty().right() + /// }; + /// + /// assert_eq!(x, block_on(future).unwrap()); + /// # } + /// ``` + #[deprecated(note = "use `left_future` instead")] + fn left(self) -> Either + where B: Future, + Self: Sized + { + Either::Left(self) + } + + /// Wrap this future in an `Either` future, making it the left-hand variant + /// of that `Either`. + /// + /// This can be used in combination with the `right_future` method to write `if` + /// statements that evaluate to different futures in different branches. + /// + /// # Examples + /// + /// ``` + /// # extern crate futures; + /// use futures::executor::block_on; + /// use futures::future::*; + /// + /// # fn main() { + /// let x = 6; + /// let future = if x < 10 { + /// ok::<_, bool>(x).left_future() + /// } else { + /// empty().right_future() + /// }; + /// + /// assert_eq!(x, block_on(future).unwrap()); + /// # } + /// ``` + fn left_future(self) -> Either + where B: Future, + Self: Sized + { + Either::Left(self) + } + + /// Wrap this future in an `Either` future, making it the right-hand variant + /// of that `Either`. + /// + /// This can be used in combination with the `left_future` method to write `if` + /// statements that evaluate to different futures in different branches. + /// + /// # Examples + /// + /// ``` + /// # extern crate futures; + /// use futures::executor::block_on; + /// use futures::future::*; + /// + /// # fn main() { + /// let x = 6; + /// let future = if x < 10 { + /// ok::<_, bool>(x).left() + /// } else { + /// empty().right() + /// }; + /// + /// assert_eq!(x, block_on(future).unwrap()); + /// # } + /// ``` + #[deprecated(note = "use `right_future` instead")] + fn right(self) -> Either + where A: Future, + Self: Sized, + { + Either::Right(self) + } + + /// Wrap this future in an `Either` future, making it the right-hand variant + /// of that `Either`. + /// + /// This can be used in combination with the `left_future` method to write `if` + /// statements that evaluate to different futures in different branches. + /// + /// # Examples + /// + /// ``` + /// # extern crate futures; + /// use futures::executor::block_on; + /// use futures::future::*; + /// + /// # fn main() { + /// let x = 6; + /// let future = if x < 10 { + /// ok::<_, bool>(x).left_future() + /// } else { + /// empty().right_future() + /// }; + /// + /// assert_eq!(x, block_on(future).unwrap()); + /// # } + /// ``` + fn right_future(self) -> Either + where A: Future, + Self: Sized, + { + Either::Right(self) + } + + /// Convert this future into a single element stream. + /// + /// The returned stream contains single success if this future resolves to + /// success or single error if this future resolves into error. + /// + /// # Examples + /// + /// ``` + /// # extern crate futures; + /// # extern crate futures_executor; + /// use futures::prelude::*; + /// use futures::future; + /// use futures_executor::block_on; + /// + /// # fn main() { + /// let future = future::ok::<_, bool>(17); + /// let stream = future.into_stream(); + /// let collected: Vec<_> = block_on(stream.collect()).unwrap(); + /// assert_eq!(collected, vec![17]); + /// + /// let future = future::err::(19); + /// let stream = future.into_stream(); + /// let collected: Result, _> = block_on(stream.collect()); + /// assert_eq!(collected, Err(19)); + /// # } + /// ``` + fn into_stream(self) -> IntoStream + where Self: Sized + { + into_stream::new(self) + } + + /// Flatten the execution of this future when the successful result of this + /// future is itself another future. + /// + /// This can be useful when combining futures together to flatten the + /// computation out the final result. This method can only be called + /// when the successful result of this future itself implements the + /// `IntoFuture` trait and the error can be created from this future's error + /// type. + /// + /// This method is roughly equivalent to `self.and_then(|x| x)`. + /// + /// Note that this function consumes the receiving future and returns a + /// wrapped version of it. + /// + /// # Examples + /// + /// ``` + /// # extern crate futures; + /// # extern crate futures_executor; + /// use futures::prelude::*; + /// use futures::future; + /// use futures_executor::block_on; + /// + /// # fn main() { + /// let nested_future = future::ok::<_, u32>(future::ok::(1)); + /// let future = nested_future.flatten(); + /// assert_eq!(block_on(future), Ok(1)); + /// # } + /// ``` + /// + /// Calling `flatten` on an errored `Future`, or if the inner `Future` is + /// errored, will result in an errored `Future`: + /// + /// ``` + /// # extern crate futures; + /// # extern crate futures_executor; + /// use futures::prelude::*; + /// use futures::future; + /// use futures_executor::block_on; + /// + /// # fn main() { + /// let nested_future = future::ok::<_, u32>(future::err::(1)); + /// let future = nested_future.flatten(); + /// assert_eq!(block_on(future), Err(1)); + /// # } + /// ``` + fn flatten(self) -> Flatten + where Self::Item: IntoFuture::Error>, + Self: Sized + { + let f = flatten::new(self); + assert_future::<<::Item as IntoFuture>::Item, + <::Item as IntoFuture>::Error, + _>(f) + } + + /// Flatten the execution of this future when the successful result of this + /// future is a sink. + /// + /// This can be useful when sink initialization is deferred, and it is + /// convenient to work with that sink as if sink was available at the + /// call site. + /// + /// Note that this function consumes this future and returns a wrapped + /// version of it. + fn flatten_sink(self) -> FlattenSink + where ::Item: Sink, + Self: Sized + { + flatten_sink::new(self) + } + + /// Flatten the execution of this future when the successful result of this + /// future is a stream. + /// + /// This can be useful when stream initialization is deferred, and it is + /// convenient to work with that stream as if stream was available at the + /// call site. + /// + /// Note that this function consumes this future and returns a wrapped + /// version of it. + /// + /// # Examples + /// + /// ``` + /// # extern crate futures; + /// # extern crate futures_executor; + /// use futures::prelude::*; + /// use futures::future; + /// use futures::stream; + /// use futures_executor::block_on; + /// + /// # fn main() { + /// let stream_items = vec![17, 18, 19]; + /// let future_of_a_stream = future::ok::<_, bool>(stream::iter_ok(stream_items)); + /// + /// let stream = future_of_a_stream.flatten_stream(); + /// let list: Vec<_> = block_on(stream.collect()).unwrap(); + /// assert_eq!(list, vec![17, 18, 19]); + /// # } + /// ``` + fn flatten_stream(self) -> FlattenStream + where ::Item: Stream, + Self: Sized + { + flatten_stream::new(self) + } + + /// Fuse a future such that `poll` will never again be called once it has + /// completed. + /// + /// Currently once a future has returned `Ready` or `Err` from + /// `poll` any further calls could exhibit bad behavior such as blocking + /// forever, panicking, never returning, etc. If it is known that `poll` + /// may be called too often then this method can be used to ensure that it + /// has defined semantics. + /// + /// Once a future has been `fuse`d and it returns a completion from `poll`, + /// then it will forever return `Pending` from `poll` again (never + /// resolve). This, unlike the trait's `poll` method, is guaranteed. + /// + /// This combinator will drop this future as soon as it's been completed to + /// ensure resources are reclaimed as soon as possible. + fn fuse(self) -> Fuse + where Self: Sized + { + let f = fuse::new(self); + assert_future::(f) + } + + /// Do something with the item of a future, passing it on. + /// + /// When using futures, you'll often chain several of them together. + /// While working on such code, you might want to check out what's happening at + /// various parts in the pipeline. To do that, insert a call to `inspect`. + /// + /// # Examples + /// + /// ``` + /// # extern crate futures; + /// # extern crate futures_executor; + /// use futures::prelude::*; + /// use futures::future; + /// use futures_executor::block_on; + /// + /// # fn main() { + /// let future = future::ok::(1); + /// let new_future = future.inspect(|&x| println!("about to resolve: {}", x)); + /// assert_eq!(block_on(new_future), Ok(1)); + /// # } + /// ``` + fn inspect(self, f: F) -> Inspect + where F: FnOnce(&Self::Item) -> (), + Self: Sized, + { + assert_future::(inspect::new(self, f)) + } + + /// Do something with the error of a future, passing it on. + /// + /// When using futures, you'll often chain several of them together. + /// While working on such code, you might want to check out what's happening + /// to the errors at various parts in the pipeline. To do that, insert a + /// call to `inspect_err`. + /// + /// # Examples + /// + /// ``` + /// # extern crate futures; + /// use futures::prelude::*; + /// use futures::future; + /// use futures::executor::block_on; + /// + /// # fn main() { + /// let future = future::err::(1); + /// let new_future = future.inspect_err(|&x| println!("about to error: {}", x)); + /// assert_eq!(block_on(new_future), Err(1)); + /// # } + /// ``` + fn inspect_err(self, f: F) -> InspectErr + where F: FnOnce(&Self::Error) -> (), + Self: Sized, + { + assert_future::(inspect_err::new(self, f)) + } + + /// Catches unwinding panics while polling the future. + /// + /// In general, panics within a future can propagate all the way out to the + /// task level. This combinator makes it possible to halt unwinding within + /// the future itself. It's most commonly used within task executors. It's + /// not recommended to use this for error handling. + /// + /// Note that this method requires the `UnwindSafe` bound from the standard + /// library. This isn't always applied automatically, and the standard + /// library provides an `AssertUnwindSafe` wrapper type to apply it + /// after-the fact. To assist using this method, the `Future` trait is also + /// implemented for `AssertUnwindSafe` where `F` implements `Future`. + /// + /// This method is only available when the `std` feature of this + /// library is activated, and it is activated by default. + /// + /// # Examples + /// + /// ```rust + /// # extern crate futures; + /// # extern crate futures_executor; + /// use futures::prelude::*; + /// use futures::future::{self, FutureResult}; + /// use futures_executor::block_on; + /// + /// # fn main() { + /// let mut future = future::ok::(2); + /// assert!(block_on(future.catch_unwind()).is_ok()); + /// + /// let mut future = future::lazy(|_| -> FutureResult { + /// panic!(); + /// future::ok::(2) + /// }); + /// assert!(block_on(future.catch_unwind()).is_err()); + /// # } + /// ``` + #[cfg(feature = "std")] + fn catch_unwind(self) -> CatchUnwind + where Self: Sized + ::std::panic::UnwindSafe + { + catch_unwind::new(self) + } + + /* TODO + /// Create a cloneable handle to this future where all handles will resolve + /// to the same result. + /// + /// The shared() method provides a method to convert any future into a + /// cloneable future. It enables a future to be polled by multiple threads. + /// + /// The returned `Shared` future resolves successfully with + /// `SharedItem` or erroneously with `SharedError`. + /// Both `SharedItem` and `SharedError` implements `Deref` to allow shared + /// access to the underlying result. Ownership of `Self::Item` and + /// `Self::Error` cannot currently be reclaimed. + /// + /// This method is only available when the `std` feature of this + /// library is activated, and it is activated by default. + /// + /// # Examples + /// + /// ``` + /// # extern crate futures; + /// # extern crate futures_executor; + /// use futures::prelude::*; + /// use futures::future; + /// use futures_executor::block_on; + /// + /// # fn main() { + /// let future = future::ok::<_, bool>(6); + /// let shared1 = future.shared(); + /// let shared2 = shared1.clone(); + /// + /// assert_eq!(6, *block_on(shared1).unwrap()); + /// assert_eq!(6, *block_on(shared2).unwrap()); + /// # } + /// ``` + /// + /// ``` + /// # extern crate futures; + /// # extern crate futures_executor; + /// use std::thread; + /// + /// use futures::prelude::*; + /// use futures::future; + /// use futures_executor::block_on; + /// + /// # fn main() { + /// let future = future::ok::<_, bool>(6); + /// let shared1 = future.shared(); + /// let shared2 = shared1.clone(); + /// let join_handle = thread::spawn(move || { + /// assert_eq!(6, *block_on(shared2).unwrap()); + /// }); + /// assert_eq!(6, *block_on(shared1).unwrap()); + /// join_handle.join().unwrap(); + /// # } + /// ``` + #[cfg(feature = "std")] + fn shared(self) -> Shared + where Self: Sized + { + shared::new(self) + } + */ + + /// Handle errors generated by this future by converting them into + /// `Self::Item`. + /// + /// Because it can never produce an error, the returned `Recover` future can + /// conform to any specific `Error` type, including `Never`. + /// + /// # Examples + /// + /// ``` + /// # extern crate futures; + /// # extern crate futures_executor; + /// use futures::prelude::*; + /// use futures::future; + /// use futures_executor::block_on; + /// + /// # fn main() { + /// let future = future::err::<(), &str>("something went wrong"); + /// let new_future = future.recover::(|_| ()); + /// assert_eq!(block_on(new_future), Ok(())); + /// # } + /// ``` + fn recover(self, f: F) -> Recover + where Self: Sized, + F: FnOnce(Self::Error) -> Self::Item + { + recover::new(self, f) + } + + /// Assigns the provided `Executor` to be used when spawning tasks + /// from within the future. + /// + /// # Examples + /// + /// ``` + /// # extern crate futures; + /// # extern crate futures_executor; + /// use futures::prelude::*; + /// use futures::future; + /// use futures_executor::{block_on, spawn, ThreadPool}; + /// + /// # fn main() { + /// let pool = ThreadPool::new().expect("unable to create threadpool"); + /// let future = future::ok::<(), _>(()); + /// let spawn_future = spawn(future).with_executor(pool); + /// assert_eq!(block_on(spawn_future), Ok(())); + /// # } + /// ``` + #[cfg(feature = "std")] + fn with_executor(self, executor: E) -> WithExecutor + where Self: Sized, + E: ::futures_core::executor::Executor + { + with_executor::new(self, executor) + } +} + +// Just a helper function to ensure the futures we're returning all have the +// right implementations. +fn assert_future(t: F) -> F + where F: Future, +{ + t +} diff --git a/futures-util/src/future/or_else.rs b/futures-util/src/future/or_else.rs new file mode 100644 index 0000000000..d0ff59bbdc --- /dev/null +++ b/futures-util/src/future/or_else.rs @@ -0,0 +1,40 @@ +use futures_core::{Future, IntoFuture, PollResult}; +use futures_core::task; +use super::chain::Chain; + +/// Future for the `or_else` combinator, chaining a computation onto the end of +/// a future which fails with an error. +/// +/// This is created by the `Future::or_else` method. +#[derive(Debug)] +#[must_use = "futures do nothing unless polled"] +pub struct OrElse where A: Future, B: IntoFuture { + state: Chain, +} + +pub fn new(future: A, f: F) -> OrElse + where A: Future, + B: IntoFuture, +{ + OrElse { + state: Chain::new(future, f), + } +} + +impl Future for OrElse + where A: Future, + B: IntoFuture, + F: FnOnce(A::Error) -> B, +{ + type Item = B::Item; + type Error = B::Error; + + fn poll(&mut self, cx: &mut task::Context) -> PollResult { + self.state.poll(cx, |a, f| { + match a { + Ok(item) => Ok(Ok(item)), + Err(e) => Ok(Err(f(e).into_future())) + } + }) + } +} diff --git a/futures-util/src/future/poll_fn.rs b/futures-util/src/future/poll_fn.rs new file mode 100644 index 0000000000..3c4bcc0c85 --- /dev/null +++ b/futures-util/src/future/poll_fn.rs @@ -0,0 +1,51 @@ +//! Definition of the `PollResultFn` adapter combinator + +use futures_core::{Future, PollResult}; +use futures_core::task; + +/// A future which adapts a function returning `PollResult`. +/// +/// Created by the `poll_fn` function. +#[derive(Debug)] +#[must_use = "futures do nothing unless polled"] +pub struct PollResultFn { + inner: F, +} + +/// Creates a new future wrapping around a function returning `PollResult`. +/// +/// PollResulting the returned future delegates to the wrapped function. +/// +/// # Examples +/// +/// ``` +/// # extern crate futures; +/// use futures::prelude::*; +/// use futures::future::poll_fn; +/// use futures::never::Never; +/// use futures::task; +/// +/// # fn main() { +/// fn read_line(cx: &mut task::Context) -> PollResult { +/// Ok(Async::Ready("Hello, World!".into())) +/// } +/// +/// let read_future = poll_fn(read_line); +/// # } +/// ``` +pub fn poll_fn(f: F) -> PollResultFn + where F: FnMut(&mut task::Context) -> PollResult +{ + PollResultFn { inner: f } +} + +impl Future for PollResultFn + where F: FnMut(&mut task::Context) -> PollResult +{ + type Item = T; + type Error = E; + + fn poll(&mut self, cx: &mut task::Context) -> PollResult { + (self.inner)(cx) + } +} diff --git a/futures-util/src/future/recover.rs b/futures-util/src/future/recover.rs new file mode 100644 index 0000000000..1db095e5bb --- /dev/null +++ b/futures-util/src/future/recover.rs @@ -0,0 +1,36 @@ +use core::marker::PhantomData; + +use futures_core::{Future, PollResult, Poll}; +use futures_core::task; + +/// Future for the `recover` combinator, handling errors by converting them into +/// an `Item`, compatible with any error type of the caller's choosing. +#[must_use = "futures do nothing unless polled"] +#[derive(Debug)] +pub struct Recover { + inner: A, + f: Option, + err: PhantomData, +} + +pub fn new(future: A, f: F) -> Recover + where A: Future +{ + Recover { inner: future, f: Some(f), err: PhantomData } +} + +impl Future for Recover + where A: Future, + F: FnOnce(A::Error) -> A::Item, +{ + type Item = A::Item; + type Error = E; + + fn poll(&mut self, cx: &mut task::Context) -> PollResult { + match self.inner.poll(cx) { + Poll::Ready(Err(e)) => Poll::Ready(Ok((self.f.take().expect("PollResulted future::Recover after completion"))(e))), + Poll::Ready(Ok(x)) => Poll::Ready(Ok(x)), + Poll::Pending => Poll::Pending, + } + } +} diff --git a/futures-util/src/future/select.rs b/futures-util/src/future/select.rs new file mode 100644 index 0000000000..d1145ef243 --- /dev/null +++ b/futures-util/src/future/select.rs @@ -0,0 +1,41 @@ +use futures_core::{Future, PollResult, Poll}; +use futures_core::task; + +use either::Either; + +/// Future for the `select` combinator, waiting for one of two differently-typed +/// futures to complete. +/// +/// This is created by the [`Future::select`] method. +/// +/// [`Future::select`]: trait.Future.html#method.select +#[must_use = "futures do nothing unless polled"] +#[derive(Debug)] +pub struct Select { + inner: Option<(A, B)>, +} + +pub fn new(a: A, b: B) -> Select { + Select { inner: Some((a, b)) } +} + +impl Future for Select where A: Future, B: Future { + type Item = Either<(A::Item, B), (B::Item, A)>; + type Error = Either<(A::Error, B), (B::Error, A)>; + + fn poll(&mut self, cx: &mut task::Context) -> PollResult { + let (mut a, mut b) = self.inner.take().expect("cannot poll Select twice"); + match a.poll(cx) { + Poll::Ready(Err(e)) => Poll::Ready(Err(Either::Left((e, b)))), + Poll::Ready(Ok(x)) => Poll::Ready(Ok(Either::Left((x, b)))), + Poll::Pending => match b.poll(cx) { + Poll::Ready(Err(e)) => Poll::Ready(Err(Either::Right((e, a)))), + Poll::Ready(Ok(x)) => Poll::Ready(Ok(Either::Right((x, a)))), + Poll::Pending => { + self.inner = Some((a, b)); + Poll::Pending + } + } + } + } +} diff --git a/futures-util/src/future/select_all.rs b/futures-util/src/future/select_all.rs new file mode 100644 index 0000000000..d032d47827 --- /dev/null +++ b/futures-util/src/future/select_all.rs @@ -0,0 +1,71 @@ +//! Definition of the `SelectAll`, finding the first future in a list that +//! finishes. + +use std::mem; +use std::prelude::v1::*; + +use futures_core::{Future, IntoFuture, PollResult, Poll}; +use futures_core::task; + +/// Future for the `select_all` combinator, waiting for one of any of a list of +/// futures to complete. +/// +/// This is created by the `select_all` function. +#[derive(Debug)] +#[must_use = "futures do nothing unless polled"] +pub struct SelectAll where A: Future { + inner: Vec, +} + +#[doc(hidden)] +pub type SelectAllNext = A; + +/// Creates a new future which will select over a list of futures. +/// +/// The returned future will wait for any future within `iter` to be ready. Upon +/// completion or failure the item resolved will be returned, along with the +/// index of the future that was ready and the list of all the remaining +/// futures. +/// +/// # Panics +/// +/// This function will panic if the iterator specified contains no items. +pub fn select_all(iter: I) -> SelectAll<::Future> + where I: IntoIterator, + I::Item: IntoFuture, +{ + let ret = SelectAll { + inner: iter.into_iter() + .map(|a| a.into_future()) + .collect(), + }; + assert!(ret.inner.len() > 0); + ret +} + +impl Future for SelectAll + where A: Future, +{ + type Item = (A::Item, usize, Vec); + type Error = (A::Error, usize, Vec); + + fn poll(&mut self, cx: &mut task::Context) -> PollResult { + let item = self.inner.iter_mut().enumerate().filter_map(|(i, f)| { + match f.poll(cx) { + Poll::Pending => None, + Poll::Ready(r) => Some((i, r)), + } + }).next(); + match item { + Some((idx, res)) => { + self.inner.swap_remove(idx); + let rest = mem::replace(&mut self.inner, Vec::new()); + match res { + Ok(e) => Poll::Ready(Ok((e, idx, rest))), + Err(e) => Poll::Ready(Err((e, idx, rest))), + } + } + None => Poll::Pending, + } + } +} diff --git a/futures-util/src/future/select_ok.rs b/futures-util/src/future/select_ok.rs new file mode 100644 index 0000000000..2c2f1cd1eb --- /dev/null +++ b/futures-util/src/future/select_ok.rs @@ -0,0 +1,81 @@ +//! Definition of the `SelectOk` combinator, finding the first successful future +//! in a list. + +use std::mem; +use std::prelude::v1::*; + +use futures_core::{Future, IntoFuture, PollResult, Poll}; +use futures_core::task; + +/// Future for the `select_ok` combinator, waiting for one of any of a list of +/// futures to successfully complete. Unlike `select_all`, this future ignores all +/// but the last error, if there are any. +/// +/// This is created by the `select_ok` function. +#[derive(Debug)] +#[must_use = "futures do nothing unless polled"] +pub struct SelectOk where A: Future { + inner: Vec, +} + +/// Creates a new future which will select the first successful future over a list of futures. +/// +/// The returned future will wait for any future within `iter` to be ready and Ok. Unlike +/// `select_all`, this will only return the first successful completion, or the last +/// failure. This is useful in contexts where any success is desired and failures +/// are ignored, unless all the futures fail. +/// +/// # Panics +/// +/// This function will panic if the iterator specified contains no items. +pub fn select_ok(iter: I) -> SelectOk<::Future> + where I: IntoIterator, + I::Item: IntoFuture, +{ + let ret = SelectOk { + inner: iter.into_iter() + .map(|a| a.into_future()) + .collect(), + }; + assert!(ret.inner.len() > 0); + ret +} + +impl Future for SelectOk where A: Future { + type Item = (A::Item, Vec); + type Error = A::Error; + + fn poll(&mut self, cx: &mut task::Context) -> PollResult { + // loop until we've either exhausted all errors, a success was hit, or nothing is ready + loop { + let item = self.inner.iter_mut().enumerate().filter_map(|(i, f)| { + match f.poll(cx) { + Poll::Pending => None, + Poll::Ready(r) => Some((i, r)), + } + }).next(); + + match item { + Some((idx, res)) => { + // always remove Ok or Err, if it's not the last Err continue looping + drop(self.inner.remove(idx)); + match res { + Ok(e) => { + let rest = mem::replace(&mut self.inner, Vec::new()); + return Poll::Ready(Ok((e, rest))) + }, + Err(e) => { + if self.inner.is_empty() { + return Poll::Ready(Err(e)) + } + }, + } + } + None => { + // based on the filter above, nothing is ready, return + return Poll::Pending + }, + } + } + } +} diff --git a/futures-util/src/future/shared.rs b/futures-util/src/future/shared.rs new file mode 100644 index 0000000000..b91d63574d --- /dev/null +++ b/futures-util/src/future/shared.rs @@ -0,0 +1,308 @@ +//! Definition of the Shared combinator, a future that is cloneable, +//! and can be polled in multiple threads. +//! +//! # Examples +//! +//! ``` +//! # extern crate futures; +//! # extern crate futures_executor; +//! use futures::prelude::*; +//! use futures::future; +//! use futures_executor::block_on; +//! +//! # fn main() { +//! let future = future::ok::<_, bool>(6); +//! let shared1 = future.shared(); +//! let shared2 = shared1.clone(); +//! assert_eq!(6, *block_on(shared1).unwrap()); +//! assert_eq!(6, *block_on(shared2).unwrap()); +//! # } +//! ``` + +use std::{error, fmt, mem, ops}; +use std::cell::UnsafeCell; +use std::sync::{Arc, Mutex}; +use std::sync::atomic::AtomicUsize; +use std::sync::atomic::Ordering::SeqCst; +use std::collections::HashMap; + +use futures_core::{Future, PollResult, Async}; +use futures_core::task::{self, Wake, Waker, LocalMap}; + +/// A future that is cloneable and can be polled in multiple threads. +/// Use `Future::shared()` method to convert any future into a `Shared` future. +#[must_use = "futures do nothing unless polled"] +pub struct Shared { + inner: Arc>, + waiter: usize, +} + +impl fmt::Debug for Shared + where F: Future + fmt::Debug, + F::Item: fmt::Debug, + F::Error: fmt::Debug, +{ + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + fmt.debug_struct("Shared") + .field("inner", &self.inner) + .field("waiter", &self.waiter) + .finish() + } +} + +struct Inner { + next_clone_id: AtomicUsize, + future: UnsafeCell>, + result: UnsafeCell, SharedError>>>, + notifier: Arc, +} + +struct Notifier { + state: AtomicUsize, + waiters: Mutex>, +} + +const IDLE: usize = 0; +const POLLING: usize = 1; +const REPOLL: usize = 2; +const COMPLETE: usize = 3; +const POISONED: usize = 4; + +pub fn new(future: F) -> Shared { + Shared { + inner: Arc::new(Inner { + next_clone_id: AtomicUsize::new(1), + notifier: Arc::new(Notifier { + state: AtomicUsize::new(IDLE), + waiters: Mutex::new(HashMap::new()), + }), + future: UnsafeCell::new(Some((future, LocalMap::new()))), + result: UnsafeCell::new(None), + }), + waiter: 0, + } +} + +impl Shared where F: Future { + /// If any clone of this `Shared` has completed execution, returns its result immediately + /// without blocking. Otherwise, returns None without triggering the work represented by + /// this `Shared`. + pub fn peek(&self) -> Option, SharedError>> { + match self.inner.notifier.state.load(SeqCst) { + COMPLETE => { + Some(unsafe { self.clone_result() }) + } + POISONED => panic!("inner future panicked during poll"), + _ => None, + } + } + + fn set_waiter(&mut self, cx: &mut task::Context) { + let mut waiters = self.inner.notifier.waiters.lock().unwrap(); + waiters.insert(self.waiter, cx.waker().clone()); + } + + unsafe fn clone_result(&self) -> Result, SharedError> { + match *self.inner.result.get() { + Some(Ok(ref item)) => Ok(SharedItem { item: item.item.clone() }), + Some(Err(ref e)) => Err(SharedError { error: e.error.clone() }), + _ => unreachable!(), + } + } + + fn complete(&self) { + unsafe { *self.inner.future.get() = None }; + self.inner.notifier.state.store(COMPLETE, SeqCst); + Wake::wake(&self.inner.notifier); + } +} + +impl Future for Shared + where F: Future +{ + type Item = SharedItem; + type Error = SharedError; + + fn poll(&mut self, cx: &mut task::Context) -> PollResult { + self.set_waiter(cx); + + match self.inner.notifier.state.compare_and_swap(IDLE, POLLING, SeqCst) { + IDLE => { + // Lock acquired, fall through + } + POLLING | REPOLL => { + // Another task is currently polling, at this point we just want + // to ensure that our task handle is currently registered + + return Ok(Async::Pending); + } + COMPLETE => { + return unsafe { self.clone_result().map(Async::Ready) }; + } + POISONED => panic!("inner future panicked during poll"), + _ => unreachable!(), + } + + loop { + struct Reset<'a>(&'a AtomicUsize); + + impl<'a> Drop for Reset<'a> { + fn drop(&mut self) { + use std::thread; + + if thread::panicking() { + self.0.store(POISONED, SeqCst); + } + } + } + + let _reset = Reset(&self.inner.notifier.state); + + // PollResult the future + let res = unsafe { + let (ref mut f, ref mut data) = *(*self.inner.future.get()).as_mut().unwrap(); + let waker = Waker::from(self.inner.notifier.clone()); + let mut cx = task::Context::new(data, &waker, cx.executor()); + f.poll(&mut cx) + }; + match res { + Ok(Async::Pending) => { + // Not ready, try to release the handle + match self.inner.notifier.state.compare_and_swap(POLLING, IDLE, SeqCst) { + POLLING => { + // Success + return Ok(Async::Pending); + } + REPOLL => { + // Gotta poll again! + let prev = self.inner.notifier.state.swap(POLLING, SeqCst); + assert_eq!(prev, REPOLL); + } + _ => unreachable!(), + } + + } + Ok(Async::Ready(i)) => { + unsafe { + (*self.inner.result.get()) = Some(Ok(SharedItem { item: Arc::new(i) })); + } + + break; + } + Err(e) => { + unsafe { + (*self.inner.result.get()) = Some(Err(SharedError { error: Arc::new(e) })); + } + + break; + } + } + } + + self.complete(); + unsafe { self.clone_result().map(Async::Ready) } + } +} + +impl Clone for Shared where F: Future { + fn clone(&self) -> Self { + let next_clone_id = self.inner.next_clone_id.fetch_add(1, SeqCst); + + Shared { + inner: self.inner.clone(), + waiter: next_clone_id, + } + } +} + +impl Drop for Shared where F: Future { + fn drop(&mut self) { + let mut waiters = self.inner.notifier.waiters.lock().unwrap(); + waiters.remove(&self.waiter); + } +} + +impl Wake for Notifier { + fn wake(arc_self: &Arc) { + arc_self.state.compare_and_swap(POLLING, REPOLL, SeqCst); + + let waiters = mem::replace(&mut *arc_self.waiters.lock().unwrap(), HashMap::new()); + + for (_, waiter) in waiters { + waiter.wake(); + } + } +} + +unsafe impl Sync for Inner + where F: Future + Send, + F::Item: Send + Sync, + F::Error: Send + Sync +{} + +unsafe impl Send for Inner + where F: Future + Send, + F::Item: Send + Sync, + F::Error: Send + Sync +{} + +impl fmt::Debug for Inner + where F: Future + fmt::Debug, + F::Item: fmt::Debug, + F::Error: fmt::Debug, +{ + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + fmt.debug_struct("Inner") + .finish() + } +} + +/// A wrapped item of the original future that is cloneable and implements Deref +/// for ease of use. +#[derive(Clone, Debug)] +pub struct SharedItem { + item: Arc, +} + +impl ops::Deref for SharedItem { + type Target = T; + + fn deref(&self) -> &T { + &self.item.as_ref() + } +} + +/// A wrapped error of the original future that is cloneable and implements Deref +/// for ease of use. +#[derive(Clone, Debug)] +pub struct SharedError { + error: Arc, +} + +impl ops::Deref for SharedError { + type Target = E; + + fn deref(&self) -> &E { + &self.error.as_ref() + } +} + +impl fmt::Display for SharedError + where E: fmt::Display, +{ + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.error.fmt(f) + } +} + +impl error::Error for SharedError + where E: error::Error, +{ + fn description(&self) -> &str { + self.error.description() + } + + fn cause(&self) -> Option<&error::Error> { + self.error.cause() + } +} diff --git a/futures-util/src/future/then.rs b/futures-util/src/future/then.rs new file mode 100644 index 0000000000..7b3daf1fbc --- /dev/null +++ b/futures-util/src/future/then.rs @@ -0,0 +1,37 @@ +use futures_core::{Future, IntoFuture, PollResult}; +use futures_core::task; +use super::chain::Chain; + +/// Future for the `then` combinator, chaining computations on the end of +/// another future regardless of its outcome. +/// +/// This is created by the `Future::then` method. +#[derive(Debug)] +#[must_use = "futures do nothing unless polled"] +pub struct Then where A: Future, B: IntoFuture { + state: Chain, +} + +pub fn new(future: A, f: F) -> Then + where A: Future, + B: IntoFuture, +{ + Then { + state: Chain::new(future, f), + } +} + +impl Future for Then + where A: Future, + B: IntoFuture, + F: FnOnce(Result) -> B, +{ + type Item = B::Item; + type Error = B::Error; + + fn poll(&mut self, cx: &mut task::Context) -> PollResult { + self.state.poll(cx, |a, f| { + Ok(Err(f(a).into_future())) + }) + } +} diff --git a/futures-util/src/future/with_executor.rs b/futures-util/src/future/with_executor.rs new file mode 100644 index 0000000000..ee3b411d2d --- /dev/null +++ b/futures-util/src/future/with_executor.rs @@ -0,0 +1,33 @@ +use futures_core::{Future, PollResult}; +use futures_core::task; +use futures_core::executor::Executor; + +/// Future for the `with_executor` combinator, assigning an executor +/// to be used when spawning other futures. +/// +/// This is created by the `Future::with_executor` method. +#[derive(Debug)] +#[must_use = "futures do nothing unless polled"] +pub struct WithExecutor where F: Future, E: Executor { + executor: E, + future: F +} + +pub fn new(future: F, executor: E) -> WithExecutor + where F: Future, + E: Executor, +{ + WithExecutor { executor, future } +} + +impl Future for WithExecutor + where F: Future, + E: Executor, +{ + type Item = F::Item; + type Error = F::Error; + + fn poll(&mut self, cx: &mut task::Context) -> PollResult { + self.future.poll(&mut cx.with_executor(&mut self.executor)) + } +} diff --git a/futures-util/src/lib.rs b/futures-util/src/lib.rs index 916a8ce57f..2bd41e453c 100644 --- a/futures-util/src/lib.rs +++ b/futures-util/src/lib.rs @@ -15,7 +15,7 @@ extern crate futures_core; extern crate futures_executor; // extern crate futures_io; -// extern crate futures_sink; +extern crate futures_sink; extern crate either; @@ -36,7 +36,7 @@ extern crate std; /* macro_rules! delegate_sink { ($field:ident) => { - fn poll_ready(&mut self, cx: &mut task::Context) -> Poll<(), Self::SinkError> { + fn poll_ready(&mut self, cx: &mut task::Context) -> PollResult<(), Self::SinkError> { self.$field.poll_ready(cx) } @@ -44,11 +44,11 @@ macro_rules! delegate_sink { self.$field.start_send(item) } - fn poll_flush(&mut self, cx: &mut task::Context) -> Poll<(), Self::SinkError> { + fn poll_flush(&mut self, cx: &mut task::Context) -> PollResult<(), Self::SinkError> { self.$field.poll_flush(cx) } - fn poll_close(&mut self, cx: &mut task::Context) -> Poll<(), Self::SinkError> { + fn poll_close(&mut self, cx: &mut task::Context) -> PollResult<(), Self::SinkError> { self.$field.poll_close(cx) } @@ -61,7 +61,10 @@ macro_rules! delegate_sink { pub mod lock; #[cfg(all(feature = "std", not(any(test, feature = "bench"))))] mod lock; -*/ + */ + +pub mod future; +pub use future::FutureExt; pub mod async_trait; pub use async_trait::AsyncExt;