async_iter_ext/
lib.rs

1#![doc = include_str!("../README.md")]
2
3use combinator::{filter::AsyncFilter, map::AsyncMap};
4
5pub mod combinator;
6pub mod iter;
7mod option;
8mod result;
9
10pub use iter::AsyncIterator;
11pub use option::AsyncOptionTools;
12pub use result::AsyncResultTools;
13
14pub trait AsyncIterTools: AsyncIterator {
15  /// Calls an async closure on each element of an iterator
16  ///
17  /// This is equivalent to using a for loop on the iterator, although break and continue are not possible from a closure.
18  ///
19  /// ---
20  ///
21  /// # Examples
22  ///
23  /// Basic usage:
24  ///
25  /// ```rust
26  /// use std::time::Duration;
27  ///
28  /// use async_iter_ext::AsyncIterTools;
29  /// use async_std::task;
30  ///
31  /// task::block_on(async {
32  ///   let items = [1, 2, 3, 4];
33  ///   items
34  ///     .iter()
35  ///     .for_each_async(|item| {
36  ///       async move {
37  ///         // Simulate some async work
38  ///         task::sleep(Duration::from_millis(100)).await;
39  ///         println!("Processing {}", item);
40  ///       }
41  ///     })
42  ///     .await;
43  /// });
44  /// ```
45  fn for_each_async<F, Fut>(mut self, f: F) -> impl Future<Output = ()>
46  where
47    Self: Sized,
48    F: Fn(Self::Item) -> Fut,
49    Fut: Future<Output = ()>,
50  {
51    async move {
52      while let Some(item) = self.next_async().await {
53        f(item).await;
54      }
55    }
56  }
57
58  /// Applies an async closure to each item of the iterator, returning a new iterator
59  /// of the results of each async computation.
60  ///
61  /// This is similar to the standard `Iterator::map` method, but works with asynchronous
62  /// closures that return `Future`s.
63  ///
64  /// ---
65  ///
66  /// # Examples
67  ///
68  /// ```rust
69  /// use std::time::Duration;
70  ///
71  /// use async_iter_ext::{AsyncIterTools, AsyncIterator};
72  /// use async_std::task;
73  ///
74  /// let multiplied_by_two = task::block_on(async {
75  ///   let items = [1, 2, 3, 4];
76  ///   items
77  ///     .iter()
78  ///     .map_async(|item| {
79  ///       async move {
80  ///         // Simulate async transformation
81  ///         task::sleep(Duration::from_millis(100)).await;
82  ///         item * 2
83  ///       }
84  ///     })
85  ///     .async_collect::<Vec<_>>()
86  ///     .await
87  /// });
88  /// ```
89  fn map_async<B, F, Fut>(self, f: F) -> AsyncMap<Self, F>
90  where
91    Self: Sized,
92    F: Fn(Self::Item) -> Fut,
93    Fut: Future<Output = B>,
94  {
95    AsyncMap { iter: self, f }
96  }
97
98  /// Filters the items of an iterator using an asynchronous predicate.
99  ///
100  /// This works like the standard `Iterator::filter`, but allows the predicate
101  /// to be asynchronous by returning a `Future<Output = bool>`.
102  ///
103  /// ---
104  ///
105  /// > ⚠️ Warning: The item type must implement `Clone` because filtering requires that the item is cloned when the predicate is run.
106  ///
107  /// ---
108  ///
109  /// # Examples
110  ///
111  /// ```rust
112  /// use async_iter_ext::{AsyncIterTools, AsyncIterator};
113  /// use async_std::task;
114  ///
115  /// task::block_on(async {
116  ///   let items = [1, 2, 3, 4, 5, 6];
117  ///   let filtered = items
118  ///     .iter()
119  ///     .filter_async(|item| {
120  ///       async move {
121  ///         // Keep even numbers only
122  ///         item % 2 == 0
123  ///       }
124  ///     })
125  ///     .async_collect::<Vec<_>>();
126  /// });
127  /// ```
128  fn filter_async<F, Fut>(self, f: F) -> AsyncFilter<Self, F>
129  where
130    Self: Sized,
131    F: Fn(Self::Item) -> Fut,
132    Fut: Future<Output = bool>,
133    Self::Item: Clone,
134  {
135    AsyncFilter { iter: self, f }
136  }
137}
138
139impl<T> AsyncIterTools for T where T: AsyncIterator + ?Sized {}