about summary refs log tree commit diff
diff options
context:
space:
mode:
authorManish Goregaokar <manishsmail@gmail.com>2020-07-18 16:50:50 -0700
committerGitHub <noreply@github.com>2020-07-18 16:50:50 -0700
commit479c8ad17c6908bd792dcacb0a3e0b5503903cf4 (patch)
tree1b3a4b37d184000e04ca9da8b2d9d65cd91bf688
parent1fa54ad9680cc82e7301f8ed4e9b7402dfd6ce0e (diff)
parent18be370342c9b2a93f1d56b2b674bd2fbdcbb019 (diff)
downloadrust-479c8ad17c6908bd792dcacb0a3e0b5503903cf4.tar.gz
rust-479c8ad17c6908bd792dcacb0a3e0b5503903cf4.zip
Rollup merge of #70817 - yoshuawuyts:task-ready, r=dtolnay
Add core::task::ready! macro

This PR adds `ready!` as a top-level macro to `libcore` following the implementation of `futures_core::ready`, tracking issue https://github.com/rust-lang/rust/issues/70922. This macro is commonly used when implementing `Future`, `AsyncRead`, `AsyncWrite` and `Stream`. And being only 5 lines, it seems like a useful and straight forward addition to std.

## Example

```rust
use core::task::{Context, Poll};
use core::future::Future;
use core::pin::Pin;

async fn get_num() -> usize {
    42
}

pub fn do_poll(cx: &mut Context<'_>) -> Poll<()> {
    let mut f = get_num();
    let f = unsafe { Pin::new_unchecked(&mut f) };

    let num = ready!(f.poll(cx));
    // ... use num

    Poll::Ready(())
}
```

## Naming

In `async-std` we chose to nest the macro under the `task` module instead of having the macro at the top-level. This is a pattern that currently does not occur in std, mostly due to this not being possible prior to Rust 2018.

This PR proposes to add the `ready` macro as `core::ready`. But another option would be to introduce it as `core::task::ready` since it's really only useful when used in conjunction with `task::{Context, Poll}`.

## Implementation questions

I tried rendering the documentation locally but the macro didn't show up under `core`. I'm not sure if I quite got this right. I used the [`todo!` macro PR](https://github.com/rust-lang/rust/pull/56348/files) as a reference, and our approaches look similar.

## References

- [`futures::ready`](https://docs.rs/futures/0.3.4/futures/macro.ready.html)
- [`async_std::task::ready`](https://docs.rs/async-std/1.5.0/async_std/task/index.html)
- [`futures_core::ready`](https://docs.rs/futures-core/0.3.4/futures_core/macro.ready.html)
-rw-r--r--src/libcore/task/mod.rs4
-rw-r--r--src/libcore/task/ready.rs60
-rw-r--r--src/libstd/lib.rs1
3 files changed, 65 insertions, 0 deletions
diff --git a/src/libcore/task/mod.rs b/src/libcore/task/mod.rs
index 27760749c1d..3d6f4f5971a 100644
--- a/src/libcore/task/mod.rs
+++ b/src/libcore/task/mod.rs
@@ -9,3 +9,7 @@ pub use self::poll::Poll;
 mod wake;
 #[stable(feature = "futures_api", since = "1.36.0")]
 pub use self::wake::{Context, RawWaker, RawWakerVTable, Waker};
+
+mod ready;
+#[unstable(feature = "ready_macro", issue = "70922")]
+pub use ready::ready;
diff --git a/src/libcore/task/ready.rs b/src/libcore/task/ready.rs
new file mode 100644
index 00000000000..d4e733eb2bc
--- /dev/null
+++ b/src/libcore/task/ready.rs
@@ -0,0 +1,60 @@
+/// Extracts the successful type of a `Poll<T>`.
+///
+/// This macro bakes in propagation of `Pending` signals by returning early.
+///
+/// # Examples
+///
+/// ```
+/// #![feature(future_readiness_fns)]
+/// #![feature(ready_macro)]
+///
+/// use core::task::{ready, Context, Poll};
+/// use core::future::{self, Future};
+/// use core::pin::Pin;
+///
+/// pub fn do_poll(cx: &mut Context<'_>) -> Poll<()> {
+///     let mut fut = future::ready(42);
+///     let fut = Pin::new(&mut fut);
+///
+///     let num = ready!(fut.poll(cx));
+///     # drop(num);
+///     // ... use num
+///
+///     Poll::Ready(())
+/// }
+/// ```
+///
+/// The `ready!` call expands to:
+///
+/// ```
+/// # #![feature(future_readiness_fns)]
+/// # #![feature(ready_macro)]
+/// #
+/// # use core::task::{Context, Poll};
+/// # use core::future::{self, Future};
+/// # use core::pin::Pin;
+/// #
+/// # pub fn do_poll(cx: &mut Context<'_>) -> Poll<()> {
+///     # let mut fut = future::ready(42);
+///     # let fut = Pin::new(&mut fut);
+///     #
+/// let num = match fut.poll(cx) {
+///     Poll::Ready(t) => t,
+///     Poll::Pending => return Poll::Pending,
+/// };
+///     # drop(num);
+///     # // ... use num
+///     #
+///     # Poll::Ready(())
+/// # }
+/// ```
+#[unstable(feature = "ready_macro", issue = "70922")]
+#[rustc_macro_transparency = "semitransparent"]
+pub macro ready($e:expr) {
+    match $e {
+        $crate::task::Poll::Ready(t) => t,
+        $crate::task::Poll::Pending => {
+            return $crate::task::Poll::Pending;
+        }
+    }
+}
diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs
index 0397153098c..11b8f953be4 100644
--- a/src/libstd/lib.rs
+++ b/src/libstd/lib.rs
@@ -305,6 +305,7 @@
 #![feature(ptr_internals)]
 #![feature(raw)]
 #![feature(raw_ref_macros)]
+#![feature(ready_macro)]
 #![feature(renamed_spin_loop)]
 #![feature(rustc_attrs)]
 #![feature(rustc_private)]