use std::collections::VecDeque;
use std::task::Waker;
use std::time::{Duration, Instant};
#[derive(Clone)]
pub struct TimerData {
wheel: Vec<VecDeque<(usize, Waker)>>,
current_tick: u64,
resolution: Duration,
size: usize,
next_timer_id: usize,
start_time: Instant,
}
impl TimerData {
pub fn new() -> Self {
let size = 1024; let resolution = Duration::from_millis(1); Self {
wheel: (0..size).map(|_| VecDeque::new()).collect(),
current_tick: 0,
resolution,
size,
next_timer_id: 0,
start_time: Instant::now(),
}
}
pub fn register_timer(&mut self, deadline: Instant, waker: Waker) {
let delay = deadline.saturating_duration_since(self.start_time);
let ticks = delay.as_millis() as u64 / self.resolution.as_millis() as u64;
let slot = ((self.current_tick + ticks) % self.size as u64) as usize;
let id = self.next_timer_id;
self.next_timer_id += 1;
self.wheel[slot].push_back((id, waker));
}
pub fn check_expired(&mut self) {
let now = Instant::now();
let elapsed = now.saturating_duration_since(self.start_time);
let target_tick = elapsed.as_millis() as u64 / self.resolution.as_millis() as u64;
while self.current_tick <= target_tick {
let slot = (self.current_tick % self.size as u64) as usize;
while let Some((_, waker)) = self.wheel[slot].pop_front() {
waker.wake();
}
self.current_tick += 1;
}
}
pub fn next_timeout(&self) -> Option<Duration> {
for i in 0..self.size {
let slot = ((self.current_tick + i as u64) % self.size as u64) as usize;
if !self.wheel[slot].is_empty() {
return Some(Duration::from_millis(
i as u64 * self.resolution.as_millis() as u64,
));
}
}
None
}
pub fn is_empty(&self) -> bool {
self.wheel.iter().all(|bucket| bucket.is_empty())
}
}
impl Default for TimerData {
fn default() -> Self {
Self::new()
}
}