use std::ptr;
#[derive(Clone, Debug)]
pub struct Buffer<T>
where
T: Copy + Default,
{
data: Vec<T>,
position: usize,
limit: usize,
}
impl<T> Buffer<T>
where
T: Copy + Default,
{
#[inline(always)]
#[must_use]
pub fn with_capacity(capacity: usize) -> Self {
let capacity = capacity.max(1);
Self {
data: vec![T::default(); capacity],
position: 0,
limit: 0,
}
}
#[inline(always)]
#[must_use]
pub fn capacity(&self) -> usize {
self.data.len()
}
#[inline(always)]
#[must_use]
pub const fn position(&self) -> usize {
self.position
}
#[inline(always)]
#[must_use]
pub const fn limit(&self) -> usize {
self.limit
}
#[inline(always)]
#[must_use]
pub fn data(&self) -> &[T] {
&self.data
}
#[inline(always)]
#[must_use]
pub fn data_mut(&mut self) -> &mut [T] {
&mut self.data
}
#[inline(always)]
#[must_use]
pub const fn available(&self) -> usize {
self.limit - self.position
}
#[inline(always)]
#[must_use]
pub fn spare_capacity(&self) -> usize {
self.data.len() - self.limit
}
#[inline(always)]
#[must_use]
pub const fn is_empty(&self) -> bool {
self.position == self.limit
}
#[inline(always)]
#[must_use]
pub fn is_full(&self) -> bool {
self.limit == self.data.len()
}
#[inline(always)]
pub fn clear(&mut self) {
self.position = 0;
self.limit = 0;
}
#[inline(always)]
pub fn consume(&mut self, count: usize) {
assert!(
count <= self.available(),
"cannot consume beyond buffer limit"
);
unsafe {
self.consume_unchecked(count);
}
}
#[inline(always)]
pub unsafe fn consume_unchecked(&mut self, count: usize) {
debug_assert!(
count <= self.available(),
"unchecked consume exceeds available buffer"
);
self.position += count;
}
#[inline(always)]
pub fn advance(&mut self, count: usize) {
assert!(
count <= self.spare_capacity(),
"cannot advance beyond buffer capacity"
);
unsafe {
self.advance_unchecked(count);
}
}
#[inline(always)]
pub unsafe fn advance_unchecked(&mut self, count: usize) {
debug_assert!(
count <= self.spare_capacity(),
"unchecked advance exceeds spare buffer capacity"
);
self.limit += count;
}
#[inline]
pub fn compact(&mut self) {
let available = self.available();
if available == 0 {
self.clear();
return;
}
if self.position != 0 {
unsafe {
let source = self.data.as_ptr().add(self.position);
let destination = self.data.as_mut_ptr();
ptr::copy(source, destination, available);
}
}
self.position = 0;
self.limit = available;
}
#[inline(always)]
pub unsafe fn copy_from_unchecked(
&mut self,
input: &[T],
input_index: usize,
count: usize,
) {
debug_assert!(
input_index
.checked_add(count)
.is_some_and(|end| end <= input.len()),
"unchecked input range exceeds source buffer"
);
debug_assert!(
count <= self.spare_capacity(),
"unchecked input copy exceeds spare buffer capacity"
);
unsafe {
let source = input.as_ptr().add(input_index);
let destination = self.data.as_mut_ptr().add(self.limit);
ptr::copy_nonoverlapping(source, destination, count);
self.advance_unchecked(count);
}
}
#[inline(always)]
pub unsafe fn copy_to_unchecked(
&mut self,
output: &mut [T],
output_index: usize,
count: usize,
) {
debug_assert!(
output_index
.checked_add(count)
.is_some_and(|end| end <= output.len()),
"unchecked output range exceeds destination buffer"
);
debug_assert!(
count <= self.available(),
"unchecked output copy exceeds readable buffer"
);
unsafe {
let source = self.data.as_ptr().add(self.position);
let destination = output.as_mut_ptr().add(output_index);
ptr::copy_nonoverlapping(source, destination, count);
self.consume_unchecked(count);
}
}
}