use mio::Token;
use std::time::Instant;
use crate::net::TokenTimeout;
pub struct Timeouts {
pub(crate) queue: Vec<TokenTimeout>,
}
impl Timeouts {
pub fn new() -> Timeouts {
Timeouts { queue: Vec::new() }
}
pub fn add(&mut self, token: Token, instant: Instant) {
let index = self
.get_index_by(|item| item.timeout > instant)
.map(|index| index + 1)
.unwrap_or(0);
self.queue.insert(index, TokenTimeout::new(token, instant));
}
pub fn remove(&mut self, token: Token) -> Option<TokenTimeout> {
self.get_token_index(token)
.map(|index| self.queue.remove(index))
}
fn get_index_by<F>(&self, func: F) -> Option<usize>
where
F: Fn(&TokenTimeout) -> bool,
{
for i in (0..self.queue.len()).rev() {
let token_timeout = &self.queue[i];
if func(token_timeout) {
return Some(i);
}
}
None
}
pub fn get_token_index(&self, token: Token) -> Option<usize> {
self.get_index_by(|item| item.token == token)
}
pub fn current(&self) -> Option<&TokenTimeout> {
self.queue.last()
}
pub(crate) fn pop_timeouts(&mut self, instant: Instant) -> Vec<TokenTimeout> {
if self.queue.len() == 0 {
return vec![];
}
let index = match self.get_index_by(|item| item.timeout > instant) {
Some(index) => index + 1,
None => 0,
};
let mut result = self.queue.split_off(index);
result.reverse();
result
}
pub fn is_empty(&self) -> bool {
self.queue.is_empty()
}
pub fn len(&self) -> usize {
self.queue.len()
}
}
#[cfg(test)]
mod tests {
use std::time::Duration;
use super::*;
#[test]
fn test_pop_timeouts() {
let mut timeouts = Timeouts::new();
let instant = Instant::now();
timeouts.add(Token(0), instant + Duration::from_secs(1));
timeouts.add(Token(1), instant + Duration::from_secs(2));
timeouts.add(Token(3), instant + Duration::from_secs(3));
let result = timeouts.pop_timeouts(instant + Duration::from_secs(2));
assert_eq!(result.len(), 2);
assert_eq!(result[0].token, Token(0));
assert_eq!(result[1].token, Token(1));
let result = timeouts.pop_timeouts(instant + Duration::from_secs(2));
assert_eq!(result.len(), 0);
let result = timeouts.pop_timeouts(instant + Duration::from_secs(3));
assert_eq!(result.len(), 1);
}
#[test]
fn test_timeouts_new() {
let timeouts = Timeouts::new();
assert!(timeouts.is_empty());
assert_eq!(timeouts.len(), 0);
}
#[test]
fn test_timeouts_add_single() {
let mut timeouts = Timeouts::new();
let instant = Instant::now();
let token = Token(42);
timeouts.add(token, instant);
assert!(!timeouts.is_empty());
assert_eq!(timeouts.len(), 1);
let current = timeouts.current();
assert!(current.is_some());
assert_eq!(current.unwrap().token, token);
assert_eq!(current.unwrap().timeout, instant);
}
#[test]
fn test_timeouts_add_multiple_ordered() {
let mut timeouts = Timeouts::new();
let instant = Instant::now();
timeouts.add(Token(1), instant + Duration::from_secs(3));
timeouts.add(Token(2), instant + Duration::from_secs(1));
timeouts.add(Token(3), instant + Duration::from_secs(2));
assert_eq!(timeouts.len(), 3);
let current = timeouts.current();
assert!(current.is_some());
assert_eq!(current.unwrap().token, Token(2)); }
#[test]
fn test_timeouts_remove() {
let mut timeouts = Timeouts::new();
let instant = Instant::now();
timeouts.add(Token(1), instant + Duration::from_secs(1));
timeouts.add(Token(2), instant + Duration::from_secs(2));
timeouts.add(Token(3), instant + Duration::from_secs(3));
assert_eq!(timeouts.len(), 3);
let removed = timeouts.remove(Token(2));
assert!(removed.is_some());
assert_eq!(removed.unwrap().token, Token(2));
assert_eq!(timeouts.len(), 2);
let removed = timeouts.remove(Token(99));
assert!(removed.is_none());
assert_eq!(timeouts.len(), 2);
}
#[test]
fn test_timeouts_get_token_index() {
let mut timeouts = Timeouts::new();
let instant = Instant::now();
timeouts.add(Token(1), instant + Duration::from_secs(1));
timeouts.add(Token(2), instant + Duration::from_secs(2));
timeouts.add(Token(3), instant + Duration::from_secs(3));
assert_eq!(timeouts.get_token_index(Token(1)), Some(2));
assert_eq!(timeouts.get_token_index(Token(2)), Some(1));
assert_eq!(timeouts.get_token_index(Token(3)), Some(0));
assert_eq!(timeouts.get_token_index(Token(99)), None);
}
#[test]
fn test_timeouts_current() {
let mut timeouts = Timeouts::new();
let instant = Instant::now();
assert!(timeouts.current().is_none());
timeouts.add(Token(1), instant + Duration::from_secs(1));
let current = timeouts.current();
assert!(current.is_some());
assert_eq!(current.unwrap().token, Token(1));
timeouts.add(Token(2), instant + Duration::from_secs(2));
timeouts.add(Token(3), instant + Duration::from_secs(3));
let current = timeouts.current();
assert!(current.is_some());
assert_eq!(current.unwrap().token, Token(1)); }
#[test]
fn test_timeouts_pop_timeouts_empty() {
let mut timeouts = Timeouts::new();
let instant = Instant::now();
let result = timeouts.pop_timeouts(instant);
assert!(result.is_empty());
}
#[test]
fn test_timeouts_pop_timeouts_all() {
let mut timeouts = Timeouts::new();
let instant = Instant::now();
timeouts.add(Token(1), instant + Duration::from_secs(1));
timeouts.add(Token(2), instant + Duration::from_secs(2));
timeouts.add(Token(3), instant + Duration::from_secs(3));
let result = timeouts.pop_timeouts(instant + Duration::from_secs(5));
assert_eq!(result.len(), 3);
assert_eq!(result[0].token, Token(1));
assert_eq!(result[1].token, Token(2));
assert_eq!(result[2].token, Token(3));
assert!(timeouts.is_empty());
}
#[test]
fn test_timeouts_pop_timeouts_partial() {
let mut timeouts = Timeouts::new();
let instant = Instant::now();
timeouts.add(Token(1), instant + Duration::from_secs(1));
timeouts.add(Token(2), instant + Duration::from_secs(2));
timeouts.add(Token(3), instant + Duration::from_secs(3));
timeouts.add(Token(4), instant + Duration::from_secs(4));
let result = timeouts.pop_timeouts(instant + Duration::from_secs(2));
assert_eq!(result.len(), 2);
assert_eq!(result[0].token, Token(1));
assert_eq!(result[1].token, Token(2));
assert_eq!(timeouts.len(), 2);
let result = timeouts.pop_timeouts(instant + Duration::from_secs(5));
assert_eq!(result.len(), 2);
assert_eq!(result[0].token, Token(3));
assert_eq!(result[1].token, Token(4));
assert!(timeouts.is_empty());
}
#[test]
fn test_timeouts_ordering() {
let mut timeouts = Timeouts::new();
let instant = Instant::now();
timeouts.add(Token(5), instant + Duration::from_secs(5));
timeouts.add(Token(3), instant + Duration::from_secs(3));
timeouts.add(Token(1), instant + Duration::from_secs(1));
timeouts.add(Token(4), instant + Duration::from_secs(4));
timeouts.add(Token(2), instant + Duration::from_secs(2));
let result = timeouts.pop_timeouts(instant + Duration::from_secs(10));
assert_eq!(result.len(), 5);
assert_eq!(result[0].token, Token(1));
assert_eq!(result[1].token, Token(2));
assert_eq!(result[2].token, Token(3));
assert_eq!(result[3].token, Token(4));
assert_eq!(result[4].token, Token(5));
}
}