use std::time::{Duration, Instant};
use uuid::Uuid;
#[derive(Debug, Clone)]
pub struct DebouncedPreloader {
delay: Duration,
pending: Option<(Uuid, Instant)>,
}
impl Default for DebouncedPreloader {
fn default() -> Self {
Self {
delay: Duration::from_millis(500),
pending: None,
}
}
}
impl DebouncedPreloader {
pub fn new(delay_ms: u64) -> Self {
Self {
delay: Duration::from_millis(delay_ms),
pending: None,
}
}
pub fn set_delay(&mut self, delay_ms: u64) {
self.delay = Duration::from_millis(delay_ms);
}
pub fn delay_ms(&self) -> u64 {
self.delay.as_millis() as u64
}
pub fn schedule(&mut self, comp_uuid: Uuid) {
let trigger_at = Instant::now() + self.delay;
self.pending = Some((comp_uuid, trigger_at));
log::trace!(
"DebouncedPreloader: scheduled preload for {} in {}ms",
comp_uuid,
self.delay.as_millis()
);
}
pub fn cancel(&mut self) {
if self.pending.is_some() {
log::trace!("DebouncedPreloader: cancelled pending preload");
}
self.pending = None;
}
pub fn tick(&mut self) -> Option<Uuid> {
let Some((uuid, trigger_at)) = self.pending else {
return None;
};
if Instant::now() >= trigger_at {
self.pending = None;
log::trace!("DebouncedPreloader: triggering preload for {}", uuid);
Some(uuid)
} else {
None
}
}
pub fn is_pending(&self) -> bool {
self.pending.is_some()
}
pub fn pending_comp(&self) -> Option<Uuid> {
self.pending.map(|(uuid, _)| uuid)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_immediate_no_trigger() {
let mut preloader = DebouncedPreloader::new(100);
let uuid = Uuid::new_v4();
preloader.schedule(uuid);
assert!(preloader.is_pending());
assert!(preloader.tick().is_none());
}
#[test]
fn test_trigger_after_delay() {
let mut preloader = DebouncedPreloader::new(10); let uuid = Uuid::new_v4();
preloader.schedule(uuid);
std::thread::sleep(Duration::from_millis(15));
assert_eq!(preloader.tick(), Some(uuid));
assert!(!preloader.is_pending());
}
#[test]
fn test_debounce_resets_timer() {
let mut preloader = DebouncedPreloader::new(50);
let uuid1 = Uuid::new_v4();
let uuid2 = Uuid::new_v4();
preloader.schedule(uuid1);
std::thread::sleep(Duration::from_millis(30));
preloader.schedule(uuid2);
assert!(preloader.tick().is_none());
assert_eq!(preloader.pending_comp(), Some(uuid2));
}
}