use super::relay::matching_channel;
use super::types::Receiver;
use std::time::Duration;
use tokio::time::{sleep_until, Instant};
impl<T> Receiver<T> {
pub fn debounce(self, duration: Duration) -> Receiver<T>
where
T: Send + 'static,
{
let (tx, rx) = matching_channel::<T, T>(&self.inner);
let mut receiver = self;
tokio::spawn(async move {
let mut deadline: Option<Instant> = None;
let mut pending_msg: Option<T> = None;
loop {
tokio::select! {
msg = receiver.recv() => {
match msg {
Some(new_msg) => {
pending_msg = Some(new_msg);
deadline = Some(Instant::now() + duration);
}
None => {
if let Some(msg_to_send) = pending_msg.take() {
let _ = tx.send(msg_to_send).await;
}
break;
}
}
}
_ = sleep_until(deadline.unwrap_or_else(Instant::now)), if deadline.is_some() => {
if let Some(msg_to_send) = pending_msg.take() {
if tx.send(msg_to_send).await.is_err() {
break;
}
}
deadline = None;
}
}
}
});
Receiver { inner: rx }
}
pub fn window(self, window_duration: Duration) -> Receiver<Vec<T>>
where
T: Send + 'static,
{
let (tx, rx) = matching_channel::<T, Vec<T>>(&self.inner);
let mut receiver = self;
tokio::spawn(async move {
let mut buffer: Vec<T> = Vec::new();
let mut interval = tokio::time::interval(window_duration);
interval.set_missed_tick_behavior(tokio::time::MissedTickBehavior::Skip);
loop {
tokio::select! {
msg = receiver.recv() => {
match msg {
Some(new_msg) => {
buffer.push(new_msg);
}
None => {
if !buffer.is_empty() {
let _ = tx.send(buffer).await;
}
break;
}
}
}
_ = interval.tick() => {
let batch = std::mem::take(&mut buffer);
if tx.send(batch).await.is_err() {
break;
}
}
}
}
});
Receiver { inner: rx }
}
}