Files
riscv64-kernel/src/data_structures/circular_buffer.rs

88 lines
2.2 KiB
Rust

use core::{
mem::MaybeUninit,
ops::{Index, IndexMut},
};
#[derive(Debug, Copy)]
pub struct CircularBuffer<T, const SIZE: usize> {
buffer: [MaybeUninit<T>; SIZE],
head: usize,
tail: usize,
len: usize,
}
impl<T: Copy, const SIZE: usize> Clone for CircularBuffer<T, SIZE> {
fn clone(&self) -> Self {
*self
}
}
impl<T, const SIZE: usize> CircularBuffer<T, SIZE> {
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<T> {
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<T, const SIZE: usize> Index<usize> for CircularBuffer<T, SIZE> {
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<T, const SIZE: usize> IndexMut<usize> for CircularBuffer<T, SIZE> {
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")
}
}
}