diff --git a/futures-util/src/async_await/mod.rs b/futures-util/src/async_await/mod.rs index fed0ca0361..9bffef1d7f 100644 --- a/futures-util/src/async_await/mod.rs +++ b/futures-util/src/async_await/mod.rs @@ -19,6 +19,10 @@ pub use self::poll::*; mod pending; pub use self::pending::*; +#[macro_use] +mod yield_now; +pub use self::yield_now::*; + // Primary export is a macro #[macro_use] mod join; diff --git a/futures-util/src/async_await/yield_now.rs b/futures-util/src/async_await/yield_now.rs new file mode 100644 index 0000000000..072e94baaa --- /dev/null +++ b/futures-util/src/async_await/yield_now.rs @@ -0,0 +1,70 @@ +use core::pin::Pin; + +use futures_core::future::Future; +use futures_core::task::{LocalWaker, Poll}; + +/// A macro which temporarily give up the CPU +/// +/// # What's the difference between yield_now!() and pending!()? +/// +/// When using the [`pending!()`](pending!), it must be ensured that [`wake`](std::task::Waker::wake) +/// is called somewhere when further progress can be made. +/// +/// `yield_now!()` just like [`std::thread::yield_now`](std::thread::yield_now), but it used for asynchronous programming. +/// +/// # Examples +/// +/// ``` +/// #![feature(await_macro, async_await, futures_api)] +/// +/// use futures::yield_now; +/// +/// # let mut count = 10usize; +/// # let mut is_ready = || { +/// # count -= 1; +/// # count == 0 +/// # }; +/// async { +/// loop { +/// if is_ready() { +/// // finish job +/// break; +/// } else { +/// // do something +/// yield_now!(); +/// } +/// } +/// }; +/// +/// ``` +/// +/// This macro is only usable inside of async functions, closures, and blocks. +#[macro_export] +macro_rules! yield_now { + () => { + await!($crate::async_await::yield_now()) + }; +} + +#[doc(hidden)] +pub fn yield_now() -> impl Future { + YieldNow { is_ready: false } +} + +#[allow(missing_debug_implementations)] +struct YieldNow { + is_ready: bool, +} + +impl Future for YieldNow { + type Output = (); + fn poll(mut self: Pin<&mut Self>, lw: &LocalWaker) -> Poll { + if self.is_ready { + Poll::Ready(()) + } else { + self.is_ready = true; + lw.wake(); + Poll::Pending + } + } +} diff --git a/futures/src/lib.rs b/futures/src/lib.rs index b46bbf29a6..2f2b023fc2 100644 --- a/futures/src/lib.rs +++ b/futures/src/lib.rs @@ -57,7 +57,7 @@ pub use futures_util::{ #[cfg(feature = "std")] pub use futures_util::{ // Async-await - join, try_join, pending, poll, + join, try_join, pending, yield_now, poll, }; #[cfg(feature = "std")]