1 unstable release
0.1.0 | Jan 13, 2024 |
---|
#1401 in Asynchronous
67KB
2K
SLoC
Async Iter
This library offers an asynchronous version of the rust's Iterator
trait and utilities.
Quick Start
Add to Dependencies
Add async-iter to your dependencies:
cargo add asynciter
Entrance to Utilities
Then, import the basic traits:
use asynciter::{
// This offers standard api, just like the `std::iter::Iterator`
AsyncIterator,
// use `.aiter()` to convert a synchronous iterator
// into an asynchronous one
ToAsyncIterator,
// use `.into_aiter()` to convert a synchronous iterable object
// into an asynchronous iterator
IntoAsyncIterator,
}
Api Call Stack
All api names and restrictions are the same as the std ones.
You just need to change your .iter()
or .into_iter()
to .aiter()
or .into_aiter()
:
assert_eq!(
["Hello%", "World%", "!"]
.into_aiter()
.map(|s| s.to_ascii_lowercase())
.intersperse(" ".into())
.flat_map(|s| s.chars().filter(|s| s != &'%').collect::<Vec<_>>())
.collect::<String>()
.await,
"hello world !"
);
Asynchronous Alternative
If you want to use asynchronous functions inside your iterators,
api prefixed with a
will accept a function returning a Future
while works the same as synchronous ones:
async fn do_async(val: i32) -> String {
format!("Async! {val}")
}
(0..=10)
.aiter()
// `amap` accepts `FnMut(Item) -> Future<Output>`
.amap(do_async)
// `afor_each` accepts `FnMut(Item) -> Future<Output = ()>`
.afor_each(|s| async move {
println!("{s}");
})
.await;
Awaited Asynchronous Iterator
If you have an iterator which yields Future
s, use .awaited()
to
change them into an AsyncIterator
:
// impl Iterator<Output: Future<Output = i32>>
let sync_it = (0..10).map(|s| async move { s + 1 });
// impl AsyncIterator<Output = i32>
let async_it = sync_it.aiter().awaited();
Internal Implementation
All internal implementations can be found in the asynciter::iterimpl
module, and are exported publicly, but direct usage is not recommended.
Notes
For those api which accept FnXXX(&Self::Item) -> Future
, there's another
extra restriction. Since the Future
will be used later than the function
call, the reference might outlive the function call's lifetime, leading
to compiler failures. To keep code safe, the reference must be processed
and dropped outside of the Future
.
For example, the following code will not pass the compiler check:
(0..10)
.aiter()
.afilter(
|s| // Here we accept the reference
async move {
*s < 5 // And we use it here.
// The reference will live longer than the function,
// which is not safe.
}
)
Instead, we must use the following solution:
(0..10)
.map(|s| s.to_string())
.aiter()
.afilter(|s| {
let s = s.clone(); // Here we save the reference
// by cloning the value
async move {
// do something
false
}
})
.for_each(|_| {}).await;
License
This project is licensed under the MIT License or Apache V2.0 License.