use std::collections::VecDeque;
use std::time::Duration;
use futures::{Stream, StreamExt as _};
use super::buffer::{take_window, window_capacity};
pub fn tumbling_window<S, T>(
stream: S,
duration: Duration,
max_items: usize,
) -> impl Stream<Item = Vec<T>> + Send + 'static
where
S: Stream<Item = T> + Send + 'static,
T: Send + 'static,
{
async_stream::stream! {
tokio::pin!(stream);
let (max_items, initial_capacity) = window_capacity(max_items);
let mut buf: Vec<T> = Vec::with_capacity(initial_capacity);
let mut deadline = tokio::time::Instant::now() + duration;
loop {
tokio::select! {
item = stream.next() => {
if let Some(v) = item {
buf.push(v);
if buf.len() >= max_items {
yield take_window(&mut buf, initial_capacity);
deadline = tokio::time::Instant::now() + duration;
}
} else {
if !buf.is_empty() {
yield take_window(&mut buf, initial_capacity);
}
break;
}
}
() = tokio::time::sleep_until(deadline) => {
if !buf.is_empty() {
yield take_window(&mut buf, initial_capacity);
}
deadline = tokio::time::Instant::now() + duration;
}
}
}
}
}
pub fn batch<S, T>(
stream: S,
size: usize,
timeout: Duration,
) -> impl Stream<Item = Vec<T>> + Send + 'static
where
S: Stream<Item = T> + Send + 'static,
T: Send + 'static,
{
async_stream::stream! {
tokio::pin!(stream);
let size = size.max(1);
let mut buf: Vec<T> = Vec::with_capacity(size);
let mut deadline: Option<tokio::time::Instant> = None;
loop {
tokio::select! {
item = stream.next() => {
if let Some(v) = item {
if buf.is_empty() {
deadline = Some(tokio::time::Instant::now() + timeout);
}
buf.push(v);
if buf.len() >= size {
deadline = None;
yield std::mem::take(&mut buf);
}
} else {
if !buf.is_empty() {
yield std::mem::take(&mut buf);
}
break;
}
}
() = async {
match deadline {
Some(d) => tokio::time::sleep_until(d).await,
None => std::future::pending::<()>().await,
}
} => {
deadline = None;
if !buf.is_empty() {
yield std::mem::take(&mut buf);
}
}
}
}
}
}
pub fn sliding_window<S, T>(
stream: S,
size: usize,
step: usize,
) -> impl Stream<Item = Vec<T>> + Send + 'static
where
S: Stream<Item = T> + Send + 'static,
T: Clone + Send + 'static,
{
async_stream::stream! {
tokio::pin!(stream);
let mut window = VecDeque::with_capacity(size.max(1));
let effective_step = step.max(1);
while let Some(item) = stream.next().await {
window.push_back(item);
while window.len() > size {
window.pop_front();
}
if size > 0 && window.len() == size {
yield window.iter().cloned().collect();
for _ in 0..effective_step.min(window.len()) {
window.pop_front();
}
}
}
}
}