drive_async_iterator/lib.rs
1//! - [GitHub repo](https://github.com/oconnor663/drive_async_iterator)
2//! - [rendered docs](https://jacko.io/docs/drive_async_iterator)
3//!
4//! > **HEADS UP:** This experimental library crate currently requires a [fork of
5//! > rustc](https://github.com/oconnor663/rust/pull/2) to build, because it depends on the
6//! > proposed `AsyncIterator::poll_progress` method.
7//!
8//! With the introduction of `AsyncIterator::poll_progress`, the `.next()` method on
9//! `Stream`/`StreamExt` is probably not going to work, because there's no way for it to fulfill
10//! the `poll_progress` contract. The most common use case of `.next()` can be replaced with a `for
11//! await` loop, but more complicated use cases are hard to translate. The `drive_next` function in
12//! this crate supports `.next()` in a `poll_progress`-compatible form, by taking ownership of an
13//! `AsyncIterator` and providing a handle with a `.next()` method. It calls `poll_progress`
14//! concurrently with its body when an `.await` other than `.next().await` is pending, so the new
15//! `AsyncIterator` contract is satisfied.
16//!
17//! A caller that previously used `Stream`/`StreamExt` this way...
18//!
19//! ```
20//! # #![feature(gen_blocks)]
21//! # #![feature(yield_expr)]
22//! # use std::pin::pin;
23//! # use futures::StreamExt;
24//! # async gen fn some_stream() -> i32 { yield 42; }
25//! # #[tokio::main]
26//! # async fn main() {
27//! let mut my_stream = pin!(some_stream());
28//! assert_eq!(my_stream.next().await, Some(42));
29//! assert_eq!(my_stream.next().await, None);
30//! # }
31//! ```
32//!
33//! ...can use `AsyncIterator` + `poll_progress` this way (note that `pin!` is gone):
34//!
35//! ```
36//! # #![feature(async_iterator)]
37//! # #![feature(gen_blocks)]
38//! # #![feature(yield_expr)]
39//! # use std::pin::pin;
40//! # async gen fn some_stream() -> i32 { yield 42; }
41//! # #[tokio::main]
42//! # async fn main() {
43//! use drive_async_iterator::drive_next;
44//!
45//! drive_next(some_stream(), async |my_stream| {
46//! assert_eq!(my_stream.next().await, Some(42));
47//! assert_eq!(my_stream.next().await, None);
48//! }).await;
49//! # }
50//! ```
51//!
52//! `drive_next` takes ownership of an `AsyncIterator` and provides a handle that has a `next`
53//! method (and a couple others, see below).
54//!
55//! ## Fixing deadlocks
56//!
57//! Besides helping with migration, `drive_next` solves a [class of
58//! deadlocks](https://jacko.io/snooze.html) that present-day `.next()` loops are vulnerable to. Or
59//! rather, `poll_progress` solves them, and `drive_next` wires `.next()` into `poll_progress`.
60//! Consider this example ([playground link][playground_deadlock]):
61//!
62//! [playground_deadlock]: <https://play.rust-lang.org/?version=stable&mode=debug&edition=2024&gist=734b2822e9de973dd68460d59a4458b2>
63//!
64//! ```no_run
65//! # use futures::StreamExt;
66//! # use futures::stream::FuturesUnordered;
67//! # use tokio::sync::Mutex;
68//! # use tokio::time::{Duration, sleep};
69//! // This function acquires a static `Mutex` and does a brief sleep,
70//! // simulating some sort of IO with a shared resource.
71//! async fn do_work() {
72//! static LOCK: Mutex<()> = Mutex::const_new(());
73//! let _guard = LOCK.lock().await;
74//! sleep(Duration::from_millis(10)).await;
75//! }
76//!
77//! # #[tokio::main]
78//! # async fn main() {
79//! let mut futures = FuturesUnordered::new();
80//! futures.push(do_work());
81//! futures.push(do_work());
82//! while let Some(_) = futures.next().await {
83//! do_work().await; // Deadlock!
84//! }
85//! # }
86//! ```
87//!
88//! That example deadlocks because one of the `do_work` futures in the [`FuturesUnordered`] is
89//! holding the `LOCK`, but it's not making progress. Using `drive_next` the same loop runs
90//! smoothly, because `FuturesUnordered` can poll its contents concurrently with the loop body:
91//!
92//! ```
93//! # #![feature(async_iterator)]
94//! # use drive_async_iterator::drive_next;
95//! # use futures::StreamExt;
96//! # use futures::stream::FuturesUnordered;
97//! # use tokio::sync::Mutex;
98//! # use tokio::time::{Duration, sleep};
99//! # // This function acquires a static `Mutex` and does a brief sleep,
100//! # // simulating some sort of IO with a shared resource.
101//! # async fn do_work() {
102//! # static LOCK: Mutex<()> = Mutex::const_new(());
103//! # let _guard = LOCK.lock().await;
104//! # sleep(Duration::from_millis(10)).await;
105//! # }
106//! # #[tokio::main]
107//! # async fn main() {
108//! let mut futures = FuturesUnordered::new();
109//! futures.push(do_work());
110//! futures.push(do_work());
111//! drive_next(futures, async |futures| {
112//! while let Some(_) = futures.next().await {
113//! do_work().await; // Not a deadlock!
114//! }
115//! }).await;
116//! # }
117//! ```
118//!
119//! ## More complicated cases
120//!
121//! The example above could work with a standard `for await` loop, so it doesn't necessarily need
122//! the `drive_next` helper. However, one of the powerful features of [`FuturesUnordered`] (and
123//! also for example [`StreamMap`]) is that you can add more work to it while it's running
124//! ([playground link][playground_select]):
125//!
126//! [playground_select]: https://play.rust-lang.org/?version=stable&mode=debug&edition=2024&gist=04a697f12b1db97a2731a2d0885fe607
127//!
128//! ```
129//! # use futures::StreamExt;
130//! # use futures::stream::FuturesUnordered;
131//! # use tokio::select;
132//! # async fn work() {}
133//! # async fn more_work() -> impl Future<Output = ()> {
134//! # work()
135//! # }
136//! # #[tokio::main]
137//! # async fn main() {
138//! let mut futures = FuturesUnordered::new();
139//! loop {
140//! select! {
141//! Some(_) = futures.next() => {
142//! // Do something with the result...
143//! }
144//! job = more_work() => futures.push(job),
145//! }
146//! # break // don't run this docs example forever
147//! }
148//! # }
149//! ```
150//!
151//! That example isn't going to work with `for await`, for two reasons:
152//!
153//! 1. We need access to `futures` in the loop body, but `for await` takes ownership of it.
154//! 2. When `FuturesUnordered` is empty, its `poll_next` method returns `Done`. But that makes `for
155//! await` and also `drive_next` drop it immediately. We need it to return `Pending` instead.
156//!
157//! For the first problem, the handle provided by `drive_next` supports the [`with_pin_mut`] and
158//! (for `Unpin` types) [`with_mut`] methods. For the second problem, this crate provides a
159//! [`NeverDone`] async iterator adapter. Putting those two things together, we can implement the
160//! example above while still calling `poll_progress` correctly under the hood:
161//!
162//! ```
163//! # #![feature(async_iterator)]
164//! # use drive_async_iterator::{NeverDone, drive_next};
165//! # use futures::stream::FuturesUnordered;
166//! # use tokio::select;
167//! # async fn work() {}
168//! # async fn more_work() -> impl Future<Output = ()> {
169//! # work()
170//! # }
171//! # #[tokio::main]
172//! # async fn main() {
173//! drive_next(NeverDone::new(FuturesUnordered::new()), async |futures| {
174//! loop {
175//! select! {
176//! Some(_) = futures.next() => {
177//! // Do something with the result...
178//! }
179//! job = more_work() => {
180//! futures.with_mut(|maybe_futures: Option<_>| {
181//! let futures = maybe_futures.expect("never dropped");
182//! futures.push(job);
183//! });
184//! }
185//! }
186//! # break // don't run this docs example forever
187//! }
188//! }).await;
189//! # }
190//! ```
191//!
192//! There's a tricky implementation detail here. `FuturesUnordered` doesn't trigger a wakeup when
193//! `push` takes it from empty to non-empty, and it also doesn't poll the future you pushed until
194//! you call `poll_next`. To make sure we keep looping and poll the new future, `drive_next`
195//! re-polls both its iterator and its body anytime `with_mut` or `with_pin_mut` is called. This is
196//! a bit of a hack, and it's possible it could cause accidental hot loops in some cases. It would
197//! be better if `FuturesUnordered` managed these wakeups internally, but that's not how it works
198//! today.
199//!
200//! Note also that calling `next` on a `NeverDone` async iterator will never return `None`.
201//! Instead, it'll block potentially forever waiting for the iterator to yield more items. That's
202//! different from the behavior of `FuturesUnordered::next` today, which returns `None` immediately
203//! in the empty case. The blocking behavior might avoid accidental hot loops in some cases, but it
204//! can also cause some existing callers to block forever unexpectedly.
205//!
206//! [`FuturesUnordered`]: https://docs.rs/futures/latest/futures/stream/struct.FuturesUnordered.html
207//! [`StreamMap`]: https://docs.rs/tokio-stream/latest/tokio_stream/struct.StreamMap.html
208//! [`with_pin_mut`]: DrivenAsyncIterator::with_pin_mut
209//! [`with_mut`]: DrivenAsyncIterator::with_mut
210
211#![no_std]
212#![feature(async_iterator)]
213
214use atomic_refcell::AtomicRefCell;
215use core::async_iter::{AsyncIterator, IntoAsyncIterator, PollNext};
216use core::pin::{Pin, pin};
217use core::task::{Context, Poll};
218
219/// Take ownership of an `AsyncIterator`, create a [`DrivenAsyncIterator`] handle for it, and call
220/// the user's closure with that handle as an argument. The handle has an async [`.next()`] method.
221///
222/// [`.next()`]: DrivenAsyncIterator::next
223pub async fn drive_next<Iter, Body, Output>(iter: Iter, body: Body) -> Output
224where
225 Iter: IntoAsyncIterator,
226 Body: AsyncFnOnce(DrivenAsyncIterator<'_, Iter::IntoAsyncIter>) -> Output,
227{
228 let state_pin = pin!(DriveState::new(iter.into_async_iter()));
229 let state_cell = AtomicRefCell::new(state_pin);
230 let driven_iter = new_driven_async_iterator(&state_cell);
231 let mut body_future = pin!(body(driven_iter));
232 let mut poll_next_future = pin!(async {
233 loop {
234 let mut state = state_cell.borrow_mut();
235 // If `next` is cancelled, `item` might not get taken immediately. In that case it
236 // might already be `Some`.
237 if *state.as_mut().next_item_wanted() && state.as_mut().item().is_none() {
238 // `DriveState` handles fusing and dropping `iterator` internally.
239 if let PollNext::Item(item) = state.as_mut().poll_next_once().await {
240 *state.as_mut().item() = Some(item);
241 *state.as_mut().next_item_wanted() = false;
242 // Now we're handing an item off to the body. We need to call `poll_progress`
243 // before this whole function yields, but we'd rather not call it now if the
244 // body is going to ask for another item immediately. Instead, we let the outer
245 // loop do it right before it finally yields.
246 }
247 }
248 // Don't want to keep the `state` borrowed across this yield.
249 drop(state);
250 pending_once().await;
251 }
252 });
253 loop {
254 // Polling the poll-next-future is a no-op once the iterator is done.
255 _ = poll_once(poll_next_future.as_mut()).await;
256 let body_poll = poll_once(body_future.as_mut()).await;
257 if let Poll::Ready(output) = body_poll {
258 return output;
259 }
260 let mut state = state_cell.borrow_mut();
261 if *state.as_mut().mutated_this_iteration() {
262 *state.as_mut().mutated_this_iteration() = false;
263 // If `with_mut` or `with_pin_mut` has been called and something is (maybe
264 // concurrently!) waiting on the next item, we need to loop again. The mutation
265 // might've e.g. added more work to a `FuturesUnordered`. In a perfect world
266 // `FuturesUnordered` would stash a `Waker` and trigger a wakeup itself in this
267 // case, the way a channel does, but it doesn't work that way today. This mechanism
268 // can't be perfect, because some pathological container might support both
269 // iteration and insertion via `Arc` without ever triggering any wakeups. At least
270 // `for await` would be equally vulnerable to that one.
271 if *state.as_mut().next_item_wanted() && state.as_mut().iterator().is_some() {
272 continue;
273 }
274 }
275 if !*state.as_mut().next_item_wanted() {
276 // The body is awaiting something other than `next`, possibly after some calls
277 // to `next` have yielded items. This is where we call `poll_progress`, so that
278 // in general we only call it once after a chain of ready items.
279 _ = state.as_mut().poll_progress_once().await;
280 }
281 // Either the iterator side is awaiting the next item, or the body side is awaiting
282 // something else, or both. They will wake us up.
283 //
284 // As above, don't keep `state` borrowed across this yield.
285 drop(state);
286 pending_once().await;
287 }
288}
289
290/// The `AsyncIterator` wrapper type that [`drive_next`] provides to its closure.
291pub struct DrivenAsyncIterator<'a, Iter: AsyncIterator> {
292 state: &'a AtomicRefCell<Pin<&'a mut DriveState<Iter>>>,
293}
294
295impl<Iter: AsyncIterator> DrivenAsyncIterator<'_, Iter> {
296 /// Get the next item from the async iterator.
297 ///
298 /// Note that this method takes `&self`, and multiple futures are allowed to call it
299 /// concurrently. However, if you manage to call `next` in _parallel_ from multiple _threads_,
300 /// it's likely to panic.
301 ///
302 /// Implementation details: `DrivenAsyncIterator` uses an [`AtomicRefCell`] internally, rather
303 /// than a [`Mutex`]. This makes it more efficient and also `no_std`-compatible. The downside
304 /// is panics when it's accessed from parallel threads, but this should be extremely unlikely
305 /// in practice. `DrivenAsyncIterator` has a local lifetime bound, so it can't be given to
306 /// [`task::spawn`] or [`thread::spawn`]. Scoped tasks also [don't currently exist][trilemma].
307 /// To trigger this panic, you'd have to use something like [`thread::scope`] in an async
308 /// context, which would be unusual and potentially an executor-blocking bug in any case.
309 ///
310 /// Note also that if this method is cancelled, `drive_next` will continue fetching the next
311 /// item from the async iterator in the background. This is necessary to satisfy the
312 /// `AsyncIterator` contract. Once you start fetching the next item, the only way to fully
313 /// cancel the fetch is to return from the `drive_next` closure or cancel `drive_next` itself.
314 ///
315 /// [`AtomicRefCell`]: https://docs.rs/atomic_refcell/latest/atomic_refcell/struct.AtomicRefCell.html
316 /// [`Mutex`]: https://docs.rs/tokio/latest/tokio/sync/struct.Mutex.html
317 /// [`task::spawn`]: https://docs.rs/tokio/latest/tokio/task/fn.spawn.html
318 /// [`thread::spawn`]: https://doc.rust-lang.org/std/thread/fn.spawn.html
319 /// [`thread::scope`]: https://doc.rust-lang.org/std/thread/fn.scope.html
320 /// [trilemma]: https://without.boats/blog/the-scoped-task-trilemma/
321 pub async fn next(&self) -> Option<Iter::Item> {
322 loop {
323 let mut state = self.state.borrow_mut();
324 if let Some(item) = state.as_mut().item().take() {
325 return Some(item);
326 }
327 if state.as_mut().iterator().is_none() {
328 return None;
329 }
330 // NOTE: `next_item_wanted` might already be true if there are concurrent calls to
331 // `next`, or if a previous call was cancelled. That's fine. If a concurrent call beats
332 // us to the item, it'll clear `next_item_wanted`, and then we'll restore it.
333 if !*state.as_mut().next_item_wanted() {
334 // There's no buffered item, and the iterator isn't already in a `poll_next` loop.
335 // Try calling `poll_next` ourselves. This is a fake await (just for `Context`),
336 // which is guaranteed to be ready immediately.
337 match state.as_mut().poll_next_once().await {
338 // If we get an item, we can just return it. That'll leave `next_item_wanted`
339 // false, and the outer loop will do a `poll_progress` for us.
340 PollNext::Item(item) => return Some(item),
341 // `DriveState` handles fusing and dropping `iterator` internally.
342 PollNext::Done => return None,
343 PollNext::Pending => {}
344 }
345 // `poll_next` has returned `Pending`, and the `AsyncIterator` contract says we
346 // need to keep calling `poll_next` until it yields an item. However, it's not
347 // enough to do that within this function, because this function could be
348 // cancelled. (If this function *owned* the iterator, then cancelling it would drop
349 // the iterator, and the contract would be satisfied.) We need to set
350 // `next_item_wanted` and trust the poll-next-future to take care of this for us.
351 *state.as_mut().next_item_wanted() = true;
352 }
353 // Yield without arranging our own wakeup, trusting the poll-next-future to make
354 // progress for us. Don't keep `state` borrowed across this.
355 drop(state);
356 pending_once().await;
357 }
358 }
359
360 /// Get a temporary pinned reference to the driven async iterator, if it's not yet done.
361 ///
362 /// `drive_next` drops its iterator as soon as `poll_next` returns `Done`. If `with_pin_mut` is
363 /// called after that, the closure will receive `None`.
364 ///
365 /// The closure argument is not async, because this reference can't be held across `.await`
366 /// points. If you try to call this reentrantly, it will panic.
367 ///
368 /// Whenever you call this method, `drive_next` will immediately re-poll the iterator, in case
369 /// it's something like `FuturesUnordered` and you just added more work to it. This is kind of
370 /// a hack, and it would be better if collections like `FuturesUnordered` handled their own
371 /// wakeups in these cases, but that's not how things work today.
372 pub fn with_pin_mut<F, Ret>(&self, f: F) -> Ret
373 where
374 F: FnOnce(Option<Pin<&mut Iter>>) -> Ret,
375 {
376 let mut state = self.state.borrow_mut();
377 *state.as_mut().mutated_this_iteration() = true;
378 f(state.as_mut().iterator().as_pin_mut())
379 }
380
381 /// Get a temporary mutable reference to the driven async iterator, if it's not yet done.
382 ///
383 /// This works like [`with_pin_mut`](DrivenAsyncIterator::with_pin_mut), except that it
384 /// requires the iterator to be [`Unpin`].
385 pub fn with_mut<F, Ret>(&self, f: F) -> Ret
386 where
387 F: FnOnce(Option<&mut Iter>) -> Ret,
388 Iter: Unpin,
389 {
390 let mut state = self.state.borrow_mut();
391 *state.as_mut().mutated_this_iteration() = true;
392 f(state.as_mut().iterator().get_mut().as_mut())
393 }
394}
395
396impl<Iter: AsyncIterator> core::fmt::Debug for DrivenAsyncIterator<'_, Iter> {
397 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
398 f.debug_struct("DrivenAsyncIterator").finish()
399 }
400}
401
402pin_project_lite::pin_project! {
403 /// An `AsyncIterator` wrapper that never returns `Done`
404 ///
405 /// An `AsyncIterator` caller is generally supposed to drop the iterator promptly after
406 /// `poll_next` returns `Done`. `for await` loops do this, and `drive_next` also does this,
407 /// without waiting for its body to finish. But some async iterators, for example
408 /// [`FuturesUnordered`] and [`StreamMap`], work differently. These allow their caller to add
409 /// work to them at any time. If they run out of work, their `poll_next` methods return `Done`,
410 /// but they can return `Some` again later if more work is added again. This doesn't play well
411 /// with `for await` or `drive_next`, because they'll drop the iterator the first time they see
412 /// `Done`. (`for await` also makes it hard to add work during the loop, because it has no
413 /// equivalent of [`with_pin_mut`] or [`with_mut`]).
414 ///
415 /// `NeverDone` is a workaround for this problem. It's a thin `AsyncIterator` wrapper that
416 /// never returns `Done`. When the inner iterator would return `Done`, `NeverDone` returns
417 /// `Pending` instead. This means that the inner iterator's `poll_next` method might get called
418 /// again after returning `Done`, which isn't generally allowed, and which will cause some
419 /// iterators to panic. It's the caller's responsibility to only use `NeverDone` with async
420 /// iterators that allow this.
421 ///
422 /// See the example in the [module level docs](crate#more-complicated-cases).
423 ///
424 /// [`FuturesUnordered`]: https://docs.rs/futures/latest/futures/stream/struct.FuturesUnordered.html
425 /// [`StreamMap`]: https://docs.rs/tokio-stream/latest/tokio_stream/struct.StreamMap.html
426 /// [`with_pin_mut`]: DrivenAsyncIterator::with_pin_mut
427 /// [`with_mut`]: DrivenAsyncIterator::with_mut
428 #[derive(Debug)]
429 pub struct NeverDone<Iter> {
430 #[pin]
431 iter: Iter,
432 }
433}
434
435impl<Iter> NeverDone<Iter> {
436 /// Wrap an `AsyncIterator` with `NeverDone`.
437 pub fn new(iter: Iter) -> Self {
438 Self { iter }
439 }
440
441 /// Consume the `NeverDone` and return the inner `AsyncIterator`.
442 pub fn into_inner(self) -> Iter {
443 self.iter
444 }
445
446 /// Return a pinned reference to the inner `AsyncIterator`.
447 pub fn as_pin_mut(self: Pin<&mut Self>) -> Pin<&mut Iter> {
448 self.project().iter
449 }
450}
451
452impl<Iter> core::ops::Deref for NeverDone<Iter> {
453 type Target = Iter;
454
455 fn deref(&self) -> &Iter {
456 &self.iter
457 }
458}
459
460impl<Iter> core::ops::DerefMut for NeverDone<Iter> {
461 fn deref_mut(&mut self) -> &mut Iter {
462 &mut self.iter
463 }
464}
465
466impl<Iter: AsyncIterator> AsyncIterator for NeverDone<Iter> {
467 type Item = Iter::Item;
468
469 fn poll_next(self: Pin<&mut Self>, cx: &mut Context) -> PollNext<Self::Item> {
470 match self.project().iter.poll_next(cx) {
471 PollNext::Done => PollNext::Pending,
472 other => other,
473 }
474 }
475
476 fn poll_progress(self: Pin<&mut Self>, cx: &mut Context) -> Poll<()> {
477 self.project().iter.poll_progress(cx)
478 }
479}
480
481fn new_driven_async_iterator<'a, Iter: AsyncIterator>(
482 state: &'a AtomicRefCell<Pin<&'a mut DriveState<Iter>>>,
483) -> DrivenAsyncIterator<'a, Iter> {
484 DrivenAsyncIterator { state }
485}
486
487pin_project_lite::pin_project! {
488 struct DriveState<Iter: AsyncIterator> {
489 #[pin]
490 iterator: Option<Iter>,
491 item: Option<Iter::Item>,
492 next_item_wanted: bool,
493 mutated_this_iteration: bool,
494 }
495}
496
497impl<Iter: AsyncIterator> DriveState<Iter> {
498 fn new(iter: Iter) -> Self {
499 Self {
500 iterator: Some(iter),
501 item: None,
502 next_item_wanted: false,
503 mutated_this_iteration: false,
504 }
505 }
506
507 fn iterator(self: Pin<&mut Self>) -> Pin<&mut Option<Iter>> {
508 self.project().iterator
509 }
510
511 fn item(self: Pin<&mut Self>) -> &mut Option<Iter::Item> {
512 self.project().item
513 }
514
515 fn next_item_wanted(self: Pin<&mut Self>) -> &mut bool {
516 self.project().next_item_wanted
517 }
518
519 fn mutated_this_iteration(self: Pin<&mut Self>) -> &mut bool {
520 self.project().mutated_this_iteration
521 }
522
523 /// This drops `iterator` the first time it returns `Done`, and it keeps returning `Done`
524 /// after that. (In other words, the iterator is effectively "fused".)
525 async fn poll_next_once(mut self: Pin<&mut Self>) -> PollNext<Iter::Item> {
526 struct PollNextOnce<'a, Iter>(Pin<&'a mut Iter>);
527 impl<Iter: AsyncIterator> Future for PollNextOnce<'_, Iter> {
528 type Output = PollNext<Iter::Item>;
529 fn poll(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output> {
530 Poll::Ready(self.0.as_mut().poll_next(cx))
531 }
532 }
533 if let Some(iter) = self.as_mut().iterator().as_pin_mut() {
534 let poll_next = PollNextOnce(iter).await;
535 if let PollNext::Done = poll_next {
536 self.as_mut().iterator().set(None);
537 }
538 poll_next
539 } else {
540 PollNext::Done
541 }
542 }
543
544 /// If `iterator` has returned `Done` and been dropped, then this returns `Ready(())`.
545 async fn poll_progress_once(self: Pin<&mut Self>) -> Poll<()> {
546 struct PollProgressOnce<'a, Iter>(Pin<&'a mut Iter>);
547 impl<Iter: AsyncIterator> Future for PollProgressOnce<'_, Iter> {
548 type Output = Poll<()>;
549 fn poll(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output> {
550 Poll::Ready(self.0.as_mut().poll_progress(cx))
551 }
552 }
553 if let Some(iter) = self.iterator().as_pin_mut() {
554 PollProgressOnce(iter).await
555 } else {
556 Poll::Ready(())
557 }
558 }
559}
560
561#[inline]
562fn pending_once() -> PendingOnce {
563 PendingOnce { yielded: false }
564}
565
566struct PendingOnce {
567 yielded: bool,
568}
569
570impl Future for PendingOnce {
571 type Output = ();
572
573 #[inline]
574 fn poll(mut self: Pin<&mut Self>, _: &mut Context) -> Poll<()> {
575 if self.yielded {
576 Poll::Ready(())
577 } else {
578 self.yielded = true;
579 Poll::Pending
580 }
581 }
582}
583
584#[inline]
585fn poll_once<Fut>(fut: Pin<&mut Fut>) -> PollOnce<'_, Fut> {
586 PollOnce(fut)
587}
588
589struct PollOnce<'a, Fut>(Pin<&'a mut Fut>);
590
591impl<Fut: Future> Future for PollOnce<'_, Fut> {
592 type Output = Poll<Fut::Output>;
593
594 #[inline]
595 fn poll(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output> {
596 Poll::Ready(self.0.as_mut().poll(cx))
597 }
598}