diff options
| author | Matthias Krüger <matthias.krueger@famsik.de> | 2021-10-11 23:45:48 +0200 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2021-10-11 23:45:48 +0200 |
| commit | d3984e16bf04f8ff886247cbf684041ba623d6ab (patch) | |
| tree | eb817a52bc1a0e32928a75aea5d02e170ed5b303 | |
| parent | b80dd9e445e19fd82d305cd61cd266b0ee61bfee (diff) | |
| parent | a1e03fc563eaaab04b747cf8d3f1a0d8931e39fd (diff) | |
| download | rust-d3984e16bf04f8ff886247cbf684041ba623d6ab.tar.gz rust-d3984e16bf04f8ff886247cbf684041ba623d6ab.zip | |
Rollup merge of #89651 - ibraheemdev:poll-ready, r=dtolnay
Add `Poll::ready` and revert stabilization of `task::ready!` This PR adds an inherent `ready` method to `Poll` that can be used with the `?` operator as an alternative to the `task::ready!` macro: ```rust let val = ready!(fut.poll(cx)); let val = fut.poll(cx).ready()?; ``` I think this form is a nice, non-breaking middle ground between changing the `impl Try for Poll`, and adding a separate macro. It looks better than `ready!` in my opinion, and it composes well: ```rust let elem = ready!(fut.poll(cx)).pop().unwrap(); let elem = fut.poll(cx).ready()?.pop().unwrap(); ``` The planned stabilization of `ready!` in 1.56 has been reverted because I think this alternate approach is worth considering. r? rust-lang/libs
| -rw-r--r-- | RELEASES.md | 2 | ||||
| -rw-r--r-- | library/core/src/task/mod.rs | 4 | ||||
| -rw-r--r-- | library/core/src/task/poll.rs | 33 | ||||
| -rw-r--r-- | library/core/src/task/ready.rs | 62 |
4 files changed, 97 insertions, 4 deletions
diff --git a/RELEASES.md b/RELEASES.md index ef1377a4a32..269740c171c 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -64,7 +64,6 @@ Stabilised APIs - [`VecDeque::shrink_to`] - [`HashMap::shrink_to`] - [`HashSet::shrink_to`] -- [`task::ready!`] These APIs are now usable in const contexts: @@ -128,7 +127,6 @@ and related tools. [`VecDeque::shrink_to`]: https://doc.rust-lang.org/stable/std/collections/struct.VecDeque.html#method.shrink_to [`HashMap::shrink_to`]: https://doc.rust-lang.org/stable/std/collections/hash_map/struct.HashMap.html#method.shrink_to [`HashSet::shrink_to`]: https://doc.rust-lang.org/stable/std/collections/hash_set/struct.HashSet.html#method.shrink_to -[`task::ready!`]: https://doc.rust-lang.org/stable/std/task/macro.ready.html [`std::mem::transmute`]: https://doc.rust-lang.org/stable/std/mem/fn.transmute.html [`slice::first`]: https://doc.rust-lang.org/stable/std/primitive.slice.html#method.first [`slice::split_first`]: https://doc.rust-lang.org/stable/std/primitive.slice.html#method.split_first diff --git a/library/core/src/task/mod.rs b/library/core/src/task/mod.rs index 5f077f77bbc..71a67a2793a 100644 --- a/library/core/src/task/mod.rs +++ b/library/core/src/task/mod.rs @@ -11,5 +11,7 @@ mod wake; pub use self::wake::{Context, RawWaker, RawWakerVTable, Waker}; mod ready; -#[stable(feature = "ready_macro", since = "1.56.0")] +#[unstable(feature = "ready_macro", issue = "70922")] pub use ready::ready; +#[unstable(feature = "poll_ready", issue = "89780")] +pub use ready::Ready; diff --git a/library/core/src/task/poll.rs b/library/core/src/task/poll.rs index 57416aeb701..3e0b3e89758 100644 --- a/library/core/src/task/poll.rs +++ b/library/core/src/task/poll.rs @@ -3,6 +3,7 @@ use crate::convert; use crate::ops::{self, ControlFlow}; use crate::result::Result; +use crate::task::Ready; /// Indicates whether a value is available or if the current task has been /// scheduled to receive a wakeup instead. @@ -92,6 +93,38 @@ impl<T> Poll<T> { pub const fn is_pending(&self) -> bool { !self.is_ready() } + + /// Extracts the successful type of a [`Poll<T>`]. + /// + /// When combined with the `?` operator, this function will + /// propogate any [`Poll::Pending`] values to the caller, and + /// extract the `T` from [`Poll::Ready`]. + /// + /// # Examples + /// + /// ```rust + /// #![feature(poll_ready)] + /// + /// use std::task::{Context, Poll}; + /// use std::future::{self, Future}; + /// use std::pin::Pin; + /// + /// pub fn do_poll(cx: &mut Context<'_>) -> Poll<()> { + /// let mut fut = future::ready(42); + /// let fut = Pin::new(&mut fut); + /// + /// let num = fut.poll(cx).ready()?; + /// # drop(num); + /// // ... use num + /// + /// Poll::Ready(()) + /// } + /// ``` + #[inline] + #[unstable(feature = "poll_ready", issue = "89780")] + pub fn ready(self) -> Ready<T> { + Ready(self) + } } impl<T, E> Poll<Result<T, E>> { diff --git a/library/core/src/task/ready.rs b/library/core/src/task/ready.rs index 2834ca5fe22..174ca675460 100644 --- a/library/core/src/task/ready.rs +++ b/library/core/src/task/ready.rs @@ -1,3 +1,8 @@ +use core::convert; +use core::fmt; +use core::ops::{ControlFlow, FromResidual, Try}; +use core::task::Poll; + /// Extracts the successful type of a [`Poll<T>`]. /// /// This macro bakes in propagation of [`Pending`] signals by returning early. @@ -8,6 +13,8 @@ /// # Examples /// /// ``` +/// #![feature(ready_macro)] +/// /// use std::task::{ready, Context, Poll}; /// use std::future::{self, Future}; /// use std::pin::Pin; @@ -27,6 +34,7 @@ /// The `ready!` call expands to: /// /// ``` +/// # #![feature(ready_macro)] /// # use std::task::{Context, Poll}; /// # use std::future::{self, Future}; /// # use std::pin::Pin; @@ -45,7 +53,7 @@ /// # Poll::Ready(()) /// # } /// ``` -#[stable(feature = "ready_macro", since = "1.56.0")] +#[unstable(feature = "ready_macro", issue = "70922")] #[rustc_macro_transparency = "semitransparent"] pub macro ready($e:expr) { match $e { @@ -55,3 +63,55 @@ pub macro ready($e:expr) { } } } + +/// Extracts the successful type of a [`Poll<T>`]. +/// +/// See [`Poll::ready`] for details. +#[unstable(feature = "poll_ready", issue = "89780")] +pub struct Ready<T>(pub(crate) Poll<T>); + +#[unstable(feature = "poll_ready", issue = "89780")] +impl<T> Try for Ready<T> { + type Output = T; + type Residual = Ready<convert::Infallible>; + + #[inline] + fn from_output(output: Self::Output) -> Self { + Ready(Poll::Ready(output)) + } + + #[inline] + fn branch(self) -> ControlFlow<Self::Residual, Self::Output> { + match self.0 { + Poll::Ready(v) => ControlFlow::Continue(v), + Poll::Pending => ControlFlow::Break(Ready(Poll::Pending)), + } + } +} + +#[unstable(feature = "poll_ready", issue = "89780")] +impl<T> FromResidual for Ready<T> { + #[inline] + fn from_residual(residual: Ready<convert::Infallible>) -> Self { + match residual.0 { + Poll::Pending => Ready(Poll::Pending), + } + } +} + +#[unstable(feature = "poll_ready", issue = "89780")] +impl<T> FromResidual<Ready<convert::Infallible>> for Poll<T> { + #[inline] + fn from_residual(residual: Ready<convert::Infallible>) -> Self { + match residual.0 { + Poll::Pending => Poll::Pending, + } + } +} + +#[unstable(feature = "poll_ready", issue = "89780")] +impl<T> fmt::Debug for Ready<T> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_tuple("Ready").finish() + } +} |
