use std::collections::VecDeque;
pub struct RingBuffer<T> {
buffer: VecDeque<T>,
capacity: usize,
}
impl<T> RingBuffer<T> {
#[must_use]
pub fn new(capacity: usize) -> Self {
assert!(capacity > 0, "RingBuffer capacity must be > 0");
Self {
buffer: VecDeque::with_capacity(capacity),
capacity,
}
}
pub fn push(&mut self, item: T) {
if self.buffer.len() == self.capacity {
self.buffer.pop_front();
}
self.buffer.push_back(item);
}
#[must_use]
pub fn latest(&self) -> Option<&T> {
self.buffer.back()
}
pub fn drain_all(&mut self) -> Vec<T> {
self.buffer.drain(..).collect()
}
#[must_use]
pub fn len(&self) -> usize {
self.buffer.len()
}
#[must_use]
pub fn is_empty(&self) -> bool {
self.buffer.is_empty()
}
#[must_use]
pub fn capacity(&self) -> usize {
self.capacity
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn ring_buffer_starts_empty() {
let buf: RingBuffer<u32> = RingBuffer::new(4);
assert!(buf.is_empty());
assert_eq!(buf.len(), 0);
assert!(buf.latest().is_none());
}
#[test]
fn ring_buffer_push_below_capacity_retains_all_items() {
let mut buf = RingBuffer::new(4);
buf.push(1u32);
buf.push(2);
buf.push(3);
assert_eq!(buf.len(), 3);
assert_eq!(buf.latest(), Some(&3));
}
#[test]
fn ring_buffer_push_at_capacity_evicts_oldest() {
let mut buf = RingBuffer::new(3);
buf.push("a");
buf.push("b");
buf.push("c");
buf.push("d"); assert_eq!(buf.len(), 3);
let items = buf.drain_all();
assert_eq!(items, vec!["b", "c", "d"]);
}
#[test]
fn ring_buffer_drain_all_empties_the_buffer() {
let mut buf = RingBuffer::new(10);
buf.push(10u32);
buf.push(20);
let items = buf.drain_all();
assert_eq!(items, vec![10, 20]);
assert!(buf.is_empty());
}
#[test]
fn ring_buffer_capacity_reported_correctly() {
let buf: RingBuffer<String> = RingBuffer::new(7);
assert_eq!(buf.capacity(), 7);
}
#[test]
fn ring_buffer_latest_tracks_most_recent_push() {
let mut buf = RingBuffer::new(2);
buf.push(100u32);
buf.push(200);
buf.push(300); assert_eq!(buf.latest(), Some(&300));
}
#[test]
fn ring_buffer_eviction_count_matches_overflow_count() {
let mut buf = RingBuffer::new(3);
for i in 0u32..10 {
buf.push(i);
}
assert_eq!(buf.len(), 3);
let items = buf.drain_all();
assert_eq!(items, vec![7, 8, 9]);
}
#[test]
#[should_panic(expected = "capacity must be > 0")]
fn ring_buffer_zero_capacity_panics() {
let _: RingBuffer<u8> = RingBuffer::new(0);
}
#[test]
fn ring_buffer_memory_stays_bounded_under_sustained_load() {
let mut buf = RingBuffer::new(100);
for i in 0u32..10_000 {
buf.push(i);
}
assert_eq!(buf.len(), 100);
let items = buf.drain_all();
assert_eq!(items[0], 9_900);
assert_eq!(items[99], 9_999);
}
}