From f1a911e89ac76a3d0ea67b3347769af945d7c0f6 Mon Sep 17 00:00:00 2001 From: Stjepan Glavina Date: Wed, 14 Aug 2019 16:16:24 +0200 Subject: [PATCH 1/4] Add future::timeout() --- src/future/mod.rs | 2 ++ src/future/timeout.rs | 78 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 80 insertions(+) create mode 100644 src/future/timeout.rs diff --git a/src/future/mod.rs b/src/future/mod.rs index 29e2b047f..adee7bbad 100644 --- a/src/future/mod.rs +++ b/src/future/mod.rs @@ -5,6 +5,8 @@ pub use std::future::Future; pub use pending::pending; pub use ready::ready; +pub use timeout::{timeout, TimeoutError}; mod pending; mod ready; +mod timeout; diff --git a/src/future/timeout.rs b/src/future/timeout.rs new file mode 100644 index 000000000..8eb90029e --- /dev/null +++ b/src/future/timeout.rs @@ -0,0 +1,78 @@ +use std::error::Error; +use std::fmt; +use std::pin::Pin; +use std::time::Duration; + +use futures_timer::Delay; +use pin_utils::unsafe_pinned; + +use crate::future::Future; +use crate::task::{Context, Poll}; + +/// Awaits a future or times out after a duration of time. +/// +/// # Examples +/// +/// ```no_run +/// # #![feature(async_await)] +/// # fn main() -> std::io::Result<()> { async_std::task::block_on(async { +/// # +/// use std::time::Duration; +/// +/// use async_std::future; +/// +/// let never = future::pending::<()>(); +/// let dur = Duration::from_secs(5); +/// assert!(future::timeout(dur, never).await.is_err()); +/// # +/// # Ok(()) }) } +/// ``` +pub async fn timeout(dur: Duration, f: F) -> Result +where + F: Future, +{ + let f = TimeoutFuture { + future: f, + delay: Delay::new(dur), + }; + f.await +} + +/// A future that times out after a duration of time. +#[doc(hidden)] +#[allow(missing_debug_implementations)] +struct TimeoutFuture { + future: F, + delay: Delay, +} + +impl TimeoutFuture { + unsafe_pinned!(future: F); + unsafe_pinned!(delay: Delay); +} + +impl Future for TimeoutFuture { + type Output = Result; + + fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { + match self.as_mut().future().poll(cx) { + Poll::Ready(v) => Poll::Ready(Ok(v)), + Poll::Pending => match self.delay().poll(cx) { + Poll::Ready(_) => Poll::Ready(Err(TimeoutError)), + Poll::Pending => Poll::Pending, + }, + } + } +} + +/// An error returned when a future times out. +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub struct TimeoutError; + +impl Error for TimeoutError {} + +impl fmt::Display for TimeoutError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + "future has timed out".fmt(f) + } +} From 38e5d15a8fd7268207b4a6e095dd02aa30ccf878 Mon Sep 17 00:00:00 2001 From: Florian Gilcher Date: Mon, 26 Aug 2019 13:39:28 -0700 Subject: [PATCH 2/4] Update src/future/timeout.rs Co-Authored-By: Yoshua Wuyts --- src/future/timeout.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/future/timeout.rs b/src/future/timeout.rs index 8eb90029e..59eee5f89 100644 --- a/src/future/timeout.rs +++ b/src/future/timeout.rs @@ -13,7 +13,7 @@ use crate::task::{Context, Poll}; /// /// # Examples /// -/// ```no_run +/// ``` /// # #![feature(async_await)] /// # fn main() -> std::io::Result<()> { async_std::task::block_on(async { /// # From 8be2ebcd3c28eed40878ca0a0cb6c724d7c8abeb Mon Sep 17 00:00:00 2001 From: Florian Gilcher Date: Mon, 26 Aug 2019 13:39:37 -0700 Subject: [PATCH 3/4] Update src/future/timeout.rs Co-Authored-By: Yoshua Wuyts --- src/future/timeout.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/future/timeout.rs b/src/future/timeout.rs index 59eee5f89..82e69020f 100644 --- a/src/future/timeout.rs +++ b/src/future/timeout.rs @@ -22,7 +22,7 @@ use crate::task::{Context, Poll}; /// use async_std::future; /// /// let never = future::pending::<()>(); -/// let dur = Duration::from_secs(5); +/// let dur = Duration::from_millis(5); /// assert!(future::timeout(dur, never).await.is_err()); /// # /// # Ok(()) }) } From fc9091c3f27894ae427fef8dc88e592af83fdc6c Mon Sep 17 00:00:00 2001 From: Stjepan Glavina Date: Tue, 27 Aug 2019 13:30:34 +0200 Subject: [PATCH 4/4] Put futues::timeout behind unstable feature --- .travis.yml | 4 ++-- Cargo.toml | 1 + src/future/mod.rs | 11 +++++++++-- src/future/timeout.rs | 14 ++++++++------ 4 files changed, 20 insertions(+), 10 deletions(-) diff --git a/.travis.yml b/.travis.yml index 4c8dd8843..e24a31a95 100644 --- a/.travis.yml +++ b/.travis.yml @@ -23,8 +23,8 @@ before_script: - cargo install-update -a script: - - if ![[ -n "$BUILD_BOOK" ]]; then cargo check --all --benches --bins --examples --tests && cargo test --all; fi - - if [[ -n "$BUILD_BOOK" ]]; then cargo test --all --benches --bins --examples --tests; fi + - if ![[ -n "$BUILD_BOOK" ]]; then cargo check --features unstable --all --benches --bins --examples --tests && cargo test --features unstable --all; fi + - if [[ -n "$BUILD_BOOK" ]]; then cargo test --features unstable --all --benches --bins --examples --tests; fi - cargo fmt --all -- --check - if [[ -n "$BUILD_DOCS" ]]; then cargo doc --features docs; fi - if [[ -n "$BUILD_BOOK" ]]; then mdbook build docs && mdbook test -L ./target/debug/deps docs; fi diff --git a/Cargo.toml b/Cargo.toml index eba38cca2..230de6402 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -21,6 +21,7 @@ rustdoc-args = ["--cfg", "feature=\"docs\""] [features] docs = [] +unstable = [] [dependencies] async-task = "1.0.0" diff --git a/src/future/mod.rs b/src/future/mod.rs index adee7bbad..5d510a449 100644 --- a/src/future/mod.rs +++ b/src/future/mod.rs @@ -3,10 +3,17 @@ #[doc(inline)] pub use std::future::Future; +use cfg_if::cfg_if; + pub use pending::pending; pub use ready::ready; -pub use timeout::{timeout, TimeoutError}; mod pending; mod ready; -mod timeout; + +cfg_if! { + if #[cfg(any(feature = "unstable", feature = "docs"))] { + mod timeout; + pub use timeout::{timeout, TimeoutError}; + } +} diff --git a/src/future/timeout.rs b/src/future/timeout.rs index 82e69020f..cf146aeb6 100644 --- a/src/future/timeout.rs +++ b/src/future/timeout.rs @@ -4,7 +4,6 @@ use std::pin::Pin; use std::time::Duration; use futures_timer::Delay; -use pin_utils::unsafe_pinned; use crate::future::Future; use crate::task::{Context, Poll}; @@ -14,7 +13,6 @@ use crate::task::{Context, Poll}; /// # Examples /// /// ``` -/// # #![feature(async_await)] /// # fn main() -> std::io::Result<()> { async_std::task::block_on(async { /// # /// use std::time::Duration; @@ -27,6 +25,7 @@ use crate::task::{Context, Poll}; /// # /// # Ok(()) }) } /// ``` +#[cfg_attr(feature = "docs", doc(cfg(unstable)))] pub async fn timeout(dur: Duration, f: F) -> Result where F: Future, @@ -47,8 +46,8 @@ struct TimeoutFuture { } impl TimeoutFuture { - unsafe_pinned!(future: F); - unsafe_pinned!(delay: Delay); + pin_utils::unsafe_pinned!(future: F); + pin_utils::unsafe_pinned!(delay: Delay); } impl Future for TimeoutFuture { @@ -58,7 +57,7 @@ impl Future for TimeoutFuture { match self.as_mut().future().poll(cx) { Poll::Ready(v) => Poll::Ready(Ok(v)), Poll::Pending => match self.delay().poll(cx) { - Poll::Ready(_) => Poll::Ready(Err(TimeoutError)), + Poll::Ready(_) => Poll::Ready(Err(TimeoutError { _priv: () })), Poll::Pending => Poll::Pending, }, } @@ -66,8 +65,11 @@ impl Future for TimeoutFuture { } /// An error returned when a future times out. +#[cfg_attr(feature = "docs", doc(cfg(unstable)))] #[derive(Clone, Copy, Debug, Eq, PartialEq)] -pub struct TimeoutError; +pub struct TimeoutError { + _priv: (), +} impl Error for TimeoutError {}