dync/
vec_void.rs

1//! This module defines a barebones internal API
2//! for representing `Vec`s using a void pointer and explicit type infomration about each element.
3
4use std::mem::{align_of, size_of, ManuallyDrop, MaybeUninit};
5
6use crate::elem::*;
7
8/// A decomposition of a `Vec` into a void pointer, a length and a capacity.
9///
10/// This type exposes a purely internal API since it has no mechanisms for dropping
11/// non-copy elements. For a `Vec` type handling copy types, use `VecCopy`.
12///
13/// This type leaks memory, it is meant to be dropped by a containing type.
14#[derive(Debug)]
15pub struct VecVoid {
16    /// Owned pointer.
17    pub(crate) ptr: *mut (),
18    /// Vector length.
19    pub(crate) len: usize,
20    /// Vector capacity.
21    pub(crate) cap: usize,
22    /// Information about the type of elements stored in this vector.
23    pub(crate) elem: ElemInfo,
24}
25
26// This implements a shallow clone, which is sufficient for VecCopy, but not for VecDrop.
27impl Clone for VecVoid {
28    fn clone(&self) -> Self {
29        fn clone<T: 'static + Clone>(buf: &VecVoid) -> VecVoid {
30            // SAFETY: Memory layout is ensured to be correct by eval_align.
31            unsafe {
32                // Copy all pointers and data from buf. This causes temporary
33                // aliasing.  This is safe because in the following we don't
34                // modify the original Vec in any way or make any calls to
35                // alloc/dealloc. We use mut here solely for the purpose
36                // of constructing a `Vec` from a `VoidVec` in order to use
37                // `Vec`s clone method.
38                let out = VecVoid {
39                    ptr: buf.ptr,
40                    len: buf.len,
41                    cap: buf.cap,
42                    elem: buf.elem,
43                };
44                // Next we clone this new VecVoid. This is basically a memcpy
45                // of the internal data into a new heap block.
46                let v = ManuallyDrop::new(out.into_aligned_vec_unchecked::<T>());
47
48                // Ensure that the capacity is preserved.
49                let mut new_v = Vec::with_capacity(v.capacity());
50                new_v.clone_from(&v);
51
52                VecVoid::from_vec_override(new_v, buf.elem)
53            }
54        }
55        eval_align!(self.elem.alignment; clone::<_>(self))
56    }
57
58    fn clone_from(&mut self, source: &Self) {
59        fn clone_from<T: 'static + Clone>(out: &mut VecVoid, source: &VecVoid) {
60            // SAFETY: Memory layout is ensured to be correct by eval_align.
61            unsafe {
62                // Same technique as in `clone`, see comments there.
63                let src = VecVoid {
64                    ptr: source.ptr,
65                    len: source.len,
66                    cap: source.cap,
67                    elem: source.elem,
68                };
69                let src = ManuallyDrop::new(src.into_aligned_vec_unchecked::<T>());
70                out.apply_aligned_unchecked(|out: &mut Vec<T>| out.clone_from(&src))
71            }
72        }
73        eval_align!(self.elem.alignment; clone_from::<_>(self, source))
74    }
75}
76
77impl Default for VecVoid {
78    fn default() -> Self {
79        let v: Vec<()> = Vec::new();
80        VecVoid::from_vec(v)
81    }
82}
83
84impl VecVoid {
85    /// Returns the length of this vector.
86    pub(crate) fn len(&self) -> usize {
87        self.len
88    }
89
90    /// Returns true if this vector is empty and false otherwise.
91    pub(crate) fn is_empty(&self) -> bool {
92        self.len == 0
93    }
94
95    /// Returns the capacity of this vector.
96    pub(crate) fn capacity(&self) -> usize {
97        self.cap
98    }
99
100    /// Converts the given `Vec<T>` into a `ManuallyDrop` version with the expected allocation
101    /// strategy.
102    #[inline]
103    fn into_valid_vec<T: 'static>(v: Vec<T>) -> ManuallyDrop<Vec<T>> {
104        // IMPORTANT:
105        // When v has no capacity, then we can't ensure that pushing to it will keep capacity T aligned.
106        // So here we push an uninitialized item to it to ensure that capacity will be properly tracked.
107        // For this reason converting a Vec to VecVoid causes additional allocations if v is non-empty.
108        // Not doing the reserve step below _may_ cause a panic when pushing to a VecVoid.
109        let mut v = ManuallyDrop::new(v);
110        if v.capacity() == 0 {
111            v.reserve(1);
112        }
113        v
114    }
115
116    /// Converts a typed `Vec<T>` into a `VecVoid`.
117    ///
118    /// If the given `Vec<T>` has no capacity, this function allocates capacity for (at least) a single element
119    /// to ensure proper memory alignment in the future.
120    #[inline]
121    pub(crate) fn from_vec<T: 'static>(v: Vec<T>) -> Self {
122        let mut v = Self::into_valid_vec(v);
123        VecVoid {
124            ptr: v.as_mut_ptr() as *mut (),
125            len: v.len(),
126            cap: v.capacity(),
127            elem: ElemInfo::new::<T>(),
128        }
129    }
130
131    /// Converts a typed `Vec<T>` into a `VecVoid` while oeverriding the element info of `T` with the
132    /// given element info.
133    ///
134    /// This function expects `v` to have non-zero capacity. Otherwise we cannot ensure that future
135    /// allocations will be element aligned with the original type.
136    ///
137    /// # Safety
138    ///
139    /// The given element info must be consistently sized and aligned with `T`.
140    ///
141    /// # Panics
142    ///
143    /// This function panics if the length of capacity of `v` is not a multiple of the given element size.
144    /// It also panics if the capacity of `v` is not large enough to contain one element specified by `elem`.
145    #[inline]
146    pub(crate) unsafe fn from_vec_override<T: 'static>(v: Vec<T>, elem: ElemInfo) -> Self {
147        let mut v = ManuallyDrop::new(v);
148
149        let velem = ElemInfo::new::<T>();
150        assert_eq!(velem.alignment, elem.alignment);
151
152        assert!(v.capacity() >= elem.size);
153
154        assert_eq!(v.len() * velem.size % elem.size, 0);
155
156        let len = v.len() * velem.size / elem.size;
157
158        // This check ensures that capacity has been increased at the correct increment, which
159        // may not be true if VecVoid starts off with no capacity to begin with.
160        assert_eq!(v.capacity() * velem.size % elem.size, 0);
161
162        let cap = v.capacity() * velem.size / elem.size;
163        VecVoid {
164            ptr: v.as_mut_ptr() as *mut (),
165            len,
166            cap,
167            elem,
168        }
169    }
170
171    /// Apply a function to this vector as if it was a `Vec<T>` where `T` has
172    /// the same alignment as the type this vector was created with.
173    #[inline]
174    pub(crate) unsafe fn apply_aligned_unchecked<T: 'static, U>(
175        &mut self,
176        f: impl FnOnce(&mut Vec<T>) -> U,
177    ) -> U {
178        let orig_elem = self.elem;
179        let mut v = std::mem::take(self).into_aligned_vec_unchecked::<T>();
180        let out = f(&mut v); // May allocate/deallocate
181                             // Returned default VecVoid value can be safely ignored
182        let _ = std::mem::replace(self, VecVoid::from_vec_override(v, orig_elem));
183        out
184    }
185
186    /// Apply a function to this vector as if it was a `Vec<T>` where `T` is
187    /// the same as the type this vector was created with.
188    #[inline]
189    pub(crate) unsafe fn apply_unchecked<T: 'static, U>(
190        &mut self,
191        f: impl FnOnce(&mut Vec<T>) -> U,
192    ) -> U {
193        let mut v = std::mem::take(self).into_vec_unchecked::<T>();
194        let out = f(&mut v); // May allocate/deallocate
195                             // Returned default VecVoid can be safely ignored.
196        let _ = std::mem::replace(self, VecVoid::from_vec(v));
197        out
198    }
199
200    #[inline]
201    pub(crate) fn clear(&mut self) {
202        fn clear<T: 'static>(buf: &mut VecVoid) {
203            // SAFETY: Memory layout is ensured to be correct by eval_align.
204            unsafe {
205                buf.apply_aligned_unchecked(|v: &mut Vec<T>| {
206                    v.clear();
207                })
208            };
209        }
210        eval_align!(self.elem.alignment; clear::<_>(self));
211    }
212
213    /// Reserve `additional` extra elements.
214    #[inline]
215    pub(crate) fn reserve(&mut self, additional: usize) {
216        fn reserve<T: 'static>(buf: &mut VecVoid, additional: usize) {
217            let size = buf.elem.size;
218            // SAFETY: Memory layout is ensured to be correct by eval_align.
219            unsafe {
220                buf.apply_aligned_unchecked(|v: &mut Vec<T>| {
221                    v.reserve(additional * size);
222                })
223            };
224        }
225        eval_align!(self.elem.alignment; reserve::<_>(self, additional));
226    }
227
228    #[inline]
229    pub(crate) fn truncate(&mut self, new_len: usize) {
230        fn truncate<T: 'static>(buf: &mut VecVoid, new_len: usize) {
231            let size = buf.elem.size;
232            // SAFETY: Memory layout is ensured to be correct by eval_align.
233            unsafe {
234                buf.apply_aligned_unchecked(|v: &mut Vec<T>| {
235                    v.truncate(new_len * size);
236                })
237            };
238        }
239        eval_align!(self.elem.alignment; truncate::<_>(self, new_len));
240    }
241
242    #[inline]
243    pub(crate) fn append(&mut self, other: &mut VecVoid) {
244        fn append<T: 'static>(buf: &mut VecVoid, other: &mut VecVoid) {
245            // SAFETY: Memory layout is ensured to be correct by eval_align.
246            unsafe {
247                buf.apply_aligned_unchecked(|target: &mut Vec<T>| {
248                    other.apply_aligned_unchecked(|source: &mut Vec<T>| {
249                        target.append(source);
250                    });
251                });
252            }
253        }
254
255        // Ensure that the two Vec types are the same.
256        assert_eq!(self.elem.type_id, other.elem.type_id);
257        debug_assert_eq!(self.elem.alignment, other.elem.alignment);
258        debug_assert_eq!(self.elem.size, other.elem.size);
259
260        eval_align!(self.elem.alignment; append::<_>(self, other));
261    }
262
263    #[inline]
264    pub(crate) fn push(&mut self, val: &[MaybeUninit<u8>]) {
265        fn push<T: 'static + Copy>(buf: &mut VecVoid, val: &[MaybeUninit<u8>]) {
266            // SAFETY: Memory layout is ensured to be correct by eval_align.
267            unsafe {
268                buf.apply_aligned_unchecked(|v: &mut Vec<T>| {
269                    // SAFETY: T here is one of the T# so it's copy. The
270                    // following is effectively a move and doesn't rely on the
271                    // "actual" type being Copy.
272                    let val_t = *(val.as_ptr() as *const T);
273                    v.push(val_t);
274                });
275            }
276        }
277
278        eval_align!(self.elem.alignment; push::<_>(self, val));
279    }
280
281    /// Resize this `VecVoid` using a given per element initializer.
282    #[cfg(feature = "traits")]
283    #[inline]
284    pub(crate) unsafe fn resize_with<I>(&mut self, len: usize, init: I)
285    where
286        I: FnOnce(&mut [MaybeUninit<u8>]),
287    {
288        fn resize_with<T: 'static + Default + Copy + std::fmt::Debug, Init>(
289            buf: &mut VecVoid,
290            len: usize,
291            init: Init,
292        ) where
293            Init: FnOnce(&mut [MaybeUninit<u8>]),
294        {
295            let size = buf.elem.size;
296            let num_bytes = buf.elem.num_bytes();
297            // SAFETY: Memory layout is ensured to be correct by eval_align.
298            unsafe {
299                buf.apply_aligned_unchecked(|v: &mut Vec<T>| {
300                    // SAFETY: T here is one of the T# so it's copy.
301                    let orig_len = v.len();
302                    v.resize_with(len * size, Default::default);
303                    let byte_slice = std::slice::from_raw_parts_mut(
304                        (&mut v[orig_len..]).as_mut_ptr() as *mut MaybeUninit<u8>,
305                        num_bytes,
306                    );
307                    init(byte_slice);
308                });
309            }
310        }
311
312        eval_align!(self.elem.alignment; resize_with::<_, I>(self, len, init));
313    }
314
315    #[inline]
316    pub(crate) fn rotate_left(&mut self, n: usize) {
317        fn rotate_left<T: 'static>(buf: &mut VecVoid, n: usize) {
318            let size = buf.elem.size;
319            // SAFETY: Memory layout is ensured to be correct by eval_align.
320            unsafe {
321                buf.apply_aligned_unchecked(|v: &mut Vec<T>| {
322                    v.rotate_left(n * size);
323                });
324            }
325        }
326
327        eval_align!(limited_stack, self.elem.alignment; rotate_left::<_>(self, n));
328    }
329
330    #[inline]
331    pub(crate) fn rotate_right(&mut self, n: usize) {
332        fn rotate_right<T: 'static>(buf: &mut VecVoid, n: usize) {
333            let size = buf.elem.size;
334            // SAFETY: Memory layout is ensured to be correct by eval_align.
335            unsafe {
336                buf.apply_aligned_unchecked(|v: &mut Vec<T>| {
337                    v.rotate_right(n * size);
338                });
339            }
340        }
341
342        eval_align!(limited_stack, self.elem.alignment; rotate_right::<_>(self, n));
343    }
344
345    /// Cast this vector into a `Vec<T>` where `T` is alignment sized.
346    ///
347    /// # Safety
348    ///
349    /// Trying to interpret the values contained in the underlying `Vec` can
350    /// cause undefined behavior, however truncating and reserving space is
351    /// valid so long as `T` has the same alignment as `self.elem.alignment`.
352    /// This is checked in debug builds.
353    pub(crate) unsafe fn into_aligned_vec_unchecked<T>(self) -> Vec<T> {
354        let mut md = ManuallyDrop::new(self);
355        ManuallyDrop::into_inner(Self::aligned_vec_unchecked(&mut md))
356    }
357
358    /// Cast this vector into a `Vec<T>` where `T` is alignment sized.
359    ///
360    /// # Safety
361    ///
362    /// Trying to interpret the values contained in the underlying `Vec` can
363    /// cause undefined behavior, however truncating and reserving space is
364    /// valid so long as `T` has the same alignment as `self.elem.alignment`.
365    /// This is checked in debug builds.
366    pub(crate) unsafe fn aligned_vec_unchecked<T>(&mut self) -> ManuallyDrop<Vec<T>> {
367        debug_assert_eq!(size_of::<T>(), self.elem.alignment);
368        debug_assert_eq!(align_of::<T>(), self.elem.alignment);
369        let len = self.len * self.elem.size;
370        let cap = self.cap * self.elem.size;
371        // Make sure the Vec isn't dropped, otherwise it will cause a double
372        // free since self is still valid.
373        ManuallyDrop::new(Vec::from_raw_parts(self.ptr as *mut T, len, cap))
374    }
375
376    /// Cast this vector into a `Vec<T>`.
377    ///
378    /// # Safety
379    ///
380    /// Trying to interpret the values contained in the underlying `Vec` can
381    /// cause undefined behavior, however truncating and reserving space is
382    /// valid so long as `T` has the same size and alignment as given by
383    /// `self.elem`.  This is checked in debug builds.
384    pub(crate) unsafe fn into_vec_unchecked<T>(self) -> Vec<T> {
385        debug_assert_eq!(size_of::<T>(), self.elem.num_bytes());
386        debug_assert_eq!(align_of::<T>(), self.elem.alignment);
387        let md = ManuallyDrop::new(self);
388        Vec::from_raw_parts(md.ptr as *mut T, md.len, md.cap)
389    }
390}
391
392impl Drop for VecVoid {
393    fn drop(&mut self) {
394        fn drop_vec<T>(buf: &mut VecVoid) {
395            unsafe {
396                let _ = ManuallyDrop::into_inner(buf.aligned_vec_unchecked::<T>());
397            }
398        }
399        eval_align!(self.elem.alignment; drop_vec::<_>(self));
400    }
401}
402
403#[cfg(test)]
404mod tests {
405    use super::*;
406
407    #[test]
408    fn rotate() {
409        let mut v = VecVoid::from_vec(vec![1u32, 2, 3]);
410        v.rotate_left(2);
411        unsafe {
412            assert_eq!(v.clone().into_vec_unchecked::<u32>(), vec![3, 1, 2]);
413        }
414        v.rotate_right(1);
415        unsafe {
416            assert_eq!(v.clone().into_vec_unchecked::<u32>(), vec![2, 3, 1]);
417        }
418    }
419
420    #[test]
421    fn clone_from() {
422        let a = VecVoid::from_vec(vec![1u32, 2, 3]);
423        let mut b = VecVoid::from_vec(Vec::<u32>::new());
424        b.clone_from(&a);
425        assert_eq!(a.len, b.len);
426        // Capacity may be different.
427        assert_eq!(a.elem, b.elem);
428        assert_ne!(a.ptr, b.ptr); // Different memory since this is a clone
429    }
430}