use alloc::collections::VecDeque;
use crate::error::{CollectionError, CollectionResult};
#[derive(Debug, Clone)]
pub struct RingBuffer<T> {
inner: VecDeque<T>,
capacity: usize,
}
impl<T> RingBuffer<T> {
pub fn new(capacity: usize) -> CollectionResult<Self> {
if capacity == 0 {
return Err(CollectionError::ZeroCapacity);
}
Ok(Self {
inner: VecDeque::with_capacity(capacity),
capacity,
})
}
pub fn push(&mut self, item: T) -> Option<T> {
let evicted = if self.inner.len() == self.capacity {
self.inner.pop_front()
} else {
None
};
self.inner.push_back(item);
evicted
}
pub fn pop(&mut self) -> Option<T> {
self.inner.pop_front()
}
pub fn oldest(&self) -> Option<&T> {
self.inner.front()
}
pub fn newest(&self) -> Option<&T> {
self.inner.back()
}
pub fn capacity(&self) -> usize {
self.capacity
}
pub fn len(&self) -> usize {
self.inner.len()
}
pub fn is_empty(&self) -> bool {
self.inner.is_empty()
}
pub fn is_full(&self) -> bool {
self.inner.len() == self.capacity
}
pub fn clear(&mut self) {
self.inner.clear();
}
pub fn iter(&self) -> alloc::collections::vec_deque::Iter<'_, T> {
self.inner.iter()
}
}
#[cfg(test)]
mod tests {
use super::*;
use alloc::vec::Vec;
fn snapshot<T: Clone>(rb: &RingBuffer<T>) -> Vec<T> {
rb.iter().cloned().collect()
}
#[test]
fn rejects_zero_capacity() {
assert_eq!(
RingBuffer::<i32>::new(0).unwrap_err(),
CollectionError::ZeroCapacity
);
}
#[test]
fn fills_then_evicts_oldest() {
let mut rb = RingBuffer::new(3).unwrap();
assert!(rb.is_empty());
assert_eq!(rb.push(1), None);
assert_eq!(rb.push(2), None);
assert_eq!(rb.push(3), None);
assert!(rb.is_full());
assert_eq!(rb.len(), 3);
assert_eq!(snapshot(&rb), [1, 2, 3]);
assert_eq!(rb.push(4), Some(1));
assert_eq!(rb.push(5), Some(2));
assert_eq!(snapshot(&rb), [3, 4, 5]);
assert_eq!(rb.len(), 3);
assert_eq!(rb.capacity(), 3);
}
#[test]
fn oldest_newest_pop_and_clear() {
let mut rb = RingBuffer::new(2).unwrap();
assert_eq!(rb.oldest(), None);
assert_eq!(rb.newest(), None);
rb.push(10);
rb.push(20);
assert_eq!(rb.oldest(), Some(&10));
assert_eq!(rb.newest(), Some(&20));
assert_eq!(rb.pop(), Some(10)); assert_eq!(rb.oldest(), Some(&20));
rb.clear();
assert!(rb.is_empty());
assert_eq!(rb.capacity(), 2); }
#[test]
fn capacity_one_keeps_only_newest() {
let mut rb = RingBuffer::new(1).unwrap();
assert_eq!(rb.push("a"), None);
assert_eq!(rb.push("b"), Some("a"));
assert_eq!(rb.push("c"), Some("b"));
assert_eq!(snapshot(&rb), ["c"]);
}
}