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 {}