use std::sync::atomic::{AtomicU64, Ordering};
use std::time::{SystemTime, UNIX_EPOCH};
pub struct AdaptiveDebouncer {
last_event: AtomicU64,
window_ms: u64,
}
impl AdaptiveDebouncer {
pub fn new(window_ms: u64) -> Self {
Self {
last_event: AtomicU64::new(0),
window_ms,
}
}
pub fn should_process(&self) -> bool {
let now = SystemTime::now()
.duration_since(UNIX_EPOCH)
.unwrap()
.as_millis() as u64;
let last = self.last_event.load(Ordering::Relaxed);
if now.saturating_sub(last) >= self.window_ms {
self.last_event.store(now, Ordering::Relaxed);
true
} else {
false
}
}
pub fn window_ms(&self) -> u64 {
self.window_ms
}
pub fn reset(&self) {
self.last_event.store(0, Ordering::Relaxed);
}
}
impl Default for AdaptiveDebouncer {
fn default() -> Self {
Self::new(200)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_new() {
let debouncer = AdaptiveDebouncer::new(100);
assert_eq!(debouncer.window_ms(), 100);
}
#[test]
fn test_default() {
let debouncer = AdaptiveDebouncer::default();
assert_eq!(debouncer.window_ms(), 200);
}
#[test]
fn test_should_process_first_call() {
let debouncer = AdaptiveDebouncer::new(100);
assert!(debouncer.should_process());
}
#[test]
fn test_reset() {
let debouncer = AdaptiveDebouncer::new(1000);
let _ = debouncer.should_process();
assert!(!debouncer.should_process());
debouncer.reset();
assert!(debouncer.should_process());
}
}