tiny_vec/
raw.rs

1#[cfg(feature = "alloc")]
2extern crate alloc as _alloc;
3#[cfg(feature = "alloc")]
4use _alloc::alloc::{self,Layout};
5
6use core::fmt::Display;
7use core::mem;
8use core::ptr::NonNull;
9
10pub struct RawVec<T> {
11    pub ptr: NonNull<T>,
12    pub cap: usize,
13}
14
15/// Returns the next capacity value
16#[inline(always)]
17#[cfg(feature = "alloc")]
18const fn next_cap(cap: usize) -> usize {
19    if cap == 0 { 1 } else { cap * 2 }
20}
21
22impl<T: Sized> RawVec<T> {
23    pub fn new() -> Self {
24        let cap = if mem::size_of::<T>() == 0 { isize::MAX } else { 0 };
25        Self {
26            ptr: NonNull::dangling(),
27            cap: cap as usize,
28        }
29    }
30}
31
32/// Represents an error when trying to allocate memory
33#[derive(Debug,Clone,Copy,PartialEq)]
34pub enum ResizeError {
35    #[cfg(feature = "alloc")]
36    AllocationError(Layout),
37    #[cfg(not(feature = "alloc"))]
38    AllocNotSupported,
39    CapacityOverflow,
40    AllocationExceedsMaximun,
41}
42
43impl Display for ResizeError {
44    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
45        match self {
46            #[cfg(feature = "alloc")]
47            ResizeError::AllocationError(layout) => write!(f, "Allocation error for layout ({layout:?})"),
48            #[cfg(not(feature = "alloc"))]
49            ResizeError::AllocNotSupported => write!(f, "Alloc is not supported"),
50            ResizeError::CapacityOverflow => write!(f, "Capacity overflow"),
51            ResizeError::AllocationExceedsMaximun => write!(f, "Allocation size exceeds maximun"),
52        }
53    }
54}
55
56impl core::error::Error for ResizeError {}
57
58impl ResizeError {
59    pub (crate) fn handle(&self) -> ! {
60        #[cfg(feature = "alloc")]
61        if let Self::AllocationError(layout) = self {
62            alloc::handle_alloc_error(*layout)
63        }
64        #[cfg(not(feature = "alloc"))]
65        if let Self::AllocNotSupported = self {
66            panic!("Alloc is not enabled. Can't switch the buffer to the heap")
67        }
68        panic!("Fatal error: {self:?}");
69    }
70}
71
72#[cfg(feature = "alloc")]
73impl<T: Sized> RawVec<T> {
74    pub fn try_with_capacity(cap: usize) -> Result<Self,ResizeError> {
75        let mut vec = Self::new();
76        if mem::size_of::<T>() != 0 {
77            vec.resize_buffer(cap)?;
78        }
79        Ok(vec)
80    }
81    fn resize_buffer(&mut self, new_cap: usize) -> Result<(), ResizeError> {
82        // since we set the capacity to usize::MAX when T has size 0,
83        // getting to here necessarily means the Vec is overfull.
84        if mem::size_of::<T>() == 0 {
85            return Err(ResizeError::CapacityOverflow)
86        }
87
88        let Ok(new_layout) = Layout::array::<T>(new_cap) else {
89            return Err(ResizeError::AllocationExceedsMaximun);
90        };
91        if new_layout.size() > isize::MAX as usize {
92            return Err(ResizeError::AllocationExceedsMaximun);
93        }
94
95        let new_ptr = if self.cap == 0 {
96            unsafe { alloc::alloc(new_layout) }
97        } else {
98            let old_layout = Layout::array::<T>(self.cap).unwrap();
99            let ptr = self.ptr.as_ptr() as *mut u8;
100            unsafe { alloc::realloc(ptr, old_layout, new_layout.size()) }
101        };
102        if new_ptr.is_null() {
103            return Err(ResizeError::AllocationError(new_layout))
104        }
105
106        self.cap = new_cap;
107        self.ptr = unsafe { NonNull::new_unchecked(new_ptr as *mut T) };
108
109        Ok(())
110    }
111    pub fn try_expand_if_needed(&mut self, len: usize, n: usize) -> Result<(), ResizeError> {
112        if len == self.cap {
113            let mut new_cap = self.cap;
114            while new_cap - len < n {
115                new_cap = next_cap(new_cap);
116            }
117            self.resize_buffer(new_cap)?;
118        }
119        Ok(())
120    }
121    #[inline]
122    pub fn try_expand_if_needed_exact(&mut self, len: usize, n: usize) -> Result<(), ResizeError> {
123        if len == self.cap {
124            self.resize_buffer(n)?;
125        }
126        Ok(())
127    }
128
129    pub fn shrink_to_fit(&mut self, len: usize) {
130        self.resize_buffer(len).unwrap_or_else(|err| err.handle());
131    }
132    pub unsafe fn destroy(&mut self) {
133        if self.cap != 0 && mem::size_of::<T>() != 0 {
134            let layout = Layout::array::<T>(self.cap).unwrap();
135            unsafe {
136                let ptr = self.ptr.as_ptr() as *mut u8;
137                alloc::dealloc(ptr, layout);
138            }
139        }
140    }
141}
142
143#[cfg(not(feature = "alloc"))]
144#[allow(unused)]
145impl<T: Sized> RawVec<T> {
146    pub fn try_with_capacity(cap: usize) -> Result<Self,ResizeError> {
147        panic!("Alloc is not enabled. Can't switch the buffer to the heap")
148    }
149    fn resize_buffer(&mut self, new_cap: usize) {
150        panic!("Alloc is not enabled. Can't switch the buffer to the heap")
151    }
152
153    pub fn try_expand_if_needed(&mut self, len: usize, n: usize) -> Result<(), ResizeError> {
154        Err(ResizeError::AllocNotSupported)
155    }
156    #[inline]
157    pub fn try_expand_if_needed_exact(&mut self, len: usize, n: usize) -> Result<(), ResizeError> {
158        Err(ResizeError::AllocNotSupported)
159    }
160
161    pub fn shrink_to_fit(&mut self, len: usize) {
162        panic!("Alloc is not enabled. Can't switch the buffer to the heap")
163    }
164    pub unsafe fn destroy(&mut self) {
165        panic!("Alloc is not enabled. Can't switch the buffer to the heap")
166    }
167}
168
169impl<T: Sized> Clone for RawVec<T> {
170    fn clone(&self) -> Self {
171        *self
172    }
173}
174
175impl<T: Sized> Copy for RawVec<T> { }
176
177impl<T> Default for RawVec<T> {
178    fn default() -> Self {
179        Self::new()
180    }
181}