From 9ff270ee89adb9ae52486f9b23fed54b6d72c048 Mon Sep 17 00:00:00 2001 From: Wim Looman Date: Sun, 24 Mar 2019 10:51:03 +0100 Subject: [PATCH 1/2] Add never_error combinator --- futures-util/Cargo.toml | 1 + futures-util/src/future/mod.rs | 14 +++++++++++ futures-util/src/future/never_error.rs | 35 ++++++++++++++++++++++++++ futures-util/src/lib.rs | 4 +++ futures/Cargo.toml | 1 + futures/src/lib.rs | 7 ++++++ 6 files changed, 62 insertions(+) create mode 100644 futures-util/src/future/never_error.rs diff --git a/futures-util/Cargo.toml b/futures-util/Cargo.toml index 2324811cf9..789485c938 100644 --- a/futures-util/Cargo.toml +++ b/futures-util/Cargo.toml @@ -22,6 +22,7 @@ io-compat = ["compat", "tokio-io"] bench = [] nightly = ["futures-core-preview/nightly", "futures-sink-preview/nightly"] cfg-target-has-atomic = ["futures-core-preview/cfg-target-has-atomic"] +never-type = [] alloc = ["futures-core-preview/alloc", "futures-sink-preview/alloc"] [dependencies] diff --git a/futures-util/src/future/mod.rs b/futures-util/src/future/mod.rs index 5c00a5b5ff..572c90ac14 100644 --- a/futures-util/src/future/mod.rs +++ b/futures-util/src/future/mod.rs @@ -70,6 +70,11 @@ pub use self::inspect::Inspect; mod unit_error; pub use self::unit_error::UnitError; +#[cfg(feature = "never-type")] +mod never_error; +#[cfg(feature = "never-type")] +pub use self::never_error::NeverError; + // Implementation details mod chain; pub(crate) use self::chain::Chain; @@ -537,6 +542,15 @@ pub trait FutureExt: Future { UnitError::new(self) } + #[cfg(feature = "never-type")] + /// Turns a [`Future`](Future) into a + /// [`TryFuture](futures_core::future::TryFuture). + fn never_error(self) -> NeverError + where Self: Sized + { + NeverError::new(self) + } + /// A convenience for calling `Future::poll` on `Unpin` future types. fn poll_unpin(&mut self, cx: &mut Context<'_>) -> Poll where Self: Unpin + Sized diff --git a/futures-util/src/future/never_error.rs b/futures-util/src/future/never_error.rs new file mode 100644 index 0000000000..84ed819d62 --- /dev/null +++ b/futures-util/src/future/never_error.rs @@ -0,0 +1,35 @@ +use core::pin::Pin; +use futures_core::future::{FusedFuture, Future}; +use futures_core::task::{self, Poll}; +use pin_utils::unsafe_pinned; + +/// Future for the [`never_error`](super::FutureExt::never_error) combinator. +#[derive(Debug)] +#[must_use = "futures do nothing unless polled"] +pub struct NeverError { + future: Fut, +} + +impl NeverError { + unsafe_pinned!(future: Fut); + + pub(super) fn new(future: Fut) -> NeverError { + NeverError { future } + } +} + +impl Unpin for NeverError {} + +impl FusedFuture for NeverError { + fn is_terminated(&self) -> bool { self.future.is_terminated() } +} + +impl Future for NeverError + where Fut: Future, +{ + type Output = Result; + + fn poll(self: Pin<&mut Self>, cx: &mut task::Context<'_>) -> Poll> { + self.future().poll(cx).map(Ok) + } +} diff --git a/futures-util/src/lib.rs b/futures-util/src/lib.rs index a1adb0fcc3..79ecae4d15 100644 --- a/futures-util/src/lib.rs +++ b/futures-util/src/lib.rs @@ -5,6 +5,7 @@ #![cfg_attr(feature = "alloc", feature(box_into_pin))] #![cfg_attr(feature = "std", feature(async_await, await_macro))] #![cfg_attr(feature = "cfg-target-has-atomic", feature(cfg_target_has_atomic))] +#![cfg_attr(feature = "never-type", feature(never_type))] #![cfg_attr(not(feature = "std"), no_std)] #![warn(missing_docs, missing_debug_implementations, rust_2018_idioms)] @@ -14,6 +15,9 @@ #[cfg(all(feature = "cfg-target-has-atomic", not(feature = "nightly")))] compile_error!("The `cfg-target-has-atomic` feature requires the `nightly` feature as an explicit opt-in to unstable features"); +#[cfg(all(feature = "never-type", not(feature = "nightly")))] +compile_error!("The `never-type` feature requires the `nightly` feature as an explicit opt-in to unstable features"); + #[cfg(feature = "alloc")] extern crate alloc; diff --git a/futures/Cargo.toml b/futures/Cargo.toml index 70d8b3ba72..f312eeaaf8 100644 --- a/futures/Cargo.toml +++ b/futures/Cargo.toml @@ -42,4 +42,5 @@ default = ["std"] compat = ["std", "futures-util-preview/compat"] io-compat = ["compat", "futures-util-preview/io-compat"] cfg-target-has-atomic = ["futures-core-preview/cfg-target-has-atomic", "futures-util-preview/cfg-target-has-atomic"] +never-type = ["futures-util-preview/never-type"] alloc = ["futures-core-preview/alloc", "futures-sink-preview/alloc", "futures-util-preview/alloc"] diff --git a/futures/src/lib.rs b/futures/src/lib.rs index 058592aca4..5b5a5ae872 100644 --- a/futures/src/lib.rs +++ b/futures/src/lib.rs @@ -23,6 +23,7 @@ #![feature(futures_api)] #![cfg_attr(feature = "cfg-target-has-atomic", feature(cfg_target_has_atomic))] +#![cfg_attr(feature = "never-type", feature(never_type))] #![cfg_attr(not(feature = "std"), no_std)] @@ -33,6 +34,9 @@ #[cfg(all(feature = "cfg-target-has-atomic", not(feature = "nightly")))] compile_error!("The `cfg-target-has-atomic` feature requires the `nightly` feature as an explicit opt-in to unstable features"); +#[cfg(all(feature = "never-type", not(feature = "nightly")))] +compile_error!("The `never-type` feature requires the `nightly` feature as an explicit opt-in to unstable features"); + #[doc(hidden)] pub use futures_util::core_reexport; #[doc(hidden)] pub use futures_core::future::Future; @@ -230,6 +234,9 @@ pub mod future { UnwrapOrElse, }; + #[cfg(feature = "never-type")] + pub use futures_util::future::NeverError; + #[cfg(feature = "alloc")] pub use futures_util::try_future::{ try_join_all, TryJoinAll, From 2bea6d5fe128ca1dfa9d62a9bf83a21c325411be Mon Sep 17 00:00:00 2001 From: Wim Looman Date: Sun, 24 Mar 2019 10:54:23 +0100 Subject: [PATCH 2/2] Improve unit_error documentation --- futures-util/src/future/mod.rs | 3 ++- futures-util/src/future/unit_error.rs | 5 +---- futures/src/lib.rs | 2 +- 3 files changed, 4 insertions(+), 6 deletions(-) diff --git a/futures-util/src/future/mod.rs b/futures-util/src/future/mod.rs index 572c90ac14..0c735023b3 100644 --- a/futures-util/src/future/mod.rs +++ b/futures-util/src/future/mod.rs @@ -535,7 +535,8 @@ pub trait FutureExt: Future { Box::pin(self) } - /// Turns a `Future` into a `TryFuture` with `Error = ()`. + /// Turns a [`Future`](Future) into a + /// [`TryFuture](futures_core::future::TryFuture). fn unit_error(self) -> UnitError where Self: Sized { diff --git a/futures-util/src/future/unit_error.rs b/futures-util/src/future/unit_error.rs index e72d742859..b473b62d0c 100644 --- a/futures-util/src/future/unit_error.rs +++ b/futures-util/src/future/unit_error.rs @@ -3,9 +3,7 @@ use futures_core::future::{FusedFuture, Future}; use futures_core::task::{Context, Poll}; use pin_utils::unsafe_pinned; -/// Future for the `unit_error` combinator, turning a `Future` into a `TryFuture`. -/// -/// This is created by the `FutureExt::unit_error` method. +/// Future for the [`unit_error`](super::FutureExt::unit_error) combinator. #[derive(Debug)] #[must_use = "futures do nothing unless polled"] pub struct UnitError { @@ -15,7 +13,6 @@ pub struct UnitError { impl UnitError { unsafe_pinned!(future: Fut); - /// Creates a new UnitError. pub(super) fn new(future: Fut) -> UnitError { UnitError { future } } diff --git a/futures/src/lib.rs b/futures/src/lib.rs index 5b5a5ae872..1825adcdbf 100644 --- a/futures/src/lib.rs +++ b/futures/src/lib.rs @@ -201,7 +201,7 @@ pub mod future { OptionFuture, FutureExt, - FlattenStream, Flatten, Fuse, Inspect, IntoStream, Map, Then, + FlattenStream, Flatten, Fuse, Inspect, IntoStream, Map, Then, UnitError, }; #[cfg(feature = "alloc")]