about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMatthias Krüger <matthias.krueger@famsik.de>2021-10-11 23:45:48 +0200
committerGitHub <noreply@github.com>2021-10-11 23:45:48 +0200
commitd3984e16bf04f8ff886247cbf684041ba623d6ab (patch)
treeeb817a52bc1a0e32928a75aea5d02e170ed5b303
parentb80dd9e445e19fd82d305cd61cd266b0ee61bfee (diff)
parenta1e03fc563eaaab04b747cf8d3f1a0d8931e39fd (diff)
downloadrust-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.md2
-rw-r--r--library/core/src/task/mod.rs4
-rw-r--r--library/core/src/task/poll.rs33
-rw-r--r--library/core/src/task/ready.rs62
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()
+    }
+}