Skip to content

Commit

Permalink
Rollup merge of rust-lang#89651 - ibraheemdev:poll-ready, r=dtolnay
Browse files Browse the repository at this point in the history
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
  • Loading branch information
matthiaskrgr authored Oct 11, 2021
2 parents 8ec0e28 + a1e03fc commit ab3df12
Show file tree
Hide file tree
Showing 4 changed files with 97 additions and 4 deletions.
2 changes: 0 additions & 2 deletions RELEASES.md
Original file line number Diff line number Diff line change
Expand Up @@ -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:

Expand Down Expand Up @@ -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
Expand Down
4 changes: 3 additions & 1 deletion library/core/src/task/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
33 changes: 33 additions & 0 deletions library/core/src/task/poll.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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>> {
Expand Down
62 changes: 61 additions & 1 deletion library/core/src/task/ready.rs
Original file line number Diff line number Diff line change
@@ -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.
Expand All @@ -8,6 +13,8 @@
/// # Examples
///
/// ```
/// #![feature(ready_macro)]
///
/// use std::task::{ready, Context, Poll};
/// use std::future::{self, Future};
/// use std::pin::Pin;
Expand All @@ -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;
Expand All @@ -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 {
Expand All @@ -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()
}
}

0 comments on commit ab3df12

Please sign in to comment.