use std::collections::VecDeque;
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
pub enum DropPolicy {
DropNewest,
#[default]
KeepLatest,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum QueuePush {
Added,
ReplacedOldest,
DroppedNewest,
}
#[derive(Debug)]
pub struct BoundedQueue<T> {
items: VecDeque<T>,
capacity: usize,
policy: DropPolicy,
}
impl<T> BoundedQueue<T> {
pub fn new(capacity: usize, policy: DropPolicy) -> Option<Self> {
(capacity > 0).then(|| Self {
items: VecDeque::with_capacity(capacity),
capacity,
policy,
})
}
pub fn push(&mut self, item: T) -> QueuePush {
if self.items.len() < self.capacity {
self.items.push_back(item);
return QueuePush::Added;
}
match self.policy {
DropPolicy::DropNewest => QueuePush::DroppedNewest,
DropPolicy::KeepLatest => {
self.items.pop_front();
self.items.push_back(item);
QueuePush::ReplacedOldest
}
}
}
pub fn pop(&mut self) -> Option<T> {
self.items.pop_front()
}
pub fn len(&self) -> usize {
self.items.len()
}
pub fn is_empty(&self) -> bool {
self.items.is_empty()
}
pub fn clear(&mut self) {
self.items.clear();
}
}
#[cfg(test)]
mod tests {
use super::{BoundedQueue, DropPolicy, QueuePush};
#[test]
fn keep_latest_discards_oldest_item() {
let mut queue = BoundedQueue::new(2, DropPolicy::KeepLatest).unwrap();
queue.push(1);
queue.push(2);
assert_eq!(queue.push(3), QueuePush::ReplacedOldest);
assert_eq!(queue.pop(), Some(2));
assert_eq!(queue.pop(), Some(3));
}
#[test]
fn drop_newest_preserves_queued_items() {
let mut queue = BoundedQueue::new(1, DropPolicy::DropNewest).unwrap();
queue.push(1);
assert_eq!(queue.push(2), QueuePush::DroppedNewest);
assert_eq!(queue.pop(), Some(1));
}
}