use core::{ mem::MaybeUninit, ops::{Index, IndexMut}, }; #[derive(Debug, Copy)] pub struct CircularBuffer { buffer: [MaybeUninit; SIZE], head: usize, tail: usize, len: usize, } impl Clone for CircularBuffer { fn clone(&self) -> Self { *self } } impl CircularBuffer { pub const fn new() -> Self { Self { buffer: [const { MaybeUninit::uninit() }; SIZE], head: 0, tail: 0, len: 0, } } pub fn len(&self) -> usize { self.len } pub fn is_empty(&self) -> bool { self.len() == 0 } pub fn is_full(&self) -> bool { self.len() == SIZE - 1 } pub fn pop(&mut self) -> Option { if self.is_empty() { None } else { let out = core::mem::replace(&mut self.buffer[self.head], MaybeUninit::uninit()); self.head = (self.head + 1) % SIZE; self.len -= 1; // # Safety // the queue is not empty and head points to a valid value Some(unsafe { out.assume_init() }) } } pub fn push(&mut self, value: T) -> bool { self.buffer[self.tail] = MaybeUninit::new(value); self.tail = (self.tail + 1) % SIZE; if self.is_full() { self.head = (self.head + 1) % SIZE; true } else { self.len += 1; false } } } impl Index for CircularBuffer { type Output = T; fn index(&self, index: usize) -> &Self::Output { if self.len() > index { unsafe { self.buffer[(self.head + index) % SIZE].assume_init_ref() } } else { panic!("index is bigger than circular buffer") } } } impl IndexMut for CircularBuffer { fn index_mut(&mut self, index: usize) -> &mut Self::Output { if self.len() > index { unsafe { self.buffer[(self.head + index) % SIZE].assume_init_mut() } } else { panic!("index is bigger than circular buffer") } } }