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();
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);
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);
}
}