1use std::pin::Pin;
8
9use futures::future::FusedFuture;
10use futures::{task, Future};
11
12#[derive(Default)]
30pub struct YieldToExecutorOnce(YieldToExecutorOnceInner);
31
32#[derive(Default)]
33enum YieldToExecutorOnceInner {
34 #[default]
35 NotPolled,
36 Ready,
37 Terminated,
38}
39
40impl YieldToExecutorOnce {
41 pub fn new() -> Self {
43 Self::default()
44 }
45}
46
47impl Future for YieldToExecutorOnce {
48 type Output = ();
49
50 fn poll(self: Pin<&mut Self>, cx: &mut task::Context<'_>) -> task::Poll<Self::Output> {
51 let Self(inner) = self.get_mut();
52 match *inner {
53 YieldToExecutorOnceInner::NotPolled => {
54 *inner = YieldToExecutorOnceInner::Ready;
55 cx.waker().wake_by_ref();
58 task::Poll::Pending
59 }
60 YieldToExecutorOnceInner::Ready => {
61 *inner = YieldToExecutorOnceInner::Terminated;
62 task::Poll::Ready(())
63 }
64 YieldToExecutorOnceInner::Terminated => {
65 panic!("polled future after completion");
66 }
67 }
68 }
69}
70
71impl FusedFuture for YieldToExecutorOnce {
72 fn is_terminated(&self) -> bool {
73 let Self(inner) = self;
74 match inner {
75 YieldToExecutorOnceInner::Ready | YieldToExecutorOnceInner::NotPolled => false,
76 YieldToExecutorOnceInner::Terminated => true,
77 }
78 }
79}
80
81#[cfg(test)]
82mod tests {
83 #[test]
84 fn yield_to_executor_once() {
85 use futures::future::FusedFuture as _;
86 use futures::FutureExt as _;
87
88 let (waker, count) = futures_test::task::new_count_waker();
89 let mut context = std::task::Context::from_waker(&waker);
90 let mut fut = super::YieldToExecutorOnce::new();
91
92 assert!(!fut.is_terminated());
93 assert_eq!(count, 0);
94 assert_eq!(fut.poll_unpin(&mut context), std::task::Poll::Pending);
95 assert!(!fut.is_terminated());
96 assert_eq!(count, 1);
97 assert_eq!(fut.poll_unpin(&mut context), std::task::Poll::Ready(()));
98 assert!(fut.is_terminated());
99 assert_eq!(count, 1);
101 }
102}