use crate::util::UncheckedSlice;
#[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 consumed(&self) -> &[T] {
&self.data[..self.position]
}
#[inline(always)]
#[must_use]
pub fn readable(&self) -> &[T] {
&self.data[self.position..self.limit]
}
#[inline(always)]
#[must_use]
pub fn spare(&self) -> &[T] {
&self.data[self.limit..]
}
#[inline(always)]
#[must_use]
pub fn spare_mut(&mut self) -> &mut [T] {
let limit = self.limit;
&mut self.data[limit..]
}
#[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)]
#[must_use]
pub fn spare_raw_parts_mut(&mut self) -> (&mut [T], usize, usize) {
let index = self.limit;
let count = self.spare_capacity();
(self.data_mut(), index, count)
}
#[inline(always)]
pub fn clear(&mut self) {
self.position = 0;
self.limit = 0;
}
#[inline(always)]
pub unsafe fn consume(&mut self, count: usize) {
debug_assert!(
count <= self.available(),
"unchecked consume exceeds available buffer"
);
self.position += count;
}
#[inline(always)]
pub(crate) unsafe fn rewind(&mut self, count: usize) {
debug_assert!(
count <= self.position,
"unchecked rewind exceeds consumed buffer prefix"
);
self.position -= count;
}
#[inline(always)]
pub unsafe fn advance(&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 {
UncheckedSlice::copy_within(
&mut self.data,
self.position,
0,
available,
);
}
}
self.position = 0;
self.limit = available;
}
#[inline(always)]
pub unsafe fn copy_from(
&mut self,
input: &[T],
input_index: usize,
count: usize,
) {
debug_assert!(
count <= self.spare_capacity(),
"unchecked input copy exceeds spare buffer capacity"
);
unsafe {
UncheckedSlice::copy_nonoverlapping(
input,
input_index,
&mut self.data,
self.limit,
count,
);
self.advance(count);
}
}
#[inline(always)]
pub unsafe fn copy_to(
&mut self,
output: &mut [T],
output_index: usize,
count: usize,
) {
unsafe {
UncheckedSlice::copy_nonoverlapping(
&self.data,
self.position,
output,
output_index,
count,
);
self.consume(count);
}
}
}