lustre-executor 0.2.0

A blazingly fast, minimal async executor with pluggable ID generation and I/O support.
Documentation
//! Timer management with efficient O(1) hashed wheel timer.

use std::collections::VecDeque;
use std::task::Waker;
use std::time::{Duration, Instant};

/// O(1) hashed wheel timer for efficient timer management.
#[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; // 1024 slots
        let resolution = Duration::from_millis(1); // 1ms per slot
        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> {
        // Find the next non-empty slot
        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()
    }
}