async-foundation 0.2.1

Foundational async primitives for Rust - timers, networking, and common utilities
Documentation
use crate::timer::timer_future::{TimerFuture, TimerFutureStateSafe};
use std::time::Instant;

pub struct TimerState {
    pub queue: Vec<TimerFutureStateSafe>,
}

impl TimerState {
    pub fn new() -> TimerState {
        TimerState { queue: Vec::new() }
    }

    pub fn add_to_queue(&mut self, expiration: Instant) -> (TimerFuture, bool) {
        let index = self.get_new_index_by_expiration(expiration);
        let shortest = index == self.queue.len();

        // eprintln!("add {:?} index={} shortest={} elapsed {:?}", expiration, index, shortest, elapsed);
        let time_future = TimerFuture::new(expiration);
        self.queue.insert(index, time_future.clone_state());
        (time_future, shortest)
    }

    fn get_new_index_by_expiration(&self, expiration: Instant) -> usize {
        for i in (0..self.queue.len()).rev() {
            let state = self.queue[i].lock().unwrap();
            if state.expiration > expiration {
                return i + 1;
            }
        }
        0
    }
    pub fn current_expiration(&self) -> Option<Instant> {
        self.queue
            .last()
            .map(|timer| timer.lock().unwrap().expiration)
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use std::time::Duration;

    #[test]
    fn test_timer_state_new() {
        let state = TimerState::new();
        assert!(state.queue.is_empty());
    }

    #[test]
    fn test_add_to_queue_single() {
        let mut state = TimerState::new();
        let now = Instant::now();
        let expiration = now + Duration::from_secs(5);
        let (_future, shortest) = state.add_to_queue(expiration);
        assert_eq!(state.queue.len(), 1);
        assert!(shortest); 
        let queue_state = state.queue[0].lock().unwrap();
        assert_eq!(queue_state.expiration, expiration);
    }

    #[test]
    fn test_current_expiration_empty() {
        let state = TimerState::new();
        assert!(state.current_expiration().is_none());
    }

    #[test]
    fn test_current_expiration_single() {
        let mut state = TimerState::new();
        let now = Instant::now();
        let expiration = now + Duration::from_secs(5);
        
        state.add_to_queue(expiration);
        
        let current = state.current_expiration();
        assert!(current.is_some());
        assert_eq!(current.unwrap(), expiration);
    }

    #[test]
    fn test_current_expiration_multiple() {
        let mut state = TimerState::new();
        let now = Instant::now();
        
        let exp1 = now + Duration::from_secs(10);
        let exp2 = now + Duration::from_secs(5);
        let exp3 = now + Duration::from_secs(1);
        
        state.add_to_queue(exp1);
        state.add_to_queue(exp2);
        state.add_to_queue(exp3);
        
        // Current expiration should be the longest (last in queue)
        let current = state.current_expiration();
        assert!(current.is_some());
        assert_eq!(current.unwrap(), exp3);
    }

    #[test]
    fn test_get_new_index_by_expiration() {
        let mut state = TimerState::new();
        let now = Instant::now();
        
        state.add_to_queue(now + Duration::from_secs(5));
        state.add_to_queue(now + Duration::from_secs(10));
        state.add_to_queue(now + Duration::from_secs(15));
        
        let new_exp = now + Duration::from_secs(1);
        let index = state.get_new_index_by_expiration(new_exp);
        assert_eq!(index, 3);
        
        let new_exp = now + Duration::from_secs(7);
        let index = state.get_new_index_by_expiration(new_exp);
        assert_eq!(index, 2);
        
        let new_exp = now + Duration::from_secs(20);
        let index = state.get_new_index_by_expiration(new_exp);
        assert_eq!(index, 0);
    }

    #[test]
    fn test_shortest_detection() {
        let mut state = TimerState::new();
        let now = Instant::now();
        let (_, shortest1) = state.add_to_queue(now + Duration::from_secs(10));
        assert!(shortest1);
        let (_, shortest2) = state.add_to_queue(now + Duration::from_secs(5));
        assert!(shortest2);
        let (_, shortest3) = state.add_to_queue(now + Duration::from_secs(15));
        assert!(!shortest3);
    }
}