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}