use std::collections::TryReserveError;
use crate::util::try_reserve_vec;
#[must_use]
#[derive(Clone, Debug)]
pub struct Buffer<T>
where
T: Clone + Default,
{
data: Vec<T>,
position: usize,
limit: usize,
}
impl<T> Buffer<T>
where
T: Clone + Default,
{
#[inline]
pub fn with_capacity(capacity: usize) -> Self {
let capacity = capacity.max(1);
Self {
data: vec![T::default(); capacity],
position: 0,
limit: 0,
}
}
#[inline]
pub fn try_with_capacity(capacity: usize) -> Result<Self, TryReserveError> {
let capacity = capacity.max(1);
let mut data = Vec::new();
try_reserve_vec(&mut data, capacity)?;
if std::mem::size_of::<T>() == 0 {
data = vec![T::default(); capacity];
} else {
data.resize_with(capacity, T::default);
}
Ok(Self {
data,
position: 0,
limit: 0,
})
}
#[inline]
pub fn try_reserve_capacity(&mut self, capacity: usize) -> Result<(), TryReserveError> {
if capacity <= self.data.len() {
return Ok(());
}
let additional = capacity - self.data.len();
try_reserve_vec(&mut self.data, additional)?;
if std::mem::size_of::<T>() == 0 {
let mut additional_data = vec![T::default(); additional];
self.data.append(&mut additional_data);
} else {
self.data.resize_with(capacity, T::default);
}
Ok(())
}
#[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 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 {
self.data[..self.limit].rotate_left(self.position);
}
self.position = 0;
self.limit = available;
}
#[inline]
pub unsafe fn copy_from(&mut self, input: &[T], input_index: usize, count: usize) {
debug_assert!(
input_index <= input.len() && count <= input.len() - input_index,
"unchecked source range exceeds input buffer"
);
debug_assert!(
count <= self.spare_capacity(),
"unchecked copy exceeds spare buffer capacity"
);
unsafe {
let input = input.get_unchecked(input_index..input_index + count);
let limit = self.limit;
let destination = self.data.get_unchecked_mut(limit..limit + count);
destination.clone_from_slice(input);
self.advance(count);
}
}
#[inline]
pub unsafe fn copy_to(&mut self, output: &mut [T], output_index: usize, count: usize) {
debug_assert!(
output_index <= output.len() && count <= output.len() - output_index,
"unchecked destination range exceeds output buffer"
);
debug_assert!(
count <= self.available(),
"unchecked copy exceeds available buffer items"
);
unsafe {
let position = self.position;
let source = self.data.get_unchecked(position..position + count);
let output = output.get_unchecked_mut(output_index..output_index + count);
output.clone_from_slice(source);
self.consume(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;
}
}