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-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() 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..2100ac9d53 --- /dev/null +++ b/futures-core/src/async_trait/mod.rs @@ -0,0 +1,210 @@ +//! Asynchronous values. + +use core::mem::Pin; +use core::marker::Unpin; + +use {Poll, PollResult, 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), + } + } + } +} + +/// 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/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..5c68fa385c 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, AsyncResult, 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..0bb1899f74 100644 --- a/futures-core/src/poll.rs +++ b/futures-core/src/poll.rs @@ -38,8 +38,48 @@ 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) } } + +/// Shorthand for a `Poll>` value. +pub type PollResult = 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. +#[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))), + }) +} + +/// 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-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)) } } 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) } } 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_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/async_result/join.rs b/futures-util/src/async_result/join.rs new file mode 100644 index 0000000000..684eebf183 --- /dev/null +++ b/futures-util/src/async_result/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_result/join_all.rs b/futures-util/src/async_result/join_all.rs new file mode 100644 index 0000000000..1d5e7dd55e --- /dev/null +++ b/futures-util/src/async_result/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_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/async_result/select.rs b/futures-util/src/async_result/select.rs new file mode 100644 index 0000000000..5ea1a77399 --- /dev/null +++ b/futures-util/src/async_result/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_result/select_all.rs b/futures-util/src/async_result/select_all.rs new file mode 100644 index 0000000000..4798e6da4d --- /dev/null +++ b/futures-util/src/async_result/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_result/select_ok.rs b/futures-util/src/async_result/select_ok.rs new file mode 100644 index 0000000000..b7ed52f3b8 --- /dev/null +++ b/futures-util/src/async_result/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/async_trait/catch_unwind.rs b/futures-util/src/async_trait/catch_unwind.rs new file mode 100644 index 0000000000..bb59f36156 --- /dev/null +++ b/futures-util/src/async_trait/catch_unwind.rs @@ -0,0 +1,36 @@ +use std::mem::Pin; +use std::prelude::v1::*; +use std::any::Any; +use std::panic::{catch_unwind, UnwindSafe, AssertUnwindSafe}; + +use futures_core::{Async, Poll}; +use futures_core::task; + +/// Async for the `catch_unwind` combinator. +/// +/// This is created by the `Async::catch_unwind` method. +#[derive(Debug)] +#[must_use = "futures do nothing unless polled"] +pub struct CatchUnwind where F: Async { + future: F, +} + +pub fn new(future: F) -> CatchUnwind + where F: Async + UnwindSafe, +{ + CatchUnwind { future } +} + +impl Async for CatchUnwind + where F: Async + UnwindSafe, +{ + type Output = Result>; + + fn poll(mut self: Pin, cx: &mut task::Context) -> Poll { + let fut = unsafe { pinned_field!(self, future) }; + match catch_unwind(AssertUnwindSafe(|| fut.poll(cx))) { + Ok(res) => res.map(Ok), + Err(e) => Poll::Ready(Err(e)) + } + } +} diff --git a/futures-util/src/async_trait/chain.rs b/futures-util/src/async_trait/chain.rs new file mode 100644 index 0000000000..ff8e309101 --- /dev/null +++ b/futures-util/src/async_trait/chain.rs @@ -0,0 +1,54 @@ +use core::mem::Pin; + +use futures_core::{Async, Poll}; +use futures_core::task; + +#[must_use = "futures do nothing unless polled"] +#[derive(Debug)] +pub enum Chain { + First(Fut1, Option), + Second(Fut2), +} + +impl Chain + where Fut1: Async, + Fut2: Async, +{ + pub fn new(fut1: Fut1, data: Data) -> Chain { + Chain::First(fut1, Some(data)) + } + + pub fn poll(mut self: Pin, cx: &mut task::Context, f: F) -> Poll + where F: FnOnce(Fut1::Output, Data) -> Fut2, + { + let mut f = Some(f); + + loop { + // safe to `get_mut` here because we don't move out + let fut2 = match *unsafe { Pin::get_mut(&mut self) } { + Chain::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(cx) { + Poll::Pending => return Poll::Pending, + Poll::Ready(t) => { + (f.take().unwrap())(t, data.take().unwrap()) + } + } + } + Chain::Second(ref mut fut2) => { + // 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(cx) + } + }; + + // safe because we're using the `&mut` to do an assignment, not for moving out + unsafe { + // note: it's safe to move the `fut2` here because we haven't yet polled it + *Pin::get_mut(&mut self) = Chain::Second(fut2); + } + } + } +} diff --git a/futures-util/src/async_trait/empty.rs b/futures-util/src/async_trait/empty.rs new file mode 100644 index 0000000000..392526d1cb --- /dev/null +++ b/futures-util/src/async_trait/empty.rs @@ -0,0 +1,32 @@ +//! Definition of the Empty combinator, a future that's never ready. + +use core::mem::Pin; +use core::marker; + +use futures_core::{Async, 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, +} + +/// 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 Async for Empty { + type Output = T; + + fn poll(self: Pin, _: &mut task::Context) -> Poll { + Poll::Pending + } +} diff --git a/futures-util/src/async_trait/flatten.rs b/futures-util/src/async_trait/flatten.rs new file mode 100644 index 0000000000..a10dcd7d26 --- /dev/null +++ b/futures-util/src/async_trait/flatten.rs @@ -0,0 +1,48 @@ +use core::fmt; +use core::mem::Pin; + +use futures_core::{Async, Poll}; +use futures_core::task; + +use super::chain::Chain; + +/// Async for the `flatten` combinator. +/// +/// This combinator turns a `Async`-of-a-`Async` into a single `Async`. +/// +/// This is created by the `Async::flatten` method. +#[must_use = "futures do nothing unless polled"] +pub struct Flatten where A: Async, A::Output: Async { + state: Chain, +} + +impl fmt::Debug for Flatten + where A: Async + fmt::Debug, + A::Output: Async + 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: Async, + A::Output: Async, +{ + Flatten { + state: Chain::new(future, ()), + } +} + +impl Async for Flatten + where A: Async, + A::Output: Async, +{ + 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/async_trait/flatten_sink.rs b/futures-util/src/async_trait/flatten_sink.rs new file mode 100644 index 0000000000..b147c7cc5c --- /dev/null +++ b/futures-util/src/async_trait/flatten_sink.rs @@ -0,0 +1,80 @@ +use core::fmt; + +use futures_core::{task, Async, Async}; +use futures_sink::Sink; + +#[derive(Debug)] +enum State where F: Async, ::Item: Sink { + Waiting(F), + Ready(F::Item), + Closed, +} + +/// 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 `Async::flatten_sink` method. +pub struct FlattenSink where F: Async, ::Item: Sink { + st: State +} + +impl fmt::Debug for FlattenSink + where F: Async + 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: 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 { + State::Ready(ref mut s) => return s.poll_ready(cx), + State::Waiting(ref mut f) => match f.poll(cx)? { + Async::Pending => return Ok(Async::Pending), + Async::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) -> Result, 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(_) => Ok(Async::Ready(())), + State::Closed => panic!("poll_flush called after eof"), + } + } + + fn poll_close(&mut self, cx: &mut task::Context) -> Result, Self::SinkError> { + if let State::Ready(ref mut s) = self.st { + try_ready!(s.poll_close(cx)); + } + self.st = State::Closed; + return Ok(Async::Ready(())); + } +} + +pub fn new(fut: F) -> FlattenSink where F: Async, ::Item: Sink { + FlattenSink { + st: State::Waiting(fut) + } +} diff --git a/futures-util/src/async_trait/fuse.rs b/futures-util/src/async_trait/fuse.rs new file mode 100644 index 0000000000..7c0ba3c2c3 --- /dev/null +++ b/futures-util/src/async_trait/fuse.rs @@ -0,0 +1,45 @@ +use core::mem::Pin; + +use futures_core::{Async, 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 `Async::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 Async for Fuse { + type Output = A::Output; + + fn poll(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::Pending, + }; + + // 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(v) + } +} diff --git a/futures-util/src/async_trait/inspect.rs b/futures-util/src/async_trait/inspect.rs new file mode 100644 index 0000000000..4c2e2fb8d1 --- /dev/null +++ b/futures-util/src/async_trait/inspect.rs @@ -0,0 +1,44 @@ +use core::mem::Pin; + +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 [`AsyncExt::inspect`] method. +#[derive(Debug)] +#[must_use = "futures do nothing unless polled"] +pub struct Inspect where A: Async { + future: A, + f: Option, +} + +pub fn new(future: A, f: F) -> Inspect + where A: Async, + F: FnOnce(&A::Output), +{ + Inspect { + future: future, + f: Some(f), + } +} + +impl Async for Inspect + where A: Async, + F: FnOnce(&A::Output), +{ + type Output = A::Output; + + fn poll(mut self: Pin, cx: &mut task::Context) -> Poll { + let e = match unsafe { pinned_field!(self, future) }.poll(cx) { + Poll::Pending => return Poll::Pending, + Poll::Ready(e) => e, + }; + + let f = unsafe { + Pin::get_mut(&mut self).f.take().expect("cannot poll Inspect twice") + }; + f(&e); + Poll::Ready(e) + } +} 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/async_trait/lazy.rs b/futures-util/src/async_trait/lazy.rs new file mode 100644 index 0000000000..ac604224c3 --- /dev/null +++ b/futures-util/src/async_trait/lazy.rs @@ -0,0 +1,56 @@ +//! Definition of the Lazy combinator, deferring execution of a function until +//! the future is polled. + +use core::mem::Pin; +use core::marker::Unpin; + +use futures_core::{Async, Poll}; +use futures_core::task; + +/// A future which, when polled, invokes a closure and yields its result. +/// +/// This is created by the `lazy` function. +#[derive(Debug)] +#[must_use = "futures do nothing unless polled"] +pub struct Lazy { + f: Option +} + +// safe because we never generate `Pin` +unsafe impl Unpin for Lazy {} + +/// Creates a new future from a closure. +/// +/// The provided closure is only run once the future is polled. +/// +/// # Examples +/// +/// ``` +/// # extern crate futures; +/// use futures::prelude::*; +/// use futures::future; +/// +/// # fn main() { +/// let a = future::lazy(|_| 1); +/// +/// let b = future::lazy(|_| -> i32 { +/// panic!("oh no!") +/// }); +/// drop(b); // closure is never run +/// # } +/// ``` +pub fn lazy(f: F) -> Lazy + where F: FnOnce(&mut task::Context) -> R, +{ + Lazy { f: Some(f) } +} + +impl Async for Lazy + where F: FnOnce(&mut task::Context) -> R, +{ + type Output = R; + + fn poll(mut self: Pin, cx: &mut task::Context) -> Poll { + Poll::Ready((self.f.take().unwrap())(cx)) + } +} diff --git a/futures-util/src/async_trait/map.rs b/futures-util/src/async_trait/map.rs new file mode 100644 index 0000000000..960edfce9e --- /dev/null +++ b/futures-util/src/async_trait/map.rs @@ -0,0 +1,42 @@ +use core::mem::Pin; + +use futures_core::{Async, Poll}; +use futures_core::task; + +/// Async for the `map` combinator, changing the type of a future. +/// +/// This is created by the `Async::map` method. +#[derive(Debug)] +#[must_use = "futures do nothing unless polled"] +pub struct Map where A: Async { + future: A, + f: Option, +} + +pub fn new(future: A, f: F) -> Map + where A: Async, +{ + Map { + future: future, + f: Some(f), + } +} + +impl Async for Map + where A: Async, + F: FnOnce(A::Output) -> U, +{ + type Output = U; + + fn poll(mut self: Pin, cx: &mut task::Context) -> Poll { + let e = match unsafe { pinned_field!(self, future) }.poll(cx) { + Poll::Pending => return Poll::Pending, + Poll::Ready(e) => e, + }; + + let f = unsafe { + Pin::get_mut(&mut self).f.take().expect("cannot poll Map twice") + }; + Poll::Ready(f(e)) + } +} diff --git a/futures-util/src/async_trait/mod.rs b/futures-util/src/async_trait/mod.rs new file mode 100644 index 0000000000..4455a60adc --- /dev/null +++ b/futures-util/src/async_trait/mod.rs @@ -0,0 +1,574 @@ +//! Asyncs +//! +//! 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::Async; +// use futures_sink::Sink; + +// Primitive futures +mod empty; +mod lazy; +mod poll_fn; +pub use self::empty::{empty, Empty}; +pub use self::lazy::{lazy, Lazy}; +pub use self::poll_fn::{poll_fn, PollFn}; + +// combinators +mod flatten; +// mod flatten_sink; +mod fuse; +// mod join; +mod map; +// mod select; +mod then; +mod inspect; + +// impl details +mod chain; + +pub use self::flatten::Flatten; +// pub use self::flatten_sink::FlattenSink; +pub use self::fuse::Fuse; +// pub use self::join::{Join, Join3, Join4, Join5}; +pub use self::map::Map; +// pub use self::select::Select; +pub use self::then::Then; +pub use self::inspect::Inspect; + +pub use either::Either; + +if_std! { + mod catch_unwind; + + /* TODO + mod join_all; + mod select_all; + mod select_ok; + mod shared; + + 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}; + */ + + mod with_executor; + pub use self::catch_unwind::CatchUnwind; + pub use self::with_executor::WithExecutor; +} + +impl AsyncExt for T where T: Async {} + +/// An extension trait for `Async`s that provides a variety of convenient +/// adapters. +pub trait AsyncExt: Async { + /// 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. + /// + /// 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::ready(1); + /// let new_future = future.map(|x| x + 3); + /// assert_eq!(block_on(new_future), 4); + /// # } + /// ``` + fn map(self, f: F) -> Map + where F: FnOnce(Self::Output) -> U, + Self: Sized, + { + assert_future::(map::new(self, f)) + } + + /// 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 `Async` trait + /// and can represent some more work to be done before the composed future + /// is finished. + /// + /// The closure `f` is only run *after* successful completion of the `self` + /// future. + /// + /// 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::ready(1); + /// let future_of_4 = future_of_1.then(|x| future::ready(x + 3)); + /// assert_eq!(block_on(future_of_4), 4); + /// ``` + fn then(self, f: F) -> Then + where F: FnOnce(Self::Output) -> B, + B: Async, + Self: Sized, + { + assert_future::(then::new(self, f)) + } + + /* TODO + /// 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: Async + 'static, + /// B: Async + '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: IntoAsync, 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 `Async`s is errored, the resulting + /// `Async` 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: IntoAsync, + 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: IntoAsync, + C: IntoAsync, + 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: IntoAsync, + C: IntoAsync, + D: IntoAsync, + 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: IntoAsync, + C: IntoAsync, + D: IntoAsync, + E: IntoAsync, + 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_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 { + /// ready(true).left_future() + /// } else { + /// ready(false).right_future() + /// }; + /// + /// assert_eq!(true, block_on(future)); + /// # } + /// ``` + fn left_future(self) -> Either + where B: Async, + 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 { + /// ready(true).left_future() + /// } else { + /// ready(false).right_future() + /// }; + /// + /// assert_eq!(false, block_on(future)); + /// # } + fn right_future(self) -> Either + where A: Async, + Self: Sized, + { + Either::Right(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 + /// `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)`. + /// + /// 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::ready(future::ready(1)); + /// let future = nested_future.flatten(); + /// assert_eq!(block_on(future), 1); + /// # } + /// ``` + fn flatten(self) -> Flatten + where Self::Output: Async, + Self: Sized + { + let f = flatten::new(self); + assert_future::<<::Output as Async>::Output, _>(f) + } + + /* TODO + /// 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) + } + */ + + /// 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 output of a future before 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, without consuming the intermediate + /// value. 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::ready(1); + /// let new_future = future.inspect(|&x| println!("about to resolve: {}", x)); + /// assert_eq!(block_on(new_future), 1); + /// # } + /// ``` + fn inspect(self, f: F) -> Inspect + where F: FnOnce(&Self::Output) -> (), + Self: Sized, + { + assert_future::(inspect::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 `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. + /// + /// # Examples + /// + /// ```rust + /// # extern crate futures; + /// # extern crate futures_executor; + /// use futures::prelude::*; + /// 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(|_| -> ReadyAsync { + /// panic!(); + /// future::ready(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 with `SharedItem`, + /// which implements `Deref` to allow shared access to the underlying + /// result. Ownership of the underlying value 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::ready(6); + /// let shared1 = future.shared(); + /// let shared2 = shared1.clone(); + /// + /// assert_eq!(6, *block_on(shared1)); + /// assert_eq!(6, *block_on(shared2)); + /// # } + /// ``` + /// + /// ``` + /// # 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::ready(6); + /// let shared1 = future.shared(); + /// let shared2 = shared1.clone(); + /// let join_handle = thread::spawn(move || { + /// assert_eq!(6, *block_on(shared2)); + /// }); + /// assert_eq!(6, *block_on(shared1)); + /// join_handle.join().unwrap(); + /// # } + /// ``` + #[cfg(feature = "std")] + fn shared(self) -> Shared + where Self: Sized + { + shared::new(self) + } +*/ + + /// 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::ready(3); + /// let spawn_future = spawn(future).with_executor(pool); + /// assert_eq!(block_on(spawn_future), 3); + /// # } + /// ``` + #[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: Async, +{ + t +} diff --git a/futures-util/src/async_trait/poll_fn.rs b/futures-util/src/async_trait/poll_fn.rs new file mode 100644 index 0000000000..dcac6a5c2d --- /dev/null +++ b/futures-util/src/async_trait/poll_fn.rs @@ -0,0 +1,53 @@ +//! Definition of the `PollFn` adapter combinator + +use core::mem::Pin; + +use futures_core::{Async, Poll}; +use futures_core::task; + +/// A future which adapts a function returning `Poll`. +/// +/// Created by the `poll_fn` function. +#[derive(Debug)] +#[must_use = "futures do nothing unless polled"] +pub struct PollFn { + inner: F, +} + +/// Creates a new future wrapping around a function returning `Poll`. +/// +/// Polling 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) -> Poll { +/// Ok(Async::Ready("Hello, World!".into())) +/// } +/// +/// let read_future = poll_fn(read_line); +/// # } +/// ``` +pub fn poll_fn(f: F) -> PollFn + where F: FnMut(&mut task::Context) -> Poll +{ + PollFn { inner: f } +} + +impl Async for PollFn + where F: FnMut(&mut task::Context) -> Poll +{ + type Output = T; + + fn poll(mut self: Pin, cx: &mut task::Context) -> Poll { + // safe because we never expose a Pin + (unsafe { Pin::get_mut(&mut self) }.inner)(cx) + } +} 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/async_trait/shared.rs b/futures-util/src/async_trait/shared.rs new file mode 100644 index 0000000000..5ac159630c --- /dev/null +++ b/futures-util/src/async_trait/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::{Async, Poll, Async}; +use futures_core::task::{self, Wake, Waker, LocalMap}; + +/// A future that is cloneable and can be polled in multiple threads. +/// Use `Async::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: Async + 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: 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`. + 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 Async for Shared + where F: Async +{ + type Item = SharedItem; + type Error = SharedError; + + fn poll(&mut self, cx: &mut task::Context) -> Poll { + 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); + + // Poll 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: Async { + 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: Async { + 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: Async + Send, + F::Item: Send + Sync, + F::Error: Send + Sync +{} + +unsafe impl Send for Inner + where F: Async + Send, + F::Item: Send + Sync, + F::Error: Send + Sync +{} + +impl fmt::Debug for Inner + where F: Async + 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/async_trait/then.rs b/futures-util/src/async_trait/then.rs new file mode 100644 index 0000000000..492c06205d --- /dev/null +++ b/futures-util/src/async_trait/then.rs @@ -0,0 +1,36 @@ +use core::mem::Pin; + +use futures_core::{Async, Poll}; +use futures_core::task; +use super::chain::Chain; + +/// Async for the `then` combinator, chaining computations on the end of +/// another future regardless of its outcome. +/// +/// This is created by the `Async::then` method. +#[derive(Debug)] +#[must_use = "futures do nothing unless polled"] +pub struct Then where A: Async, B: Async { + state: Chain, +} + +pub fn new(future: A, f: F) -> Then + where A: Async, + B: Async, +{ + Then { + state: Chain::new(future, f), + } +} + +impl Async for Then + where A: Async, + B: Async, + F: FnOnce(A::Output) -> B, +{ + type Output = B::Output; + + fn poll(mut self: Pin, cx: &mut task::Context) -> Poll { + unsafe { pinned_field!(self, state) }.poll(cx, |a, f| f(a)) + } +} diff --git a/futures-util/src/async_trait/with_executor.rs b/futures-util/src/async_trait/with_executor.rs new file mode 100644 index 0000000000..74a6318f06 --- /dev/null +++ b/futures-util/src/async_trait/with_executor.rs @@ -0,0 +1,37 @@ +use core::mem::Pin; + +use futures_core::{Async, Poll}; +use futures_core::task; +use futures_core::executor::Executor; + +/// Async for the `with_executor` combinator, assigning an executor +/// to be used when spawning other futures. +/// +/// This is created by the `Async::with_executor` method. +#[derive(Debug)] +#[must_use = "futures do nothing unless polled"] +pub struct WithExecutor where F: Async, E: Executor { + executor: E, + future: F +} + +pub fn new(future: F, executor: E) -> WithExecutor + where F: Async, + E: Executor, +{ + WithExecutor { executor, future } +} + +impl Async for WithExecutor + where F: Async, + E: Executor, +{ + type Output = F::Output; + + fn poll(mut self: Pin, cx: &mut task::Context) -> Poll { + let this = unsafe { Pin::get_mut(&mut self) }; + let fut = unsafe { Pin::new_unchecked(&mut this.future) }; + let exec = &mut this.executor; + fut.poll(&mut cx.with_executor(exec)) + } +} 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 index c6a5800d5b..7a6fcb9ce9 100644 --- a/futures-util/src/future/catch_unwind.rs +++ b/futures-util/src/future/catch_unwind.rs @@ -1,9 +1,8 @@ -use std::mem::Pin; use std::prelude::v1::*; use std::any::Any; use std::panic::{catch_unwind, UnwindSafe, AssertUnwindSafe}; -use futures_core::{Future, Poll}; +use futures_core::{Future, PollResult, Poll}; use futures_core::task; /// Future for the `catch_unwind` combinator. @@ -12,25 +11,35 @@ use futures_core::task; #[derive(Debug)] #[must_use = "futures do nothing unless polled"] pub struct CatchUnwind where F: Future { - future: F, + future: Option, } pub fn new(future: F) -> CatchUnwind where F: Future + UnwindSafe, { - CatchUnwind { future } + CatchUnwind { + future: Some(future), + } } impl Future for CatchUnwind where F: Future + UnwindSafe, { - type Output = Result>; + type Item = Result; + type Error = Box; - fn poll(mut self: Pin, cx: &mut task::Context) -> Poll { - let fut = unsafe { pinned_field!(self, future) }; - match catch_unwind(AssertUnwindSafe(|| fut.poll(cx))) { - Ok(res) => res.map(Ok), - Err(e) => Poll::Ready(Err(e)) + 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 index faa25d3110..fe75f98f32 100644 --- a/futures-util/src/future/chain.rs +++ b/futures-util/src/future/chain.rs @@ -1,53 +1,49 @@ -use core::mem::Pin; +use core::mem; -use futures_core::{Future, Poll}; +use futures_core::{Future, PollResult, Poll}; use futures_core::task; #[must_use = "futures do nothing unless polled"] #[derive(Debug)] -pub enum Chain { - First(Fut1, Option), - Second(Fut2), +pub enum Chain where A: Future { + First(A, C), + Second(B), + Done, } -impl Chain - where Fut1: Future, - Fut2: Future, +impl Chain + where A: Future, + B: Future, { - pub fn new(fut1: Fut1, data: Data) -> Chain { - Chain::First(fut1, Some(data)) + pub fn new(a: A, c: C) -> Chain { + Chain::First(a, c) } - pub fn poll(mut self: Pin, cx: &mut task::Context, f: F) -> Poll - where F: FnOnce(Fut1::Output, Data) -> Fut2, + pub fn poll(&mut self, cx: &mut task::Context, f: F) -> PollResult + where F: FnOnce(Result, C) + -> Result, B::Error>, { - let mut f = Some(f); - - loop { - // safe to `get_mut` here because we don't move out - let fut2 = match *unsafe { Pin::get_mut(&mut self) } { - Chain::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(cx) { - Poll::Pending => return Poll::Pending, - Poll::Ready(t) => { - (f.take().unwrap())(t, data.take().unwrap()) - } - } - } - Chain::Second(ref mut fut2) => { - // 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(cx) + let a_result = match *self { + Chain::First(ref mut a, _) => { + match a.poll(cx) { + Poll::Pending => return Poll::Pending, + Poll::Ready(r) => r, } - }; - - // safe because we're using the `&mut` to do an assignment, not for moving out - unsafe { - // note: it's safe to move the `fut2` here because we haven't yet polled it - *Pin::get_mut(&mut self) = Chain::Second(fut2); + } + 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 index c79f87d6da..aaddb8025a 100644 --- a/futures-util/src/future/empty.rs +++ b/futures-util/src/future/empty.rs @@ -1,9 +1,8 @@ //! Definition of the Empty combinator, a future that's never ready. -use core::mem::Pin; use core::marker; -use futures_core::{Future, Poll}; +use futures_core::{Future, PollResult, Poll}; use futures_core::task; /// A future which is never resolved. @@ -11,22 +10,23 @@ use futures_core::task; /// This future can be created with the `empty` function. #[derive(Debug)] #[must_use = "futures do nothing unless polled"] -pub struct Empty { - _data: marker::PhantomData, +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 { +pub fn empty() -> Empty { Empty { _data: marker::PhantomData } } -impl Future for Empty { - type Output = T; +impl Future for Empty { + type Item = T; + type Error = E; - fn poll(self: Pin, _: &mut task::Context) -> Poll { + 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 index 9481f4d4d4..42674b8e77 100644 --- a/futures-util/src/future/flatten.rs +++ b/futures-util/src/future/flatten.rs @@ -1,7 +1,6 @@ use core::fmt; -use core::mem::Pin; -use futures_core::{Future, Poll}; +use futures_core::{Future, IntoFuture, PollResult}; use futures_core::task; use super::chain::Chain; @@ -12,13 +11,14 @@ use super::chain::Chain; /// /// This is created by the `Future::flatten` method. #[must_use = "futures do nothing unless polled"] -pub struct Flatten where A: Future, A::Output: Future { - state: Chain, +pub struct Flatten where A: Future, A::Item: IntoFuture { + state: Chain::Future, ()>, } impl fmt::Debug for Flatten where A: Future + fmt::Debug, - A::Output: 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") @@ -29,7 +29,7 @@ impl fmt::Debug for Flatten pub fn new(future: A) -> Flatten where A: Future, - A::Output: Future, + A::Item: IntoFuture, { Flatten { state: Chain::new(future, ()), @@ -38,11 +38,16 @@ pub fn new(future: A) -> Flatten impl Future for Flatten where A: Future, - A::Output: Future, + A::Item: IntoFuture, + <::Item as IntoFuture>::Error: From<::Error> { - type Output = ::Output; + type Item = <::Item as IntoFuture>::Item; + type Error = <::Item as IntoFuture>::Error; - fn poll(mut self: Pin, cx: &mut task::Context) -> Poll { - unsafe { pinned_field!(self, state) }.poll(cx, |a, ()| a) + 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 index 5a29cb4e4a..5839d05d09 100644 --- a/futures-util/src/future/flatten_sink.rs +++ b/futures-util/src/future/flatten_sink.rs @@ -1,6 +1,6 @@ use core::fmt; -use futures_core::{task, Async, Future}; +use futures_core::{task, Poll, PollResult, Future}; use futures_sink::Sink; #[derive(Debug)] @@ -33,12 +33,12 @@ impl Sink for FlattenSink where F: Future, ::Item: Sink::Item as Sink>::SinkItem; type SinkError = <::Item as Sink>::SinkError; - fn poll_ready(&mut self, cx: &mut task::Context) -> Result, Self::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 f.poll(cx)? { - Async::Pending => return Ok(Async::Pending), - Async::Ready(s) => s, + 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"), }; @@ -55,21 +55,21 @@ impl Sink for FlattenSink where F: Future, ::Item: Sink Result, Self::SinkError> { + 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(_) => Ok(Async::Ready(())), + State::Waiting(_) => Poll::Ready(Ok(())), State::Closed => panic!("poll_flush called after eof"), } } - fn poll_close(&mut self, cx: &mut task::Context) -> Result, Self::SinkError> { + fn poll_close(&mut self, cx: &mut task::Context) -> PollResult<(), Self::SinkError> { if let State::Ready(ref mut s) = self.st { - try_ready!(s.poll_close(cx)); + try_poll!(s.poll_close(cx)); } self.st = State::Closed; - return Ok(Async::Ready(())); + return Poll::Ready(Ok(())); } } diff --git a/futures-util/src/future/flatten_stream.rs b/futures-util/src/future/flatten_stream.rs index b6d71bac67..c3a1cacefd 100644 --- a/futures-util/src/future/flatten_stream.rs +++ b/futures-util/src/future/flatten_stream.rs @@ -1,7 +1,6 @@ use core::fmt; -use core::mem::Pin; -use futures_core::{Future, Poll, Stream}; +use futures_core::{Poll, Future, PollResult, Stream}; use futures_core::task; /// Future for the `flatten_stream` combinator, flattening a @@ -9,13 +8,16 @@ use futures_core::task; /// /// This is created by the `Future::flatten_stream` method. #[must_use = "streams do nothing unless polled"] -pub struct FlattenStream { +pub struct FlattenStream + where F: Future, + ::Item: Stream, +{ state: State } impl fmt::Debug for FlattenStream where F: Future + fmt::Debug, - F::Output: fmt::Debug, + ::Item: Stream + fmt::Debug, { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { fmt.debug_struct("FlattenStream") @@ -24,57 +26,73 @@ impl fmt::Debug for FlattenStream } } -pub fn new(f: F) -> FlattenStream { +pub fn new(f: F) -> FlattenStream + where F: Future, + ::Item: Stream, +{ FlattenStream { state: State::Future(f) } } #[derive(Debug)] -enum State { +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::Output), + 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, - F::Output: Stream, + ::Item: Stream, { - type Item = ::Item; + type Item = ::Item; + type Error = ::Error; - fn poll_next(mut self: Pin, cx: &mut task::Context) -> Poll> { + fn poll_next(&mut self, cx: &mut task::Context) -> PollResult, Self::Error> { loop { - // safety: data is never moved via the resulting &mut reference - let stream = match unsafe { Pin::get_mut(&mut self) }.state { + let (next_state, ret_opt) = match 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) { + match f.poll(cx) { Poll::Pending => { // State is not changed, early return. return Poll::Pending }, - Poll::Ready(stream) => { + Poll::Ready(Ok(stream)) => { // Future resolved to stream. // We do not return, but poll that // stream in the next loop iteration. - stream + (State::Stream(stream), None) + } + Poll::Ready(Err(e)) => { + (State::Eof, Some(Poll::Ready(Err(e)))) } } } 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); + // 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"); } }; - 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); + 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 index b98c321549..d1e428f58d 100644 --- a/futures-util/src/future/fuse.rs +++ b/futures-util/src/future/fuse.rs @@ -1,6 +1,4 @@ -use core::mem::Pin; - -use futures_core::{Future, Poll}; +use futures_core::{Future, PollResult, Poll}; use futures_core::task; /// A future which "fuses" a future once it's been resolved. @@ -23,23 +21,14 @@ pub fn new(f: A) -> Fuse { } impl Future for Fuse { - type Output = A::Output; - - fn poll(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::Pending, - }; + type Item = A::Item; + type Error = A::Error; - // 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(v) + 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 index f348734cff..38775ed72a 100644 --- a/futures-util/src/future/inspect.rs +++ b/futures-util/src/future/inspect.rs @@ -1,6 +1,4 @@ -use core::mem::Pin; - -use futures_core::{Future, Poll}; +use futures_core::{Future, PollResult, Poll}; use futures_core::task; /// Do something with the item of a future, passing it on. @@ -15,7 +13,7 @@ pub struct Inspect where A: Future { pub fn new(future: A, f: F) -> Inspect where A: Future, - F: FnOnce(&A::Output), + F: FnOnce(&A::Item), { Inspect { future: future, @@ -25,20 +23,16 @@ pub fn new(future: A, f: F) -> Inspect impl Future for Inspect where A: Future, - F: FnOnce(&A::Output), + F: FnOnce(&A::Item), { - type Output = A::Output; - - fn poll(mut self: Pin, cx: &mut task::Context) -> Poll { - let e = match unsafe { pinned_field!(self, future) }.poll(cx) { - Poll::Pending => return Poll::Pending, - Poll::Ready(e) => e, - }; + type Item = A::Item; + type Error = A::Error; - let f = unsafe { - Pin::get_mut(&mut self).f.take().expect("cannot poll Inspect twice") - }; - f(&e); - Poll::Ready(e) + 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 index 57779fed51..ab4542060f 100644 --- a/futures-util/src/future/into_stream.rs +++ b/futures-util/src/future/into_stream.rs @@ -1,6 +1,4 @@ -use core::mem::Pin; - -use futures_core::{Poll, Future, Stream}; +use futures_core::{Poll, PollResult, Future, Stream}; use futures_core::task; /// A type which converts a `Future` into a `Stream` @@ -18,23 +16,20 @@ pub fn new(future: F) -> IntoStream { } impl Stream for IntoStream { - type Item = F::Output; + type Item = F::Item; + type Error = F::Error; - 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) { + 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(v) => v + Poll::Ready(r) => r, } } - 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)) + self.future = None; + Poll::Ready(ret.map(Some)) } } diff --git a/futures-util/src/future/join.rs b/futures-util/src/future/join.rs old mode 100644 new mode 100755 index e32470c26a..4b0de33372 --- a/futures-util/src/future/join.rs +++ b/futures-util/src/future/join.rs @@ -3,7 +3,7 @@ use core::fmt; use core::mem; -use futures_core::{Future, Poll, Async}; +use futures_core::{Future, PollResult, Poll}; use futures_core::task; macro_rules! generate { @@ -64,12 +64,12 @@ macro_rules! generate { type Item = (A::Item, $($B::Item),*); type Error = A::Error; - fn poll(&mut self, cx: &mut task::Context) -> Poll { + 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 Err(e) + return Poll::Ready(Err(e)) } }; $( @@ -77,15 +77,15 @@ macro_rules! generate { Ok(done) => all_done && done, Err(e) => { self.erase(); - return Err(e) + return Poll::Ready(Err(e)) } }; )* if all_done { - Ok(Async::Ready((self.a.take(), $(self.$B.take()),*))) + Poll::Ready(Ok((self.a.take(), $(self.$B.take()),*))) } else { - Ok(Async::Pending) + Poll::Pending } } } @@ -154,16 +154,16 @@ enum MaybeDone { impl MaybeDone { fn poll(&mut self, cx: &mut task::Context) -> Result { let res = match *self { - MaybeDone::NotYet(ref mut a) => a.poll(cx)?, + MaybeDone::NotYet(ref mut a) => a.poll(cx).ok()?, MaybeDone::Done(_) => return Ok(true), MaybeDone::Gone => panic!("cannot poll Join twice"), }; match res { - Async::Ready(res) => { + Poll::Ready(res) => { *self = MaybeDone::Done(res); Ok(true) } - Async::Pending => Ok(false), + Poll::Pending => Ok(false), } } diff --git a/futures-util/src/future/join_all.rs b/futures-util/src/future/join_all.rs index e6c20ffdd6..0e8710d817 100644 --- a/futures-util/src/future/join_all.rs +++ b/futures-util/src/future/join_all.rs @@ -7,7 +7,7 @@ use std::fmt; use std::mem; use std::iter::FromIterator; -use futures_core::{Future, IntoFuture, Poll, Async}; +use futures_core::{Future, IntoFuture, PollResult, Poll}; use futures_core::task; #[derive(Debug)] @@ -94,19 +94,18 @@ impl Future for JoinAll type Error = F::Error; - fn poll(&mut self, cx: &mut task::Context) -> Poll { + 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) { - Ok(Async::Ready(v)) => Ok(v), - Ok(Async::Pending) => { + Poll::Pending => { all_done = false; continue } - Err(e) => Err(e), + Poll::Ready(r) => r, } } ElemState::Done(ref mut _v) => continue, @@ -118,7 +117,7 @@ impl Future for JoinAll // On completion drop all our associated resources // ASAP. self.elems = Vec::new(); - return Err(e) + return Poll::Ready(Err(e)) } } } @@ -131,9 +130,9 @@ impl Future for JoinAll _ => unreachable!(), } }).collect(); - Ok(Async::Ready(result)) + Poll::Ready(Ok(result)) } else { - Ok(Async::Pending) + Poll::Pending } } } diff --git a/futures-util/src/future/lazy.rs b/futures-util/src/future/lazy.rs index 5732363b44..34f852c1da 100644 --- a/futures-util/src/future/lazy.rs +++ b/futures-util/src/future/lazy.rs @@ -1,56 +1,88 @@ //! Definition of the Lazy combinator, deferring execution of a function until //! the future is polled. -use core::mem::Pin; -use core::marker::Unpin; +use core::mem; -use futures_core::{Future, Poll}; +use futures_core::{Future, IntoFuture, PollResult}; use futures_core::task; -/// A future which, when polled, invokes a closure and yields its result. +/// 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 { - f: Option +pub struct Lazy { + inner: _Lazy, } -// safe because we never generate `Pin` -unsafe impl Unpin for Lazy {} +#[derive(Debug)] +enum _Lazy { + First(F), + Second(R), + Moved, +} -/// Creates a new future from a closure. +/// 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; +/// use futures::future::{self, FutureResult}; /// /// # fn main() { -/// let a = future::lazy(|_| 1); +/// let a = future::lazy(|_| future::ok::(1)); /// -/// let b = future::lazy(|_| -> i32 { +/// let b = future::lazy(|_| -> FutureResult { /// panic!("oh no!") /// }); /// drop(b); // closure is never run /// # } /// ``` -pub fn lazy(f: F) -> Lazy +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, { - Lazy { f: Some(f) } + 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 +impl Future for Lazy where F: FnOnce(&mut task::Context) -> R, + R: IntoFuture, { - type Output = R; + type Item = R::Item; + type Error = R::Error; - fn poll(mut self: Pin, cx: &mut task::Context) -> Poll { - Poll::Ready((self.f.take().unwrap())(cx)) + 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 index 3117698f15..9182271a2c 100644 --- a/futures-util/src/future/map.rs +++ b/futures-util/src/future/map.rs @@ -1,6 +1,4 @@ -use core::mem::Pin; - -use futures_core::{Future, Poll}; +use futures_core::{Future, PollResult, Poll}; use futures_core::task; /// Future for the `map` combinator, changing the type of a future. @@ -24,19 +22,16 @@ pub fn new(future: A, f: F) -> Map impl Future for Map where A: Future, - F: FnOnce(A::Output) -> U, + F: FnOnce(A::Item) -> U, { - type Output = U; + type Item = U; + type Error = A::Error; - fn poll(mut self: Pin, cx: &mut task::Context) -> Poll { - let e = match unsafe { pinned_field!(self, future) }.poll(cx) { + fn poll(&mut self, cx: &mut task::Context) -> PollResult { + let e = match self.future.poll(cx) { Poll::Pending => return Poll::Pending, - Poll::Ready(e) => e, - }; - - let f = unsafe { - Pin::get_mut(&mut self).f.take().expect("cannot poll Map twice") + Poll::Ready(r) => r, }; - Poll::Ready(f(e)) + 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 index 0524fe4cf7..8b6af3c7bb 100644 --- a/futures-util/src/future/mod.rs +++ b/futures-util/src/future/mod.rs @@ -3,69 +3,80 @@ //! This module contains a number of functions for working with `Future`s, //! including the `FutureExt` trait which adds methods to `Future` types. -use futures_core::{Future, Stream}; -// use futures_sink::Sink; +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, PollFn}; +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_sink; mod flatten_stream; mod fuse; mod into_stream; -// mod join; +mod join; mod map; -// mod select; +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_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::join::{Join, Join3, Join4, Join5}; pub use self::map::Map; -// pub use self::select::Select; +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; - - /* TODO mod join_all; mod select_all; mod select_ok; - mod shared; - + //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}; - */ - - mod with_executor; - pub use self::catch_unwind::CatchUnwind; + //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 -/// adapters. +/// combinator functions. pub trait FutureExt: Future { /// Map this future's result to a different type, returning a new future of /// the resulting type. @@ -74,6 +85,10 @@ pub trait FutureExt: Future { /// 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. @@ -88,27 +103,131 @@ pub trait FutureExt: Future { /// use futures_executor::block_on; /// /// # fn main() { - /// let future = future::ready(1); + /// 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), 4); + /// assert_eq!(block_on(new_future), Err(1)); /// # } /// ``` fn map(self, f: F) -> Map - where F: FnOnce(Self::Output) -> U, + where F: FnOnce(Self::Item) -> U, Self: Sized, { - assert_future::(map::new(self, f)) + 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`. /// - /// The returned value of the closure must implement the `Future` trait + /// 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. + /// 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. /// - /// The closure `f` is only run *after* successful completion of the `self` - /// future. + /// 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. @@ -121,19 +240,116 @@ pub trait FutureExt: Future { /// use futures::future; /// /// # fn main() { - /// let future_of_1 = future::ready(1); - /// let future_of_4 = future_of_1.then(|x| future::ready(x + 3)); - /// assert_eq!(block_on(future_of_4), 4); + /// 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(Self::Output) -> B, - B: Future, + where F: FnOnce(result::Result) -> B, + B: IntoFuture, Self: Sized, { - assert_future::(then::new(self, f)) + 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)) } - /* TODO /// Waits for either one of two differently-typed futures to complete. /// /// This function will return a new future which awaits for either this or @@ -268,7 +484,38 @@ pub trait FutureExt: Future { 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`. @@ -286,16 +533,16 @@ pub trait FutureExt: Future { /// # fn main() { /// let x = 6; /// let future = if x < 10 { - /// ready(true).left_future() + /// ok::<_, bool>(x).left_future() /// } else { - /// ready(false).right_future() + /// empty().right_future() /// }; /// - /// assert_eq!(true, block_on(future)); + /// assert_eq!(x, block_on(future).unwrap()); /// # } /// ``` fn left_future(self) -> Either - where B: Future, + where B: Future, Self: Sized { Either::Left(self) @@ -317,15 +564,48 @@ pub trait FutureExt: Future { /// # fn main() { /// let x = 6; /// let future = if x < 10 { - /// ready(true).left_future() + /// 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 { - /// ready(false).right_future() + /// empty().right_future() /// }; /// - /// assert_eq!(false, block_on(future)); + /// assert_eq!(x, block_on(future).unwrap()); /// # } + /// ``` fn right_future(self) -> Either - where A: Future, + where A: Future, Self: Sized, { Either::Right(self) @@ -346,10 +626,15 @@ pub trait FutureExt: Future { /// use futures_executor::block_on; /// /// # fn main() { - /// let future = future::ready::(17); + /// let future = future::ok::<_, bool>(17); /// let stream = future.into_stream(); - /// let collected: Vec<_> = block_on(stream.collect()); + /// 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 @@ -382,20 +667,38 @@ pub trait FutureExt: Future { /// use futures_executor::block_on; /// /// # fn main() { - /// let nested_future = future::ready(future::ready(1)); + /// let nested_future = future::ok::<_, u32>(future::ok::(1)); /// let future = nested_future.flatten(); - /// assert_eq!(block_on(future), 1); + /// 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::Output: Future, + where Self::Item: IntoFuture::Error>, Self: Sized { let f = flatten::new(self); - assert_future::<<::Output as Future>::Output, _>(f) + assert_future::<<::Item as IntoFuture>::Item, + <::Item as IntoFuture>::Error, + _>(f) } - /* TODO /// Flatten the execution of this future when the successful result of this /// future is a sink. /// @@ -411,7 +714,6 @@ pub trait FutureExt: Future { { flatten_sink::new(self) } - */ /// Flatten the execution of this future when the successful result of this /// future is a stream. @@ -435,15 +737,15 @@ pub trait FutureExt: Future { /// /// # fn main() { /// let stream_items = vec![17, 18, 19]; - /// let future_of_a_stream = future::ready(stream::iter_ok(stream_items)); + /// 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()); + /// let list: Vec<_> = block_on(stream.collect()).unwrap(); /// assert_eq!(list, vec![17, 18, 19]); /// # } /// ``` fn flatten_stream(self) -> FlattenStream - where Self::Output: Stream, + where ::Item: Stream, Self: Sized { flatten_stream::new(self) @@ -468,15 +770,14 @@ pub trait FutureExt: Future { where Self: Sized { let f = fuse::new(self); - assert_future::(f) + assert_future::(f) } - /// Do something with the output of a future before passing it on. + /// 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, without consuming the intermediate - /// value. To do that, insert a call to `inspect`. + /// 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 /// @@ -488,16 +789,44 @@ pub trait FutureExt: Future { /// use futures_executor::block_on; /// /// # fn main() { - /// let future = future::ready(1); + /// let future = future::ok::(1); /// let new_future = future.inspect(|&x| println!("about to resolve: {}", x)); - /// assert_eq!(block_on(new_future), 1); + /// assert_eq!(block_on(new_future), Ok(1)); /// # } /// ``` fn inspect(self, f: F) -> Inspect - where F: FnOnce(&Self::Output) -> (), + 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::new(self, f)) + assert_future::(inspect_err::new(self, f)) } /// Catches unwinding panics while polling the future. @@ -526,12 +855,12 @@ pub trait FutureExt: Future { /// use futures_executor::block_on; /// /// # fn main() { - /// let mut future = future::ready(2); + /// let mut future = future::ok::(2); /// assert!(block_on(future.catch_unwind()).is_ok()); /// - /// let mut future = future::lazy(|_| -> ReadyFuture { + /// let mut future = future::lazy(|_| -> FutureResult { /// panic!(); - /// future::ready(2) + /// future::ok::(2) /// }); /// assert!(block_on(future.catch_unwind()).is_err()); /// # } @@ -550,9 +879,11 @@ pub trait FutureExt: Future { /// 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 with `SharedItem`, - /// which implements `Deref` to allow shared access to the underlying - /// result. Ownership of the underlying value cannot currently be reclaimed. + /// 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. @@ -567,12 +898,12 @@ pub trait FutureExt: Future { /// use futures_executor::block_on; /// /// # fn main() { - /// let future = future::ready(6); + /// let future = future::ok::<_, bool>(6); /// let shared1 = future.shared(); /// let shared2 = shared1.clone(); /// - /// assert_eq!(6, *block_on(shared1)); - /// assert_eq!(6, *block_on(shared2)); + /// assert_eq!(6, *block_on(shared1).unwrap()); + /// assert_eq!(6, *block_on(shared2).unwrap()); /// # } /// ``` /// @@ -586,13 +917,13 @@ pub trait FutureExt: Future { /// use futures_executor::block_on; /// /// # fn main() { - /// let future = future::ready(6); + /// 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)); + /// assert_eq!(6, *block_on(shared2).unwrap()); /// }); - /// assert_eq!(6, *block_on(shared1)); + /// assert_eq!(6, *block_on(shared1).unwrap()); /// join_handle.join().unwrap(); /// # } /// ``` @@ -602,7 +933,35 @@ pub trait FutureExt: Future { { 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. @@ -618,9 +977,9 @@ pub trait FutureExt: Future { /// /// # fn main() { /// let pool = ThreadPool::new().expect("unable to create threadpool"); - /// let future = future::ready(3); + /// let future = future::ok::<(), _>(()); /// let spawn_future = spawn(future).with_executor(pool); - /// assert_eq!(block_on(spawn_future), 3); + /// assert_eq!(block_on(spawn_future), Ok(())); /// # } /// ``` #[cfg(feature = "std")] @@ -634,8 +993,8 @@ 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, +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 index db8302a906..3c4bcc0c85 100644 --- a/futures-util/src/future/poll_fn.rs +++ b/futures-util/src/future/poll_fn.rs @@ -1,22 +1,20 @@ -//! Definition of the `PollFn` adapter combinator +//! Definition of the `PollResultFn` adapter combinator -use core::mem::Pin; - -use futures_core::{Future, Poll}; +use futures_core::{Future, PollResult}; use futures_core::task; -/// A future which adapts a function returning `Poll`. +/// 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 PollFn { +pub struct PollResultFn { inner: F, } -/// Creates a new future wrapping around a function returning `Poll`. +/// Creates a new future wrapping around a function returning `PollResult`. /// -/// Polling the returned future delegates to the wrapped function. +/// PollResulting the returned future delegates to the wrapped function. /// /// # Examples /// @@ -28,26 +26,26 @@ pub struct PollFn { /// use futures::task; /// /// # fn main() { -/// fn read_line(cx: &mut task::Context) -> Poll { +/// 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) -> PollFn - where F: FnMut(&mut task::Context) -> Poll +pub fn poll_fn(f: F) -> PollResultFn + where F: FnMut(&mut task::Context) -> PollResult { - PollFn { inner: f } + PollResultFn { inner: f } } -impl Future for PollFn - where F: FnMut(&mut task::Context) -> Poll +impl Future for PollResultFn + where F: FnMut(&mut task::Context) -> PollResult { - type Output = T; + type Item = T; + type Error = E; - fn poll(mut self: Pin, cx: &mut task::Context) -> Poll { - // safe because we never expose a Pin - (unsafe { Pin::get_mut(&mut self) }.inner)(cx) + 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 index cf994d4ce3..d1145ef243 100644 --- a/futures-util/src/future/select.rs +++ b/futures-util/src/future/select.rs @@ -1,4 +1,4 @@ -use futures_core::{Future, Poll, Async}; +use futures_core::{Future, PollResult, Poll}; use futures_core::task; use either::Either; @@ -23,17 +23,17 @@ 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) -> Poll { + 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) { - 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) => { + 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)); - Ok(Async::Pending) + Poll::Pending } } } diff --git a/futures-util/src/future/select_all.rs b/futures-util/src/future/select_all.rs index 38c2594a32..d032d47827 100644 --- a/futures-util/src/future/select_all.rs +++ b/futures-util/src/future/select_all.rs @@ -4,7 +4,7 @@ use std::mem; use std::prelude::v1::*; -use futures_core::{Future, IntoFuture, Poll, Async}; +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 @@ -49,24 +49,23 @@ impl Future for SelectAll type Item = (A::Item, usize, Vec); type Error = (A::Error, usize, Vec); - fn poll(&mut self, cx: &mut task::Context) -> Poll { + fn poll(&mut self, cx: &mut task::Context) -> PollResult { 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))), + Poll::Pending => None, + Poll::Ready(r) => Some((i, r)), } }).next(); match item { Some((idx, res)) => { - self.inner.remove(idx); + self.inner.swap_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)), + Ok(e) => Poll::Ready(Ok((e, idx, rest))), + Err(e) => Poll::Ready(Err((e, idx, rest))), } } - None => Ok(Async::Pending), + None => Poll::Pending, } } } diff --git a/futures-util/src/future/select_ok.rs b/futures-util/src/future/select_ok.rs index 24a7200f96..2c2f1cd1eb 100644 --- a/futures-util/src/future/select_ok.rs +++ b/futures-util/src/future/select_ok.rs @@ -4,7 +4,7 @@ use std::mem; use std::prelude::v1::*; -use futures_core::{Future, IntoFuture, Poll, Async}; +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 @@ -45,14 +45,13 @@ impl Future for SelectOk where A: Future { type Item = (A::Item, Vec); type Error = A::Error; - fn poll(&mut self, cx: &mut task::Context) -> Poll { + 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) { - Ok(Async::Pending) => None, - Ok(Async::Ready(e)) => Some((i, Ok(e))), - Err(e) => Some((i, Err(e))), + Poll::Pending => None, + Poll::Ready(r) => Some((i, r)), } }).next(); @@ -63,18 +62,18 @@ impl Future for SelectOk where A: Future { match res { Ok(e) => { let rest = mem::replace(&mut self.inner, Vec::new()); - return Ok(Async::Ready((e, rest))) + return Poll::Ready(Ok((e, rest))) }, Err(e) => { if self.inner.is_empty() { - return Err(e) + return Poll::Ready(Err(e)) } }, } } None => { // based on the filter above, nothing is ready, return - return Ok(Async::Pending) + return Poll::Pending }, } } diff --git a/futures-util/src/future/shared.rs b/futures-util/src/future/shared.rs index c7b10adf00..b91d63574d 100644 --- a/futures-util/src/future/shared.rs +++ b/futures-util/src/future/shared.rs @@ -26,7 +26,7 @@ use std::sync::atomic::AtomicUsize; use std::sync::atomic::Ordering::SeqCst; use std::collections::HashMap; -use futures_core::{Future, Poll, Async}; +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. @@ -123,7 +123,7 @@ impl Future for Shared type Item = SharedItem; type Error = SharedError; - fn poll(&mut self, cx: &mut task::Context) -> Poll { + fn poll(&mut self, cx: &mut task::Context) -> PollResult { self.set_waiter(cx); match self.inner.notifier.state.compare_and_swap(IDLE, POLLING, SeqCst) { @@ -158,7 +158,7 @@ impl Future for Shared let _reset = Reset(&self.inner.notifier.state); - // Poll the future + // 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()); diff --git a/futures-util/src/future/then.rs b/futures-util/src/future/then.rs index a26feba262..7b3daf1fbc 100644 --- a/futures-util/src/future/then.rs +++ b/futures-util/src/future/then.rs @@ -1,6 +1,4 @@ -use core::mem::Pin; - -use futures_core::{Future, Poll}; +use futures_core::{Future, IntoFuture, PollResult}; use futures_core::task; use super::chain::Chain; @@ -10,13 +8,13 @@ use super::chain::Chain; /// This is created by the `Future::then` method. #[derive(Debug)] #[must_use = "futures do nothing unless polled"] -pub struct Then where A: Future, B: Future { - state: Chain, +pub struct Then where A: Future, B: IntoFuture { + state: Chain, } pub fn new(future: A, f: F) -> Then where A: Future, - B: Future, + B: IntoFuture, { Then { state: Chain::new(future, f), @@ -25,12 +23,15 @@ pub fn new(future: A, f: F) -> Then impl Future for Then where A: Future, - B: Future, - F: FnOnce(A::Output) -> B, + B: IntoFuture, + F: FnOnce(Result) -> B, { - type Output = B::Output; + type Item = B::Item; + type Error = B::Error; - fn poll(mut self: Pin, cx: &mut task::Context) -> Poll { - unsafe { pinned_field!(self, state) }.poll(cx, |a, f| f(a)) + 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 index 4f1310c691..ee3b411d2d 100644 --- a/futures-util/src/future/with_executor.rs +++ b/futures-util/src/future/with_executor.rs @@ -1,6 +1,4 @@ -use core::mem::Pin; - -use futures_core::{Future, Poll}; +use futures_core::{Future, PollResult}; use futures_core::task; use futures_core::executor::Executor; @@ -26,12 +24,10 @@ impl Future for WithExecutor where F: Future, E: Executor, { - type Output = F::Output; + type Item = F::Item; + type Error = F::Error; - fn poll(mut self: Pin, cx: &mut task::Context) -> Poll { - let this = unsafe { Pin::get_mut(&mut self) }; - let fut = unsafe { Pin::new_unchecked(&mut this.future) }; - let exec = &mut this.executor; - fut.poll(&mut cx.with_executor(exec)) + 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 39afba0a5e..2bd41e453c 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)] @@ -15,12 +15,12 @@ extern crate futures_core; extern crate futures_executor; // extern crate futures_io; -// extern crate futures_sink; +extern crate futures_sink; extern crate either; //#[cfg(feature = "std")] -//use futures_core::{Future, Poll, task}; +//use futures_core::{Async, Poll, task}; macro_rules! if_std { ($($i:item)*) => ($( @@ -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,13 +61,16 @@ 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 future_result; -pub use future_result::FutureResult; +pub mod async_trait; +pub use async_trait::AsyncExt; + +pub mod async_result; +pub use async_result::AsyncResultExt; // #[cfg(feature = "std")] // pub mod io; @@ -83,7 +86,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}; }