use std::collections::VecDeque;
#[derive(Debug, Clone)]
pub struct BoundedQueue<T> {
items: VecDeque<T>,
max_size: usize,
}
impl<T> BoundedQueue<T> {
pub fn new(max_size: usize) -> Self {
Self {
items: VecDeque::with_capacity(max_size),
max_size,
}
}
pub fn push(&mut self, item: T) -> Option<T> {
if self.max_size == 0 {
return Some(item);
}
let evicted = if self.is_full() {
self.items.pop_front()
} else {
None
};
self.items.push_back(item);
evicted
}
pub fn len(&self) -> usize {
self.items.len()
}
pub fn is_empty(&self) -> bool {
self.items.is_empty()
}
pub fn is_full(&self) -> bool {
self.items.len() >= self.max_size
}
pub fn iter(&self) -> impl Iterator<Item = &T> {
self.items.iter()
}
pub fn drain_oldest(&mut self, n: usize) -> Vec<T> {
let count = n.min(self.items.len());
self.items.drain(..count).collect()
}
}
#[cfg(test)]
pub mod tests {
use super::BoundedQueue;
#[test]
fn bounded_queue_evicts_oldest() {
let mut queue = BoundedQueue::new(2);
assert_eq!(queue.push(1), None);
assert_eq!(queue.push(2), None);
assert_eq!(queue.push(3), Some(1));
assert_eq!(queue.iter().copied().collect::<Vec<i32>>(), vec![2, 3]);
assert!(queue.is_full());
}
#[test]
fn bounded_queue_drain() {
let mut queue = BoundedQueue::new(4);
queue.push("first");
queue.push("second");
queue.push("third");
assert_eq!(queue.drain_oldest(2), vec!["first", "second"]);
assert_eq!(queue.len(), 1);
assert_eq!(queue.drain_oldest(5), vec!["third"]);
assert!(queue.is_empty());
}
#[test]
fn bounded_queue_with_zero_capacity_rejects_items() {
let mut queue = BoundedQueue::new(0);
assert_eq!(queue.push(7), Some(7));
assert!(queue.is_empty());
assert!(queue.is_full());
}
}