Skip to main content

async_iter_ext/
iter.rs

1use std::vec::IntoIter;
2
3use sync_iter::SyncIter;
4
5pub mod process_result;
6pub mod sync_iter;
7
8/// Trait for asynchronous iteration.
9///
10/// This trait is similar to the standard `Iterator` trait, but designed to work in asynchronous
11/// contexts where `next()` returns a `Future`. It provides core methods for driving async iteration,
12/// collecting results, and converting to a synchronous iterator.
13///
14/// Implementors must define `next_async`, which yields the next item wrapped in a `Future`.
15pub trait AsyncIterator {
16    /// The type of the elements being iterated over.
17    type Item;
18
19    /// Asynchronously returns the next item in the iterator.
20    ///
21    /// Returns `None` when iteration is finished.
22    ///
23    /// # Examples
24    ///
25    /// ```rust
26    /// use async_iter_ext::AsyncIterator;
27    ///
28    /// async fn iterate<I: AsyncIterator>(mut iter: I) {
29    ///     while let Some(item) = iter.next_async().await {
30    ///         // process item
31    ///     }
32    /// }
33    /// ```
34    fn next_async(&mut self) -> impl Future<Output = Option<Self::Item>>;
35
36    /// Converts this async iterator into a synchronous [`SyncIter`] using `async` collection.
37    ///
38    /// This method collects all remaining items into a `Vec` and returns a `SyncIter` over them.
39    ///
40    /// ---
41    ///
42    /// # Notes
43    ///
44    /// - This is useful when you want to move from an async context to sync processing.
45    ///
46    /// ---
47    ///
48    /// # Examples
49    ///
50    /// ```rust
51    /// use async_iter_ext::AsyncIterator;
52    ///
53    /// async fn convert<I: AsyncIterator>(iter: &mut I) {
54    ///     let sync = iter.sync_iter().await;
55    ///     for item in sync {
56    ///         // use item
57    ///     }
58    /// }
59    /// ```
60    fn sync_iter(&mut self) -> impl Future<Output = SyncIter<IntoIter<Self::Item>>>
61    where
62        Self: Sized,
63    {
64        async move { SyncIter::new(collect_into_vec(self).await.into_iter()) }
65    }
66
67    /// Provides a hint about the size of the remaining items.
68    ///
69    /// Returns a tuple where the first element is a lower bound and the second
70    /// is an optional upper bound.
71    ///
72    /// This is used to optimize certain operations such as preallocating capacity.
73    ///
74    /// Default implementation returns `(0, None)`.
75    fn async_size_hint(&self) -> (usize, Option<usize>) {
76        (0, None)
77    }
78
79    /// Collects all items of the async iterator into a container type.
80    ///
81    /// Works like the standard `Iterator::collect`, but in an async context.
82    ///
83    /// The target container must implement `FromIterator<Self::Item>`.
84    ///
85    /// ---
86    ///
87    /// # Examples
88    ///
89    /// ```rust
90    /// use async_iter_ext::AsyncIterator;
91    ///
92    /// async fn collect_items<I: AsyncIterator>(iter: I) -> Vec<I::Item> {
93    ///     iter.async_collect::<Vec<_>>().await
94    /// }
95    /// ```
96    fn async_collect<B>(mut self) -> impl Future<Output = B>
97    where
98        Self: Sized,
99        B: FromIterator<Self::Item>,
100    {
101        async move {
102            let items = collect_into_vec(&mut self).await;
103            B::from_iter(items)
104        }
105    }
106}
107
108/// Asynchronously collects all items from an [`AsyncIterator`] into a `Vec`.
109///
110/// Uses `async_size_hint` to optimize preallocation if the upper bound is known.
111async fn collect_into_vec<I>(iter: &mut I) -> Vec<I::Item>
112where
113    I: AsyncIterator,
114{
115    let mut items = vec![];
116
117    match iter.async_size_hint() {
118        (_, Some(upper_limit)) => {
119            for _ in 0..upper_limit {
120                if let Some(item) = iter.next_async().await {
121                    items.push(item);
122                }
123            }
124        }
125        _ => {
126            while let Some(item) = iter.next_async().await {
127                items.push(item);
128            }
129        }
130    }
131
132    items
133}
134
135/// Blanket implementation of [`AsyncIterator`] for all synchronous [`Iterator`] types.
136///
137/// This enables any standard iterator to be used as an async iterator by immediately
138/// returning the next item.
139impl<T> AsyncIterator for T
140where
141    T: Iterator + ?Sized,
142{
143    type Item = T::Item;
144
145    async fn next_async(&mut self) -> Option<Self::Item> {
146        self.next()
147    }
148
149    fn async_size_hint(&self) -> (usize, Option<usize>) {
150        self.size_hint()
151    }
152}