#[cfg(feature = "alloc")]
extern crate alloc as _alloc;
#[cfg(feature = "alloc")]
use _alloc::alloc::{self,Layout};
use core::fmt::Display;
use core::mem;
use core::ptr::NonNull;
pub struct RawVec<T> {
pub ptr: NonNull<T>,
pub cap: usize,
}
#[inline(always)]
#[cfg(feature = "alloc")]
const fn next_cap(cap: usize) -> usize {
if cap == 0 { 1 } else { cap * 2 }
}
impl<T: Sized> RawVec<T> {
pub fn new() -> Self {
let cap = if mem::size_of::<T>() == 0 { isize::MAX } else { 0 };
Self {
ptr: NonNull::dangling(),
cap: cap as usize,
}
}
}
#[derive(Debug,Clone,Copy,PartialEq)]
pub enum ResizeError {
#[cfg(feature = "alloc")]
AllocationError(Layout),
#[cfg(not(feature = "alloc"))]
AllocNotSupported,
CapacityOverflow,
AllocationExceedsMaximun,
}
impl Display for ResizeError {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
match self {
#[cfg(feature = "alloc")]
ResizeError::AllocationError(layout) => write!(f, "Allocation error for layout ({layout:?})"),
#[cfg(not(feature = "alloc"))]
ResizeError::AllocNotSupported => write!(f, "Alloc is not supported"),
ResizeError::CapacityOverflow => write!(f, "Capacity overflow"),
ResizeError::AllocationExceedsMaximun => write!(f, "Allocation size exceeds maximun"),
}
}
}
impl core::error::Error for ResizeError {}
impl ResizeError {
pub (crate) fn handle(&self) -> ! {
#[cfg(feature = "alloc")]
if let Self::AllocationError(layout) = self {
alloc::handle_alloc_error(*layout)
}
#[cfg(not(feature = "alloc"))]
if let Self::AllocNotSupported = self {
panic!("Alloc is not enabled. Can't switch the buffer to the heap")
}
panic!("Fatal error: {self:?}");
}
}
#[cfg(feature = "alloc")]
impl<T: Sized> RawVec<T> {
pub fn try_with_capacity(cap: usize) -> Result<Self,ResizeError> {
let mut vec = Self::new();
if mem::size_of::<T>() != 0 {
vec.resize_buffer(cap)?;
}
Ok(vec)
}
fn resize_buffer(&mut self, new_cap: usize) -> Result<(), ResizeError> {
if mem::size_of::<T>() == 0 {
return Err(ResizeError::CapacityOverflow)
}
let Ok(new_layout) = Layout::array::<T>(new_cap) else {
return Err(ResizeError::AllocationExceedsMaximun);
};
if new_layout.size() > isize::MAX as usize {
return Err(ResizeError::AllocationExceedsMaximun);
}
let new_ptr = if self.cap == 0 {
unsafe { alloc::alloc(new_layout) }
} else {
let old_layout = Layout::array::<T>(self.cap).unwrap();
let ptr = self.ptr.as_ptr() as *mut u8;
unsafe { alloc::realloc(ptr, old_layout, new_layout.size()) }
};
if new_ptr.is_null() {
return Err(ResizeError::AllocationError(new_layout))
}
self.cap = new_cap;
self.ptr = unsafe { NonNull::new_unchecked(new_ptr as *mut T) };
Ok(())
}
pub fn try_expand_if_needed(&mut self, len: usize, n: usize) -> Result<(), ResizeError> {
if len == self.cap {
let mut new_cap = self.cap;
while new_cap - len < n {
new_cap = next_cap(new_cap);
}
self.resize_buffer(new_cap)?;
}
Ok(())
}
#[inline]
pub fn try_expand_if_needed_exact(&mut self, len: usize, n: usize) -> Result<(), ResizeError> {
if len == self.cap {
self.resize_buffer(n)?;
}
Ok(())
}
pub fn shrink_to_fit(&mut self, len: usize) {
self.resize_buffer(len).unwrap_or_else(|err| err.handle());
}
pub unsafe fn destroy(&mut self) {
if self.cap != 0 && mem::size_of::<T>() != 0 {
let layout = Layout::array::<T>(self.cap).unwrap();
unsafe {
let ptr = self.ptr.as_ptr() as *mut u8;
alloc::dealloc(ptr, layout);
}
}
}
}
#[cfg(not(feature = "alloc"))]
#[allow(unused)]
impl<T: Sized> RawVec<T> {
pub fn try_with_capacity(cap: usize) -> Result<Self,ResizeError> {
panic!("Alloc is not enabled. Can't switch the buffer to the heap")
}
fn resize_buffer(&mut self, new_cap: usize) {
panic!("Alloc is not enabled. Can't switch the buffer to the heap")
}
pub fn try_expand_if_needed(&mut self, len: usize, n: usize) -> Result<(), ResizeError> {
Err(ResizeError::AllocNotSupported)
}
#[inline]
pub fn try_expand_if_needed_exact(&mut self, len: usize, n: usize) -> Result<(), ResizeError> {
Err(ResizeError::AllocNotSupported)
}
pub fn shrink_to_fit(&mut self, len: usize) {
panic!("Alloc is not enabled. Can't switch the buffer to the heap")
}
pub unsafe fn destroy(&mut self) {
panic!("Alloc is not enabled. Can't switch the buffer to the heap")
}
}
impl<T: Sized> Clone for RawVec<T> {
fn clone(&self) -> Self {
*self
}
}
impl<T: Sized> Copy for RawVec<T> { }
impl<T> Default for RawVec<T> {
fn default() -> Self {
Self::new()
}
}