Skip to main content

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}