use std::sync::{Arc, Mutex};
#[derive(Clone)]
pub struct BoundedBuffer<T> {
items: Arc<Mutex<Vec<T>>>,
max_size: usize,
}
impl<T: Clone> BoundedBuffer<T> {
pub fn new(max_size: usize) -> Self {
Self {
items: Arc::new(Mutex::new(Vec::new())),
max_size,
}
}
pub fn push(&self, item: T) {
let mut items = self.items.lock().unwrap();
items.push(item);
if items.len() > self.max_size {
let excess = items.len() - self.max_size;
items.drain(0..excess);
}
}
pub fn get_all(&self) -> Vec<T> {
self.items.lock().unwrap().clone()
}
#[allow(dead_code)]
pub fn clear(&self) {
self.items.lock().unwrap().clear();
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn new_buffer_starts_empty() {
let buffer: BoundedBuffer<i32> = BoundedBuffer::new(3);
assert!(buffer.get_all().is_empty());
}
#[test]
fn push_appends_items_in_order() {
let buffer = BoundedBuffer::new(10);
buffer.push(1);
buffer.push(2);
buffer.push(3);
assert_eq!(buffer.get_all(), vec![1, 2, 3]);
}
#[test]
fn push_drops_oldest_items_past_max_size() {
let buffer = BoundedBuffer::new(2);
buffer.push(1);
buffer.push(2);
buffer.push(3);
assert_eq!(buffer.get_all(), vec![2, 3]);
}
#[test]
fn clear_empties_the_buffer() {
let buffer = BoundedBuffer::new(5);
buffer.push("a".to_string());
buffer.push("b".to_string());
buffer.clear();
assert!(buffer.get_all().is_empty());
}
#[test]
fn clone_shares_the_same_underlying_buffer() {
let buffer = BoundedBuffer::new(5);
let handle = buffer.clone();
handle.push(42);
assert_eq!(buffer.get_all(), vec![42]);
}
}