tux_owned_alloc/
raw_vec.rs

1use super::{AllocErr, LayoutErr, RawVecErr, UninitAlloc};
2use std::{
3    alloc::{alloc, dealloc, handle_alloc_error, realloc, Layout},
4    fmt,
5    marker::PhantomData,
6    mem,
7    ptr::NonNull,
8    slice,
9};
10
11/// Raw Vector allocation. This allocation, instead of holding a pointer to a
12/// single `T`, holds a pointer to as many `T` are required. The allocation is
13/// resizable and is freed on `drop`. No initialization or deinitialization of
14/// the elements is performed. This type may be useful for `Vec`-like types. If
15/// the size of the allocation is zero, no allocation is performed and a
16/// dangling pointer is used (just like in `std`). For the drop checker, the
17/// type acts as if it contains a `T` due to usage of `PhantomData<T>`.
18///
19/// ```rust
20/// extern crate owned_alloc;
21///
22/// use owned_alloc::RawVec;
23///
24/// let mut vec = RawVec::<usize>::with_capacity(200);
25/// assert_eq!(200, vec.cap());
26/// assert_eq!(200, unsafe { vec.as_slice().len() });
27///
28/// vec.resize(354);
29/// assert_eq!(354, vec.cap());
30/// assert_eq!(354, unsafe { vec.as_slice().len() });
31/// ```
32pub struct RawVec<T> {
33    nnptr: NonNull<T>,
34    cap: usize,
35    _marker: PhantomData<T>,
36}
37
38impl<T> Default for RawVec<T> {
39    fn default() -> Self {
40        Self::new()
41    }
42}
43
44impl<T> RawVec<T> {
45    /// Creates a new `RawVec` of capacity `0` and a dangling pointer. No
46    /// allocation is performed.
47    pub fn new() -> Self {
48        Self { nnptr: NonNull::dangling(), cap: 0, _marker: PhantomData }
49    }
50
51
52    /// Creates a new `RawVec` with a given capacity. In case of allocation
53    /// error, the handler registered via stdlib is called. In case of overflow
54    /// calculating the total size, the function panics.
55    pub fn with_capacity(cap: usize) -> Self {
56        match Self::try_with_capacity(cap) {
57            Ok(this) => this,
58            Err(RawVecErr::Alloc(err)) => handle_alloc_error(err.layout),
59            Err(RawVecErr::Layout(err)) => {
60                panic!("Capacity overflows memory size: {}", err)
61            }
62        }
63    }
64
65    /// Creates a new `RawVec` with a given capacity. In case of allocation
66    /// error or overflow calculating the total size, `Err` is returned.
67    pub fn try_with_capacity(cap: usize) -> Result<Self, RawVecErr> {
68        let layout = Self::make_layout(cap)?;
69        let res = if layout.size() == 0 {
70            Ok(NonNull::dangling())
71        } else {
72            NonNull::new(unsafe { alloc(layout) })
73                .map(NonNull::cast::<T>)
74                .ok_or_else(|| AllocErr { layout }.into())
75        };
76
77        res.map(|nnptr| Self { nnptr, cap, _marker: PhantomData })
78    }
79
80    /// Creates a `RawVec` from a plain old standard library `Vec`. Beware, only
81    /// the pointer and the capacity are saved. The length is discarded. If you
82    /// want to keep track of the length, you will have to store it for
83    /// yourself. Note also that no element is dropped (ever) by the
84    /// `RawVec`.
85    ///
86    /// # Safety
87    /// This function is `unsafe` because there are no guarantees that `Vec` and
88    /// `RawVec` allocate in the same way. They probably do in the Rust version
89    /// you are using, but there are no future guarantees.
90    pub unsafe fn from_vec(mut vec: Vec<T>) -> Self {
91        let this = Self {
92            nnptr: NonNull::new_unchecked(vec.as_mut_ptr()),
93            cap: vec.capacity(),
94            _marker: PhantomData,
95        };
96        mem::forget(vec);
97        this
98    }
99
100    /// Recreate the `RawVec` from a raw non-null pointer and a capacity.
101    ///
102    /// # Safety
103    /// This functions is `unsafe` because passing the wrong pointer leads to
104    /// undefined behaviour. Passing wrong capacity also leads to undefined
105    /// behaviour.
106    pub unsafe fn from_raw_parts(nnptr: NonNull<T>, cap: usize) -> Self {
107        Self { nnptr, cap, _marker: PhantomData }
108    }
109
110    /// Recreate the `RawVec` from a raw non-null pointer to a slice with length
111    /// equal to the `RawVec`'s capacity.
112    ///
113    /// # Safety
114    /// This functions is `unsafe` because passing the wrong pointer leads to
115    /// undefined behaviour, including passing a pointer with the wrong length.
116    pub unsafe fn from_raw_slice(mut raw: NonNull<[T]>) -> Self {
117        Self {
118            nnptr: NonNull::new_unchecked(raw.as_mut().as_mut_ptr()),
119            cap: raw.as_ref().len(),
120            _marker: PhantomData,
121        }
122    }
123
124    /// The requested allocation capacity. It is guaranteed to be the capacity
125    /// passed to the last capacity-modifier method. Those are
126    /// `with_capacity`, `try_with_capacity` and `resize`. The methods `new`
127    /// and `try_new` initialize the capacity to `0`.
128    pub fn cap(&self) -> usize {
129        self.cap
130    }
131
132    /// The raw non-null pointer to the first element.
133    pub fn raw(&self) -> NonNull<T> {
134        self.nnptr
135    }
136
137    /// The raw non-null pointer to the slice with length equal to the
138    /// `RawVec`'s capacity.
139    pub fn raw_slice(&self) -> NonNull<[T]> {
140        unsafe { NonNull::from(self.as_slice()) }
141    }
142
143    /// "Forgets" dropping the allocation and returns a raw non-null pointer to
144    /// the slice with length equal to the `RawVec`'s capacity.
145    pub fn into_raw_slice(self) -> NonNull<[T]> {
146        let ptr = self.raw_slice();
147        mem::forget(self);
148        ptr
149    }
150
151    /// Encodes the `RawVec` as an immutable reference to a slice with length
152    /// equal to the capacity.
153    ///
154    /// # Safety
155    /// This function is `unsafe` because if the index of an uninitialized
156    /// element is accessed incorrectly, undefined behavior occurs.
157    pub unsafe fn as_slice(&self) -> &[T] {
158        slice::from_raw_parts(self.nnptr.as_ptr(), self.cap())
159    }
160
161    /// Encodes the `RawVec` as an mutable reference to a slice with length
162    /// equal to the capacity.
163    ///
164    /// # Safety
165    /// This function is `unsafe` because if the index of an uninitialized
166    /// element is accessed incorrectly, undefined behavior occurs.
167    pub unsafe fn as_mut_slice(&mut self) -> &mut [T] {
168        slice::from_raw_parts_mut(self.nnptr.as_ptr(), self.cap())
169    }
170
171    /// Creates a plain old standard library `Vec` from the `RawVec` and a given
172    /// length.
173    ///
174    /// # Safety
175    /// This function is `unsafe` because there are no guarantees that `Vec` and
176    /// `RawVec` allocate in the same way. They probably do in the Rust version
177    /// you are using, but there are no future guarantees. Also, the length
178    /// argument must be passed correctly, since the elements until the given
179    /// length will be considered correctly, but the `RawVec` initialize no
180    /// element.
181    pub unsafe fn into_vec(self, len: usize) -> Vec<T> {
182        let vec = Vec::from_raw_parts(self.nnptr.as_ptr(), len, self.cap);
183        mem::forget(self);
184        vec
185    }
186
187    /// Resizes the `RawVec` with a given capacity. In case of allocation
188    /// error, the handler registered via stdlib is called. In case of overflow
189    /// calculating the total size, the function panics.
190    pub fn resize(&mut self, new_cap: usize) {
191        match self.try_resize(new_cap) {
192            Err(RawVecErr::Alloc(err)) => handle_alloc_error(err.layout),
193            Err(RawVecErr::Layout(err)) => {
194                panic!("Capacity overflows memory size: {}", err)
195            }
196
197            Ok(_) => (),
198        }
199    }
200
201    /// Resizes the `RawVec` with a given capacity. In case of allocation
202    /// error or overflow calculating the total size, `Err` is returned. In case
203    /// of failure, the original allocation is untouched.
204    pub fn try_resize(&mut self, new_cap: usize) -> Result<(), RawVecErr> {
205        let layout = Self::make_layout(new_cap)?;
206
207        let res = if layout.size() == 0 {
208            self.free();
209            Ok(NonNull::dangling())
210        } else {
211            let old = Self::make_layout(self.cap).unwrap();
212            NonNull::new(unsafe {
213                realloc(self.nnptr.cast().as_ptr(), old, layout.size())
214            })
215                .map(NonNull::cast::<T>)
216                .ok_or_else(|| AllocErr { layout }.into())
217        };
218
219        res.map(|nnptr| {
220            self.nnptr = nnptr;
221            self.cap = new_cap;
222        })
223    }
224
225    fn free(&self) {
226        if self.cap != 0 && mem::size_of::<T>() != 0 {
227            let layout = Self::make_layout(self.cap).unwrap();
228            unsafe {
229                dealloc(self.nnptr.cast().as_ptr(), layout);
230            }
231        }
232    }
233
234    fn make_layout(cap: usize) -> Result<Layout, LayoutErr> {
235        let total_size =
236            mem::size_of::<T>().checked_mul(cap).ok_or(LayoutErr)?;
237        Layout::from_size_align(total_size, mem::align_of::<T>())
238            .map_err(Into::into)
239    }
240}
241
242impl<T> fmt::Debug for RawVec<T> {
243    fn fmt(&self, fmtr: &mut fmt::Formatter) -> fmt::Result {
244        write!(
245            fmtr,
246            "RawVec {{ pointer {:?}, cap: {} }}",
247            self.nnptr, self.cap
248        )
249    }
250}
251
252impl<T> Drop for RawVec<T> {
253    fn drop(&mut self) {
254        self.free();
255    }
256}
257
258impl<T> From<UninitAlloc<T>> for RawVec<T> {
259    fn from(alloc: UninitAlloc<T>) -> Self {
260        Self { nnptr: alloc.into_raw(), cap: 1, _marker: PhantomData }
261    }
262}
263
264unsafe impl<T> Send for RawVec<T> where T: Send {}
265
266unsafe impl<T> Sync for RawVec<T> where T: Sync {}
267
268#[cfg(test)]
269mod test {
270    use super::RawVec;
271
272    #[test]
273    fn cap_is_the_one_passed() {
274        let mut alloc = RawVec::<usize>::with_capacity(20);
275        assert_eq!(alloc.cap(), 20);
276
277        alloc.resize(50);
278        assert_eq!(alloc.cap(), 50);
279
280        alloc.resize(5);
281        assert_eq!(alloc.cap(), 5);
282    }
283
284    #[test]
285    fn from_into_std_vec() {
286        let vec = unsafe { RawVec::<u128>::with_capacity(465).into_vec(0) };
287        assert_eq!(vec.capacity(), 465);
288        let raw = unsafe { RawVec::from_vec(vec) };
289        assert_eq!(raw.cap(), 465);
290    }
291}