#[cfg(feature = "alloc")]
use alloc::{boxed::Box, vec::Vec};
use core::{cell::UnsafeCell, marker::PhantomData, mem::MaybeUninit, ops::Range, ptr::NonNull, slice};
#[cfg(feature = "alloc")]
use core::{mem::forget, ptr};
pub unsafe trait Storage {
    type Item: Sized;
    fn len(&self) -> usize;
    fn is_empty(&self) -> bool {
        self.len() == 0
    }
    fn as_ptr(&self) -> *const MaybeUninit<Self::Item> {
        self.as_mut_ptr().cast_const()
    }
    fn as_mut_ptr(&self) -> *mut MaybeUninit<Self::Item>;
    unsafe fn slice(&self, range: Range<usize>) -> &[MaybeUninit<Self::Item>] {
        slice::from_raw_parts(self.as_ptr().add(range.start), range.len())
    }
    #[allow(clippy::mut_from_ref)]
    unsafe fn slice_mut(&self, range: Range<usize>) -> &mut [MaybeUninit<Self::Item>] {
        slice::from_raw_parts_mut(self.as_mut_ptr().add(range.start), range.len())
    }
}
pub struct Ref<'a, T> {
    _ghost: PhantomData<&'a mut [T]>,
    ptr: *mut MaybeUninit<T>,
    len: usize,
}
unsafe impl<'a, T> Send for Ref<'a, T> where T: Sync {}
unsafe impl<'a, T> Sync for Ref<'a, T> where T: Sync {}
unsafe impl<'a, T> Storage for Ref<'a, T> {
    type Item = T;
    #[inline]
    fn as_mut_ptr(&self) -> *mut MaybeUninit<T> {
        self.ptr
    }
    #[inline]
    fn len(&self) -> usize {
        self.len
    }
}
impl<'a, T> From<&'a mut [MaybeUninit<T>]> for Ref<'a, T> {
    fn from(value: &'a mut [MaybeUninit<T>]) -> Self {
        Self {
            _ghost: PhantomData,
            ptr: value.as_mut_ptr(),
            len: value.len(),
        }
    }
}
impl<'a, T> From<Ref<'a, T>> for &'a mut [MaybeUninit<T>] {
    fn from(value: Ref<'a, T>) -> Self {
        unsafe { slice::from_raw_parts_mut(value.ptr, value.len) }
    }
}
pub struct Owning<T: ?Sized> {
    data: UnsafeCell<T>,
}
unsafe impl<T: ?Sized> Sync for Owning<T> where T: Sync {}
impl<T> From<T> for Owning<T> {
    fn from(value: T) -> Self {
        Self::new(value)
    }
}
impl<T> Owning<T> {
    pub const fn new(value: T) -> Self {
        Self {
            data: UnsafeCell::new(value),
        }
    }
}
pub type Array<T, const N: usize> = Owning<[MaybeUninit<T>; N]>;
unsafe impl<T, const N: usize> Storage for Array<T, N> {
    type Item = T;
    #[inline]
    fn as_mut_ptr(&self) -> *mut MaybeUninit<T> {
        self.data.get() as *mut _
    }
    #[inline]
    fn len(&self) -> usize {
        N
    }
}
impl<T, const N: usize> From<Array<T, N>> for [MaybeUninit<T>; N] {
    fn from(value: Array<T, N>) -> Self {
        value.data.into_inner()
    }
}
pub type Slice<T> = Owning<[MaybeUninit<T>]>;
unsafe impl<T> Storage for Slice<T> {
    type Item = T;
    #[inline]
    fn as_mut_ptr(&self) -> *mut MaybeUninit<T> {
        self.data.get() as *mut _
    }
    #[inline]
    fn len(&self) -> usize {
        unsafe { NonNull::new_unchecked(self.data.get()) }.len()
    }
}
#[cfg(feature = "alloc")]
pub struct Heap<T> {
    ptr: *mut MaybeUninit<T>,
    len: usize,
}
#[cfg(feature = "alloc")]
unsafe impl<T> Send for Heap<T> where T: Send {}
#[cfg(feature = "alloc")]
unsafe impl<T> Sync for Heap<T> where T: Sync {}
#[cfg(feature = "alloc")]
unsafe impl<T> Storage for Heap<T> {
    type Item = T;
    #[inline]
    fn as_mut_ptr(&self) -> *mut MaybeUninit<T> {
        self.ptr
    }
    #[inline]
    fn len(&self) -> usize {
        self.len
    }
}
#[cfg(feature = "alloc")]
impl<T> Heap<T> {
    pub fn new(capacity: usize) -> Self {
        Self {
            ptr: Vec::<T>::with_capacity(capacity).leak() as *mut _ as *mut MaybeUninit<T>,
            len: capacity,
        }
    }
}
#[cfg(feature = "alloc")]
impl<T> From<Vec<MaybeUninit<T>>> for Heap<T> {
    fn from(mut value: Vec<MaybeUninit<T>>) -> Self {
        let len = value.capacity();
        let ptr = value.as_mut_ptr();
        forget(value);
        Self { ptr, len }
    }
}
#[cfg(feature = "alloc")]
impl<T> From<Box<[MaybeUninit<T>]>> for Heap<T> {
    fn from(value: Box<[MaybeUninit<T>]>) -> Self {
        Self {
            len: value.len(),
            ptr: Box::into_raw(value) as *mut MaybeUninit<T>,
        }
    }
}
#[cfg(feature = "alloc")]
impl<T> From<Heap<T>> for Box<[MaybeUninit<T>]> {
    fn from(value: Heap<T>) -> Self {
        unsafe { Box::from_raw(ptr::slice_from_raw_parts_mut(value.ptr, value.len)) }
    }
}
#[cfg(feature = "alloc")]
impl<T> Drop for Heap<T> {
    fn drop(&mut self) {
        drop(unsafe { Box::from_raw(ptr::slice_from_raw_parts_mut(self.ptr, self.len)) });
    }
}