use std::{
io::{self, Write},
ops::{Deref, DerefMut},
sync::Arc,
};
use crate::{
header::{Guard, Header},
RingAl, USIZEALIGN,
};
pub struct ExtBuf<'a> {
pub(crate) header: Header,
pub(crate) initialized: usize,
pub(crate) ringal: &'a mut RingAl,
pub(crate) finalized: bool,
}
impl ExtBuf<'_> {
pub fn finalize(mut self) -> FixedBufMut {
let capacity = self.header.capacity();
let ptr = self.header.buffer();
let inner = unsafe { std::slice::from_raw_parts_mut(ptr, capacity) };
self.finalized = true;
FixedBufMut {
inner,
initialized: self.initialized,
_guard: self.header.into(),
}
}
unsafe fn copy_from(&mut self, src: &[u8]) {
let count = src.len();
let src = src.as_ptr();
let buffer = self.header.buffer().add(self.initialized);
buffer.copy_from_nonoverlapping(src, count);
self.initialized += count;
}
}
impl Write for ExtBuf<'_> {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
let available = self.header.capacity() - self.initialized;
let count = buf.len();
if available >= count {
unsafe { self.copy_from(buf) };
return Ok(count);
}
let Some(header) = self.ringal.alloc(count - available, USIZEALIGN) else {
return Err(io::Error::new(
io::ErrorKind::StorageFull,
"allocator's capacity exhausted",
));
};
if header < self.header {
let ptr = self.header.buffer();
let old = unsafe { std::slice::from_raw_parts(ptr, self.initialized) };
let _guard = Guard::from(self.header);
self.header = header;
self.header.lock();
self.initialized = 0;
let _ = self.write(old)?;
return self.write(buf);
}
let end = header.next().0;
self.header.store(end);
unsafe { self.copy_from(buf) };
Ok(count)
}
fn flush(&mut self) -> std::io::Result<()> {
Ok(())
}
}
impl Drop for ExtBuf<'_> {
#[inline(always)]
fn drop(&mut self) {
if !self.finalized {
let _ = Guard::from(self.header);
}
}
}
pub struct FixedBufMut {
pub(crate) _guard: Guard,
pub(crate) inner: &'static mut [u8],
pub(crate) initialized: usize,
}
impl FixedBufMut {
pub fn freeze(self) -> FixedBuf {
FixedBuf {
_rc: Arc::new(self._guard),
inner: &self.inner[..self.initialized],
}
}
#[inline(always)]
pub fn spare(&self) -> usize {
self.inner.len() - self.initialized
}
}
impl Deref for FixedBufMut {
type Target = [u8];
#[inline(always)]
fn deref(&self) -> &Self::Target {
unsafe { self.inner.get_unchecked(..self.initialized) }
}
}
impl DerefMut for FixedBufMut {
#[inline(always)]
fn deref_mut(&mut self) -> &mut Self::Target {
unsafe { self.inner.get_unchecked_mut(..self.initialized) }
}
}
impl Write for FixedBufMut {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
let tocopy = self.spare().min(buf.len());
let src = buf.as_ptr();
unsafe {
self.inner
.as_mut_ptr()
.add(self.initialized)
.copy_from_nonoverlapping(src, tocopy);
}
self.initialized += tocopy;
Ok(tocopy)
}
fn flush(&mut self) -> io::Result<()> {
Ok(())
}
}
#[derive(Clone)]
pub struct FixedBuf {
_rc: Arc<Guard>,
inner: &'static [u8],
}
impl Deref for FixedBuf {
type Target = [u8];
#[inline(always)]
fn deref(&self) -> &Self::Target {
self.inner
}
}
#[cfg(feature = "generic")]
pub struct GenericBufMut<T: Sized + 'static> {
pub(crate) _guard: Guard,
pub(crate) inner: &'static mut [T],
pub(crate) initialized: usize,
}
#[cfg(feature = "generic")]
mod generic {
use super::{Deref, DerefMut, GenericBufMut};
impl<T> Deref for GenericBufMut<T> {
type Target = [T];
#[inline(always)]
fn deref(&self) -> &Self::Target {
unsafe { self.inner.get_unchecked(..self.initialized) }
}
}
impl<T> DerefMut for GenericBufMut<T> {
#[inline(always)]
fn deref_mut(&mut self) -> &mut Self::Target {
unsafe { self.inner.get_unchecked_mut(..self.initialized) }
}
}
impl<T> GenericBufMut<T> {
pub fn capacity(&self) -> usize {
self.inner.len()
}
pub fn push(&mut self, value: T) -> Option<T> {
if self.inner.len() == self.initialized {
return Some(value);
}
unsafe {
let cell = self.inner.get_unchecked_mut(self.initialized) as *mut T;
std::ptr::write(cell, value);
}
self.initialized += 1;
None
}
pub fn insert(&mut self, mut value: T, mut index: usize) -> Option<T> {
if self.initialized < index {
return Some(value);
}
self.initialized += 1;
unsafe {
while index < self.initialized {
let cell = self.inner.get_unchecked_mut(index) as *mut T;
let temp = std::ptr::read(cell as *const T);
std::ptr::write(cell, value);
value = temp;
index += 1;
}
}
std::mem::forget(value);
None
}
pub fn pop(&mut self) -> Option<T> {
(self.initialized != 0).then_some(())?;
self.initialized -= 1;
let value = unsafe { self.inner.get_unchecked_mut(self.initialized) };
let owned = unsafe { std::ptr::read(value as *const T) };
Some(owned)
}
pub fn remove(&mut self, mut index: usize) -> Option<T> {
(self.initialized > index).then_some(())?;
if self.initialized - 1 == index {
return self.pop();
}
let mut value = unsafe { self.inner.get_unchecked_mut(index) } as *mut T;
let element = unsafe { std::ptr::read(value) };
self.initialized -= 1;
unsafe {
while index < self.initialized {
index += 1;
let next = self.inner.get_unchecked_mut(index) as *mut T;
{
let next = std::ptr::read(next);
std::ptr::write(value, next);
}
value = next;
}
}
Some(element)
}
pub fn swap_remove(&mut self, index: usize) -> Option<T> {
(index < self.initialized).then_some(())?;
if self.initialized - 1 == index {
return self.pop();
}
self.initialized -= 1;
let element = unsafe {
let last = self.inner.get_unchecked_mut(self.initialized) as *mut T;
let value = self.inner.get_unchecked_mut(index) as *mut T;
let element = std::ptr::read(value);
let temp = std::ptr::read(last);
std::ptr::write(value, temp);
element
};
Some(element)
}
}
}