use std::fmt;
#[derive(Debug)]
pub struct RingBuffer<T> {
buffer: Vec<T>,
head: usize,
tail: usize,
size: usize,
capacity: usize,
}
impl<T> RingBuffer<T> {
pub fn with_capacity(capacity: usize) -> Self {
assert!(capacity > 0, "Capacity must be greater than 0");
Self {
buffer: Vec::with_capacity(capacity),
head: 0,
tail: 0,
size: 0,
capacity,
}
}
pub fn len(&self) -> usize {
self.size
}
pub fn is_empty(&self) -> bool {
self.size == 0
}
pub fn is_full(&self) -> bool {
self.size == self.capacity
}
pub fn capacity(&self) -> usize {
self.capacity
}
pub fn push(&mut self, item: T) {
if self.is_full() {
self.tail = (self.tail + 1) % self.capacity;
} else {
self.size += 1;
}
self.buffer.push(item);
self.head = (self.head + 1) % self.capacity;
}
pub fn push_batch(&mut self, items: &[T])
where
T: Clone,
{
for item in items {
self.push(item.clone());
}
}
pub fn pop(&mut self) -> Option<T> {
if self.is_empty() {
return None;
}
let index: _ = self.tail;
self.tail = (self.tail + 1) % self.capacity;
self.size -= 1;
if index < self.buffer.len() {
Some(self.buffer.remove(index))
} else {
None
}
}
pub fn clear(&mut self) {
self.buffer.clear();
self.head = 0;
self.tail = 0;
self.size = 0;
}
pub fn get_all(&self) -> Vec<&T>
where
T: Clone,
{
if self.is_empty() {
return Vec::new();
}
let mut result = Vec::with_capacity(self.size);
let mut index = self.tail;
for _ in 0..self.size {
if index < self.buffer.len() {
result.push(&self.buffer[index]);
}
index = (index + 1) % self.capacity;
}
result
}
pub fn reserve(&mut self, additional: usize) {
self.buffer.reserve(additional);
}
pub fn shrink_to_fit(&mut self) {
self.buffer.shrink_to_fit();
}
}
impl<T> fmt::Display for RingBuffer<T>
where
T: fmt::Display,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"RingBuffer {{ size: {}/{}, head: {}, tail: {} }}",
self.size, self.capacity, self.head, self.tail
)
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::collections::{BTreeMap, HashMap};
#[test]
fn test_ring_buffer_creation() {
let buffer: RingBuffer<i32> = RingBuffer::with_capacity(10);
assert_eq!(buffer.capacity(), 10);
assert_eq!(buffer.len(), 0);
assert!(buffer.is_empty());
}
#[test]
fn test_push_and_pop() {
let mut buffer = RingBuffer::with_capacity(3);
buffer.push(1);
buffer.push(2);
buffer.push(3);
assert_eq!(buffer.len(), 3);
assert!(buffer.is_full());
assert_eq!(buffer.pop(), Some(1));
assert_eq!(buffer.len(), 2);
assert_eq!(buffer.pop(), Some(2));
assert_eq!(buffer.pop(), Some(3));
assert_eq!(buffer.len(), 0);
assert!(buffer.is_empty());
}
#[test]
fn test_overwrite_on_full() {
let mut buffer = RingBuffer::with_capacity(3);
buffer.push(1);
buffer.push(2);
buffer.push(3);
buffer.push(4); assert_eq!(buffer.len(), 3);
assert_eq!(buffer.pop(), Some(2));
assert_eq!(buffer.pop(), Some(3));
assert_eq!(buffer.pop(), Some(4));
}
#[test]
fn test_batch_push() {
let mut buffer = RingBuffer::with_capacity(5);
let items: _ = vec![1, 2, 3, 4, 5];
buffer.push_batch(&items);
assert_eq!(buffer.len(), 5);
assert!(buffer.is_full());
}
#[test]
fn test_clear() {
let mut buffer = RingBuffer::with_capacity(5);
buffer.push(1);
buffer.push(2);
buffer.clear();
assert_eq!(buffer.len(), 0);
assert!(buffer.is_empty());
}
#[test]
fn test_get_all() {
let mut buffer = RingBuffer::with_capacity(5);
buffer.push(1);
buffer.push(2);
buffer.push(3);
let all: _ = buffer.get_all();
assert_eq!(all.len(), 3);
}
#[test]
fn test_display() {
let buffer: RingBuffer<i32> = RingBuffer::with_capacity(10);
let display: _ = format!("{}", buffer);
assert!(display.contains("RingBuffer"));
assert!(display.contains("size: 0/10"));
}
}