use std::future::Future;
use std::hash::Hash;
use std::time::Duration;
use futures::Stream;
use futures::StreamExt as _;
use rskit_errors::AppResult;
use crate::operators::{concurrent, rate, transform, windowing};
#[allow(async_fn_in_trait)]
pub trait RskitStreamExt: Stream + Sized + Send + 'static
where
Self::Item: Send + 'static,
{
fn rmap<O, F, Fut>(self, f: F) -> impl Stream<Item = AppResult<O>> + Send + 'static
where
O: Send + 'static,
F: FnMut(Self::Item) -> Fut + Send + 'static,
Fut: Future<Output = AppResult<O>> + Send + 'static,
{
self.then(f)
}
fn rflatmap<O, F, Fut, St>(self, f: F) -> impl Stream<Item = AppResult<O>> + Send + 'static
where
O: Send + 'static,
F: FnMut(Self::Item) -> Fut + Send + 'static,
Fut: Future<Output = AppResult<St>> + Send + 'static,
St: Stream<Item = AppResult<O>> + Send + Unpin + 'static,
{
self.then(f).flat_map(|result| match result {
Ok(s) => s.left_stream(),
Err(e) => futures::stream::once(futures::future::ready(Err(e))).right_stream(),
})
}
fn rfilter<F>(self, mut f: F) -> impl Stream<Item = Self::Item> + Send + 'static
where
F: FnMut(&Self::Item) -> bool + Send + 'static,
{
self.filter(move |item| {
let keep = f(item);
std::future::ready(keep)
})
}
fn rdistinct(self) -> impl Stream<Item = Self::Item> + Send + 'static
where
Self::Item: Clone + Eq + Hash,
{
transform::distinct(self)
}
fn rtap<F, Fut>(self, mut f: F) -> impl Stream<Item = Self::Item> + Send + 'static
where
F: FnMut(&Self::Item) -> Fut + Send + 'static,
Fut: Future<Output = ()> + Send + 'static,
{
self.then(move |item| {
let fut = f(&item);
async move {
fut.await;
item
}
})
}
fn rtake(self, n: usize) -> impl Stream<Item = Self::Item> + Send + 'static {
self.take(n)
}
fn rskip(self, n: usize) -> impl Stream<Item = Self::Item> + Send + 'static {
self.skip(n)
}
fn rpartition<F>(
self,
predicate: F,
) -> (
impl Stream<Item = Self::Item> + Send + 'static,
impl Stream<Item = Self::Item> + Send + 'static,
)
where
F: FnMut(&Self::Item) -> bool + Send + 'static,
{
transform::partition(self, predicate)
}
async fn rreduce<Acc, F>(self, init: Acc, mut f: F) -> Acc
where
Acc: Send + 'static,
F: FnMut(Acc, Self::Item) -> Acc + Send + 'static,
{
let mut acc = init;
let this = self;
tokio::pin!(this);
while let Some(item) = this.next().await {
acc = f(acc, item);
}
acc
}
fn rparallel<O, F, Fut>(
self,
concurrency: usize,
f: F,
) -> impl Stream<Item = AppResult<O>> + Send + 'static
where
O: Send + 'static,
F: Fn(Self::Item) -> Fut + Clone + Send + Sync + 'static,
Fut: Future<Output = AppResult<O>> + Send + 'static,
{
concurrent::parallel(self, concurrency, f)
}
fn rfan_out<O, F, Fut>(
self,
max_branches: usize,
fns: Vec<F>,
) -> impl Stream<Item = AppResult<Vec<O>>> + Send + 'static
where
O: Send + 'static,
Self::Item: Clone,
F: Fn(Self::Item) -> Fut + Clone + Send + Sync + 'static,
Fut: Future<Output = AppResult<O>> + Send + 'static,
{
concurrent::fan_out(self, max_branches, fns)
}
fn rtumbling_window(
self,
duration: Duration,
max_items: usize,
) -> impl Stream<Item = Vec<Self::Item>> + Send + 'static {
windowing::tumbling_window(self, duration, max_items)
}
fn rsliding_window(
self,
size: usize,
step: usize,
) -> impl Stream<Item = Vec<Self::Item>> + Send + 'static
where
Self::Item: Clone,
{
windowing::sliding_window(self, size, step)
}
fn rbatch(
self,
size: usize,
timeout: Duration,
) -> impl Stream<Item = Vec<Self::Item>> + Send + 'static {
windowing::batch(self, size, timeout)
}
fn rdebounce(self, delay: Duration) -> impl Stream<Item = Self::Item> + Send + 'static {
rate::debounce(self, delay)
}
fn rdebounce_batch(
self,
quiet: Duration,
max_items: usize,
) -> impl Stream<Item = Vec<Self::Item>> + Send + 'static {
rate::debounce_batch(self, quiet, max_items)
}
fn rthrottle(self, interval: Duration) -> impl Stream<Item = Self::Item> + Send + 'static {
rate::throttle(self, interval)
}
fn rmerge(
self,
other: impl Stream<Item = Self::Item> + Send + 'static,
) -> impl Stream<Item = Self::Item> + Send + 'static {
futures::stream::select(self, other)
}
}
impl<S> RskitStreamExt for S
where
S: Stream + Send + 'static,
S::Item: Send + 'static,
{
}