mod enumerate;
mod for_each;
mod from_concurrent_stream;
mod from_stream;
mod into_concurrent_stream;
mod limit;
mod map;
mod take;
mod try_for_each;
use core::future::Future;
use core::num::NonZeroUsize;
use core::pin::Pin;
use for_each::ForEachConsumer;
use try_for_each::TryForEachConsumer;
pub use enumerate::Enumerate;
pub use from_concurrent_stream::FromConcurrentStream;
pub use from_stream::FromStream;
pub use into_concurrent_stream::IntoConcurrentStream;
pub use limit::Limit;
pub use map::Map;
pub use take::Take;
#[allow(async_fn_in_trait)]
pub trait Consumer<Item, Fut>
where
Fut: Future<Output = Item>,
{
type Output;
async fn send(self: Pin<&mut Self>, fut: Fut) -> ConsumerState;
async fn progress(self: Pin<&mut Self>) -> ConsumerState;
async fn flush(self: Pin<&mut Self>) -> Self::Output;
}
#[allow(async_fn_in_trait)]
pub trait ConcurrentStream {
type Item;
type Future: Future<Output = Self::Item>;
async fn drive<C>(self, consumer: C) -> C::Output
where
C: Consumer<Self::Item, Self::Future>;
fn concurrency_limit(&self) -> Option<NonZeroUsize>;
fn size_hint(&self) -> (usize, Option<usize>) {
(0, None)
}
fn enumerate(self) -> Enumerate<Self>
where
Self: Sized,
{
Enumerate::new(self)
}
fn limit(self, limit: Option<NonZeroUsize>) -> Limit<Self>
where
Self: Sized,
{
Limit::new(self, limit)
}
fn take(self, limit: usize) -> Take<Self>
where
Self: Sized,
{
Take::new(self, limit)
}
fn map<F, FutB, B>(self, f: F) -> Map<Self, F, Self::Future, Self::Item, FutB, B>
where
Self: Sized,
F: Fn(Self::Item) -> FutB,
F: Clone,
FutB: Future<Output = B>,
{
Map::new(self, f)
}
async fn for_each<F, Fut>(self, f: F)
where
Self: Sized,
F: Fn(Self::Item) -> Fut,
F: Clone,
Fut: Future<Output = ()>,
{
let limit = self.concurrency_limit();
self.drive(ForEachConsumer::new(limit, f)).await
}
async fn try_for_each<F, Fut, E>(self, f: F) -> Result<(), E>
where
Self: Sized,
F: Fn(Self::Item) -> Fut,
F: Clone,
Fut: Future<Output = Result<(), E>>,
{
let limit = self.concurrency_limit();
self.drive(TryForEachConsumer::new(limit, f)).await
}
async fn collect<B>(self) -> B
where
B: FromConcurrentStream<Self::Item>,
Self: Sized,
{
B::from_concurrent_stream(self).await
}
}
#[derive(Debug)]
pub enum ConsumerState {
Break,
Continue,
Empty,
}
#[cfg(test)]
mod test {
use super::*;
use crate::prelude::*;
use futures_lite::prelude::*;
use futures_lite::stream;
#[test]
fn drain() {
futures_lite::future::block_on(async {
stream::repeat(1)
.take(5)
.co()
.map(|x| async move {
println!("{x:?}");
})
.for_each(|_| async {})
.await;
});
}
#[test]
fn for_each() {
futures_lite::future::block_on(async {
let s = stream::repeat(1).take(2);
s.co()
.limit(NonZeroUsize::new(3))
.for_each(|x| async move {
println!("{x:?}");
})
.await;
});
}
}