use core::mem::{align_of, size_of, MaybeUninit};
use super::{Storage, StorageWithCapacity};
#[repr(C)]
struct AlignedBuffer<T, A> {
align: MaybeUninit<[A; 0]>,
value: T,
}
#[repr(transparent)]
pub struct UninitBuffer<T, A = u8>(MaybeUninit<AlignedBuffer<T, A>>);
unsafe impl<T, A> Send for UninitBuffer<T, A> {}
unsafe impl<T, A> Sync for UninitBuffer<T, A> {}
const fn size<U, T, A>() -> usize {
if size_of::<U>() == 0 {
usize::MAX
} else {
size_of::<AlignedBuffer<T, A>>() / size_of::<U>()
}
}
impl<T, A> UninitBuffer<T, A> {
pub const fn capacity<U>() -> usize { size::<U, T, A>() }
pub const fn uninit() -> Self { Self(MaybeUninit::uninit()) }
pub const fn new(value: T) -> Self {
Self(MaybeUninit::new(AlignedBuffer {
align: MaybeUninit::uninit(),
value,
}))
}
}
impl<T, A> Default for UninitBuffer<T, A> {
fn default() -> Self { Self::uninit() }
}
impl<T, A> Clone for UninitBuffer<T, A> {
fn clone(&self) -> Self { Self::default() }
}
unsafe impl<U, T, A> StorageWithCapacity<U> for UninitBuffer<T, A> {
fn with_capacity(capacity: usize) -> Self {
let max_capacity = size::<U, T, A>();
if capacity > max_capacity {
crate::raw::capacity::fixed_capacity_reserve_error(max_capacity, capacity)
}
Self::default()
}
#[inline]
#[doc(hidden)]
#[allow(non_snake_case)]
fn __with_capacity__const_capacity_checked(capacity: usize, old_capacity: Option<usize>) -> Self {
match old_capacity {
Some(old_capacity) if old_capacity <= size::<U, T, A>() => Self::default(),
_ => StorageWithCapacity::<U>::with_capacity(capacity),
}
}
}
unsafe impl<U, T, A> Storage<U> for UninitBuffer<T, A> {
#[doc(hidden)]
const CONST_CAPACITY: Option<usize> = Some(size::<U, T, A>());
const IS_ALIGNED: bool = align_of::<AlignedBuffer<T, A>>() >= align_of::<U>();
fn capacity(&self) -> usize { size::<U, T, A>() }
fn as_ptr(&self) -> *const U { self.0.as_ptr().cast() }
fn as_mut_ptr(&mut self) -> *mut U { self.0.as_mut_ptr().cast() }
fn reserve(&mut self, new_capacity: usize) {
let capacity = size::<U, T, A>();
if new_capacity > capacity {
crate::raw::capacity::fixed_capacity_reserve_error(capacity, new_capacity)
}
}
fn try_reserve(&mut self, capacity: usize) -> bool { capacity <= size::<U, T, A>() }
}