hyper/common/
task.rs

1use std::task::{Context, Poll};
2#[cfg(feature = "client")]
3use std::task::{RawWaker, RawWakerVTable, Waker};
4
5/// A function to help "yield" a future, such that it is re-scheduled immediately.
6///
7/// Useful for spin counts, so a future doesn't hog too much time.
8pub(crate) fn yield_now(cx: &mut Context<'_>) -> Poll<std::convert::Infallible> {
9    cx.waker().wake_by_ref();
10    Poll::Pending
11}
12
13// TODO: replace with `std::task::Waker::noop()` once MSRV >= 1.85
14#[cfg(feature = "client")]
15fn noop_waker() -> Waker {
16    const NOOP_RAW_WAKER: RawWaker = RawWaker::new(std::ptr::null(), &NOOP_VTABLE);
17    const NOOP_VTABLE: RawWakerVTable = RawWakerVTable::new(
18        // `clone` returns the same noop waker again
19        |_: *const ()| NOOP_RAW_WAKER,
20        // `wake`, `wake_by_ref`, and `drop` do nothing
21        |_: *const ()| {},
22        |_: *const ()| {},
23        |_: *const ()| {},
24    );
25
26    // SAFETY: all functions in the vtable are safe to call, and Waker's safety does not require
27    // them to actually do anything.
28    unsafe { Waker::from_raw(NOOP_RAW_WAKER) }
29}
30
31/// Poll the future once and return `Some` if it is ready, else `None`.
32///
33/// If the future wasn't ready, it future likely can't be driven to completion any more: the polling
34/// uses a no-op waker, so knowledge of what the pending future was waiting for is lost.
35#[cfg(feature = "client")]
36pub(crate) fn now_or_never<F: std::future::Future>(fut: F) -> Option<F::Output> {
37    let waker = noop_waker();
38    let mut cx = Context::from_waker(&waker);
39    // TODO: replace with std::pin::pin! and drop pin-utils once MSRV >= 1.68
40    pin_utils::pin_mut!(fut);
41    match fut.poll(&mut cx) {
42        Poll::Ready(res) => Some(res),
43        Poll::Pending => None,
44    }
45}