use tokio::time::{sleep, Duration};
use tokio::sync::Mutex;
use std::sync::Arc;
pub struct Debouncer {
delay: Duration,
task: Arc<Mutex<Option<tokio::task::JoinHandle<()>>>>,
}
impl Debouncer {
pub fn new(delay: Duration) -> Self {
Debouncer {
delay,
task: Arc::new(Mutex::new(None)),
}
}
pub async fn call<F, Fut, R>(&self, f: F)
where
F: FnOnce() -> Fut + Send + 'static,
Fut: std::future::Future<Output = R> + Send + 'static,
{
let mut task = self.task.lock().await;
if let Some(handle) = task.take() {
handle.abort();
}
let delay = self.delay;
*task = Some(tokio::spawn(async move {
sleep(delay).await;
f().await;
}));
}
}
#[cfg(test)]
mod tests {
use std::sync::Arc;
use tokio::sync::Mutex;
use tokio::time::Duration;
use crate::Debouncer;
#[tokio::test]
async fn should_call_last_only_test() {
let debouncer = Debouncer::new(Duration::from_secs(1));
let counter = Arc::new(Mutex::new(0));
let counter_clone = Arc::clone(&counter);
debouncer.call(move || {
async move {
let mut num = counter_clone.lock().await;
*num += 1;
}
}).await;
let counter_clone = Arc::clone(&counter);
debouncer.call(move || {
async move {
let mut num = counter_clone.lock().await;
*num += 1;
}
}).await;
for _ in 0..5 {
let counter_clone = Arc::clone(&counter);
debouncer.call(move || {
async move {
let mut num = counter_clone.lock().await;
*num += 1;
}
}).await;
tokio::time::sleep(Duration::from_millis(200)).await;
}
tokio::time::sleep(Duration::from_secs(2)).await;
let final_value = *counter.lock().await;
assert_eq!(final_value, 1, "The final call should be executed once.");
}
#[tokio::test]
async fn should_call_all_if_duration_is_short_test() {
let debouncer = Debouncer::new(Duration::from_millis(100));
let counter = Arc::new(Mutex::new(0));
let counter_clone = Arc::clone(&counter);
debouncer.call(move || {
async move {
let mut num = counter_clone.lock().await;
*num += 1;
}
}).await;
let counter_clone = Arc::clone(&counter);
debouncer.call(move || {
async move {
let mut num = counter_clone.lock().await;
*num += 1;
}
}).await;
for _ in 0..5 {
let counter_clone = Arc::clone(&counter);
debouncer.call(move || {
async move {
let mut num = counter_clone.lock().await;
*num += 1;
}
}).await;
tokio::time::sleep(Duration::from_millis(200)).await;
}
tokio::time::sleep(Duration::from_secs(2)).await;
let final_value = *counter.lock().await;
assert_eq!(final_value, 5, "The final call should be executed every time.");
}
}