yield_progress/
basic_yield.rs

1use core::fmt;
2use core::future::Future;
3use core::pin::Pin;
4use core::task::{Context, Poll};
5
6#[cfg(doc)]
7use super::YieldProgress;
8
9/// The minimum, executor-agnostic yield operation.
10/// **This may be unsuitable for some applications.**
11///
12/// This function is provided as a convenience for constructing a [`YieldProgress`] where no more
13/// specific yield implementation is required. It does not itself interact with the
14/// [`YieldProgress`] system.
15///
16/// # Caveat
17///
18/// This function implements yielding by returning a [`Future`] which will:
19///
20/// 1. The first time it is polled, immediately [wake] and return [`Poll::Pending`].
21/// 2. The second time it is polled, return [`Poll::Ready`].
22///
23/// This might be inadequate if the executor's scheduling policy:
24///
25/// * Distinguishes intentional yielding.
26///   For example, in Tokio 1.\*, you should use [`tokio::task::yield_now()`] instead.
27/// * Is not fair among tasks, so some amount of delay is required to successfully yield to other
28///   tasks.
29/// * Is not fair between tasks and something else.
30///   For example, if the executor is implemented inside some event loop but itself loops through
31///   Rust async tasks as long as any of the tasks have [woken][wake], then something additional is
32///   needed to yield to the higher level.
33///
34/// [wake]: core::task::Waker::wake()
35/// [`tokio::task::yield_now()`]: https://docs.rs/tokio/1/tokio/task/fn.yield_now.html
36pub fn basic_yield_now() -> impl Future<Output = ()> + fmt::Debug + Send {
37    BasicYieldNow { state: State::New }
38}
39
40#[derive(Debug)]
41struct BasicYieldNow {
42    state: State,
43}
44
45#[derive(Clone, Copy, Debug)]
46enum State {
47    New,
48    Ready,
49    Used,
50}
51impl Future for BasicYieldNow {
52    type Output = ();
53
54    fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
55        let state = &mut self.get_mut().state;
56        match *state {
57            State::New => {
58                *state = State::Ready;
59                cx.waker().wake_by_ref();
60                Poll::Pending
61            }
62            State::Ready => {
63                *state = State::Used;
64                Poll::Ready(())
65            }
66            State::Used => panic!("future polled after completion"),
67        }
68    }
69}