1use std::{
7 future::Future,
8 pin::{pin, Pin},
9 task::{Context, Poll},
10};
11
12use futures::task;
13
14pub fn yield_once() -> YieldOnce {
19 YieldOnce::default()
20}
21
22#[derive(Default)]
24pub struct YieldOnce {
25 yielded: bool,
26}
27
28impl Future for YieldOnce {
29 type Output = ();
30
31 fn poll(mut self: Pin<&mut Self>, context: &mut Context) -> Poll<Self::Output> {
32 let mut this = self.as_mut();
33
34 if this.yielded {
35 Poll::Ready(())
36 } else {
37 this.yielded = true;
38 context.waker().wake_by_ref();
39 Poll::Pending
40 }
41 }
42}
43
44pub trait BlockingWait {
46 type Output;
48
49 fn blocking_wait(self) -> Self::Output;
53}
54
55impl<AnyFuture> BlockingWait for AnyFuture
56where
57 AnyFuture: Future,
58{
59 type Output = AnyFuture::Output;
60
61 fn blocking_wait(mut self) -> Self::Output {
62 let waker = task::noop_waker();
63 let mut task_context = Context::from_waker(&waker);
64 let mut future = pin!(self);
65
66 loop {
67 match future.as_mut().poll(&mut task_context) {
68 Poll::Pending => continue,
69 Poll::Ready(output) => return output,
70 }
71 }
72 }
73}
74
75#[cfg(test)]
77mod tests {
78 use std::task::{Context, Poll};
79
80 use futures::{future::poll_fn, task::noop_waker, FutureExt as _};
81
82 use super::{yield_once, BlockingWait};
83
84 #[test]
89 #[expect(clippy::bool_assert_comparison)]
90 fn yield_once_returns_pending_only_on_first_call() {
91 let mut future = yield_once();
92
93 let waker = noop_waker();
94 let mut context = Context::from_waker(&waker);
95
96 assert_eq!(future.yielded, false);
97 assert!(future.poll_unpin(&mut context).is_pending());
98 assert_eq!(future.yielded, true);
99 assert!(future.poll_unpin(&mut context).is_ready());
100 assert_eq!(future.yielded, true);
101 }
102
103 #[test]
105 fn blocking_wait_blocks_until_future_is_ready() {
106 let mut remaining_polls = 100;
107
108 let future = poll_fn(|_context| {
109 if remaining_polls == 0 {
110 Poll::Ready(())
111 } else {
112 remaining_polls -= 1;
113 Poll::Pending
114 }
115 });
116
117 future.blocking_wait();
118
119 assert_eq!(remaining_polls, 0);
120 }
121}