use crate::{utils::pad_to_align, DEFAULT_STORAGE_ALIGN};
use core::{fmt::Debug, mem::MaybeUninit};
pub unsafe trait Storage {
type AllocError;
const ALIGN: usize;
fn try_grow_by(&mut self, additional_bytes: usize) -> Result<(), Self::AllocError>;
fn view(&self) -> &[MaybeUninit<u8>];
fn view_mut(&mut self) -> &mut [MaybeUninit<u8>];
}
#[cfg(feature = "alloc")]
mod alloc {
use super::*;
use aligned_vec::{AVec, ConstAlign};
use core::convert::Infallible;
pub struct VecStorage<const ALIGN: usize = DEFAULT_STORAGE_ALIGN> {
bytes: AVec<MaybeUninit<u8>, ConstAlign<ALIGN>>,
}
impl VecStorage {
#[inline]
pub fn new() -> Self {
Self::new_align()
}
}
impl<const ALIGN: usize> VecStorage<ALIGN> {
#[inline]
pub fn new_align() -> Self {
Default::default()
}
}
impl<const ALIGN: usize> Default for VecStorage<ALIGN> {
#[inline]
fn default() -> Self {
Self {
bytes: AVec::new(ALIGN),
}
}
}
unsafe impl<const ALIGN: usize> Storage for VecStorage<ALIGN> {
type AllocError = Infallible;
const ALIGN: usize = ALIGN;
#[inline]
fn try_grow_by(&mut self, additional_bytes: usize) -> Result<(), Self::AllocError> {
self.bytes.reserve(additional_bytes);
let new_size = unsafe { self.bytes.len().unchecked_add(additional_bytes) };
unsafe {
self.bytes.set_len(new_size);
}
Ok(())
}
#[inline]
fn view(&self) -> &[MaybeUninit<u8>] {
self.bytes.as_slice()
}
#[inline]
fn view_mut(&mut self) -> &mut [MaybeUninit<u8>] {
self.bytes.as_mut_slice()
}
}
}
#[cfg(feature = "alloc")]
pub use alloc::*;
#[derive(Debug)]
pub enum SliceStorageError {
Overflow,
OutOfMemory,
}
pub struct SliceStorage<'a, const ALIGN: usize = DEFAULT_STORAGE_ALIGN> {
bytes: &'a mut [MaybeUninit<u8>],
size: usize,
}
impl<'a> SliceStorage<'a> {
#[inline]
pub fn from_unaligned_bytes(
bytes: &'a mut [MaybeUninit<u8>],
) -> Result<Self, SliceStorageError> {
Self::from_unaligned_bytes_align(bytes)
}
}
impl<'a, const ALIGN: usize> SliceStorage<'a, ALIGN> {
#[inline]
pub fn from_unaligned_bytes_align(
bytes: &'a mut [MaybeUninit<u8>],
) -> Result<Self, SliceStorageError> {
let padding = unsafe { pad_to_align(bytes.as_ptr() as usize, ALIGN) };
let mut storage = SliceStorage { bytes, size: 0 };
storage.try_grow_by(padding)?;
storage.bytes = unsafe { storage.bytes.get_unchecked_mut(storage.size..) };
storage.size = 0;
Ok(storage)
}
}
unsafe impl<const ALIGN: usize> Storage for SliceStorage<'_, ALIGN> {
type AllocError = SliceStorageError;
const ALIGN: usize = ALIGN;
#[inline]
fn try_grow_by(&mut self, additional_bytes: usize) -> Result<(), Self::AllocError> {
let new_size = self
.size
.checked_add(additional_bytes)
.ok_or(SliceStorageError::Overflow)?;
if new_size >= self.bytes.len() {
return Err(SliceStorageError::OutOfMemory);
}
self.size = new_size;
Ok(())
}
#[inline]
fn view(&self) -> &[MaybeUninit<u8>] {
unsafe { self.bytes.get_unchecked(0..self.size) }
}
#[inline]
fn view_mut(&mut self) -> &mut [MaybeUninit<u8>] {
unsafe { self.bytes.get_unchecked_mut(0..self.size) }
}
}