use std::io::{Result as IoResult, Error as IoError, ErrorKind};
use std::num::NonZeroUsize;
use std::slice::from_raw_parts_mut;
use crate::Primitive;
pub struct SpareBuffer<'a, T>
where
T: Primitive
{
buffer: &'a mut Vec<T>,
limit: Option<NonZeroUsize>,
allocated: bool,
}
impl<'a, T> SpareBuffer<'a, T>
where
T: Primitive
{
pub fn from(buffer: &'a mut Vec<T>, limit: Option<NonZeroUsize>) -> Self {
Self {
buffer,
limit,
allocated: false,
}
}
pub fn len(&self) -> usize {
self.buffer.len()
}
pub fn is_empty(&self) -> bool {
self.buffer.is_empty()
}
pub fn limit(&self) -> Option<NonZeroUsize> {
self.limit
}
pub fn data(&self) -> &[T] {
&self.buffer[..]
}
pub fn allocate_spare(&mut self, length: NonZeroUsize) -> &mut[T] {
self.buffer.reserve(length.get());
self.allocated = true;
let spare = self.buffer.spare_capacity_mut();
unsafe {
from_raw_parts_mut(spare.as_mut_ptr() as *mut T, spare.len())
}
}
pub fn commit(&mut self, additional: usize) -> IoResult<()> {
assert!(std::mem::replace(&mut self.allocated, false), "No spare buffer allocated!");
if additional > 0 {
let new_length = self.buffer.len().checked_add(additional).expect("Numerical overflow! (new_length)");
assert!(new_length <= self.buffer.capacity(), "Commit size exceeds available capacity!");
if new_length <= self.limit.map_or(usize::MAX, NonZeroUsize::get) {
unsafe {
self.buffer.set_len(new_length)
}
} else {
return Err(IoError::new(ErrorKind::OutOfMemory, "The new length exceeds the specified limit!"))
}
}
Ok(())
}
pub unsafe fn commit_unchecked(&mut self, additional: usize) {
self.allocated = false;
if additional > 0 {
self.buffer.set_len(self.buffer.len() + additional)
}
}
}