bevy_platform/collections/aligned_vec.rs
1//! Provides [`AlignedVec`] based on [rkyv::util::AlignedVec](https://github.com/rkyv/rkyv/blob/main/rkyv/src/util/alloc/aligned_vec.rs)'s implementation but the alignment can be set at runtime.
2//!
3//! The original source code, adapted here, is copyright 2021 David Koloski, used here under the MIT License.
4#![expect(unsafe_code, reason = "This struct needs to interact with raw memory")]
5
6use alloc::alloc::{alloc, dealloc, handle_alloc_error, realloc};
7#[cfg(feature = "bytemuck")]
8use alloc::vec::Vec;
9use core::{
10 alloc::Layout,
11 borrow::{Borrow, BorrowMut},
12 fmt,
13 mem::ManuallyDrop,
14 ops::{Deref, DerefMut, Index, IndexMut},
15 ptr::NonNull,
16 slice,
17};
18
19/// A vector of bytes that dynamically aligns its memory to the specified alignment.
20///
21/// ```
22/// # use bevy_platform::collections::AlignedVec;
23/// let bytes = AlignedVec::with_capacity(4096, 1);
24/// assert_eq!(bytes.as_ptr().align_offset(4096), 0);
25/// ```
26pub struct AlignedVec {
27 ptr: NonNull<u8>,
28 align: usize,
29 cap: usize,
30 len: usize,
31}
32
33impl Drop for AlignedVec {
34 fn drop(&mut self) {
35 if self.cap != 0 {
36 // SAFETY: both `ptr` and `layout` are valid
37 unsafe {
38 dealloc(self.ptr.as_ptr(), self.layout());
39 }
40 }
41 }
42}
43
44impl AlignedVec {
45 /// The alignment of the vector
46 #[inline]
47 pub fn alignment(&self) -> usize {
48 self.align
49 }
50
51 /// Maximum valid size of [`Layout`].
52 ///
53 /// Dictated by the requirements of [`Layout::from_size_align`]:
54 /// `size`, when rounded up to the nearest multiple of `align`, must not overflow `isize`.
55 #[inline]
56 const fn max_size_for_alignment(align: usize) -> usize {
57 isize::MAX as usize + 1 - align
58 }
59
60 /// Maximum valid capacity of the vector with `self.align`.
61 #[inline]
62 fn max_capacity(&self) -> usize {
63 Self::max_size_for_alignment(self.alignment())
64 }
65
66 /// Constructs a new, empty `AlignedVec`.
67 ///
68 /// The vector will not allocate until elements are pushed into it.
69 ///
70 /// # Examples
71 /// ```
72 /// # use bevy_platform::collections::AlignedVec;
73 /// let mut vec = AlignedVec::new(16);
74 /// ```
75 #[inline]
76 pub fn new(align: usize) -> Self {
77 Self::with_capacity(align, 0)
78 }
79
80 /// Constructs a new, empty `AlignedVec` with the specified alignment and capacity.
81 ///
82 /// The vector will be able to hold exactly `capacity` bytes without
83 /// reallocating. If `capacity` is 0, the vector will not allocate.
84 ///
85 /// # Examples
86 /// ```
87 /// # use bevy_platform::collections::AlignedVec;
88 /// let mut vec = AlignedVec::with_capacity(16, 10);
89 ///
90 /// // The vector contains no items, even though it has capacity for more
91 /// assert_eq!(vec.len(), 0);
92 /// assert_eq!(vec.capacity(), 10);
93 ///
94 /// // These are all done without reallocating...
95 /// for i in 0..10 {
96 /// vec.push(i);
97 /// }
98 /// assert_eq!(vec.len(), 10);
99 /// assert_eq!(vec.capacity(), 10);
100 ///
101 /// // ...but this may make the vector reallocate
102 /// vec.push(11);
103 /// assert_eq!(vec.len(), 11);
104 /// assert!(vec.capacity() >= 11);
105 /// ```
106 #[inline]
107 pub fn with_capacity(align: usize, capacity: usize) -> Self {
108 assert!(align > 0, "align must be 1 or more");
109 assert!(align.is_power_of_two(), "align must be a power of 2");
110 // As `align` has to be a power of 2, this caps `align` at a max
111 // of `(isize::MAX + 1) / 2` (1 GiB on 32-bit systems).
112 assert!(
113 align < isize::MAX as usize,
114 "align must be less than isize::MAX"
115 );
116
117 if capacity == 0 {
118 Self {
119 ptr: NonNull::without_provenance(
120 // SAFETY: `align` is checked to be non-zero.
121 unsafe { core::num::NonZero::<usize>::new_unchecked(align) },
122 ),
123 align,
124 cap: 0,
125 len: 0,
126 }
127 } else {
128 assert!(
129 capacity <= Self::max_size_for_alignment(align),
130 "`capacity` when rounded up to the nearest multiple of align overflows `isize`"
131 );
132
133 let ptr = {
134 // SAFETY: align > 0, align is power of two and capacity <= max size for alignment.
135 let layout = unsafe { Layout::from_size_align_unchecked(capacity, align) };
136 // SAFETY: capacity is not zero.
137 let ptr = unsafe { alloc(layout) };
138 if ptr.is_null() {
139 handle_alloc_error(layout);
140 }
141 // SAFETY: ptr is not null
142 unsafe { NonNull::new_unchecked(ptr) }
143 };
144
145 Self {
146 ptr,
147 align,
148 cap: capacity,
149 len: 0,
150 }
151 }
152 }
153
154 #[inline]
155 fn layout(&self) -> Layout {
156 // SAFETY: `cap` and `align` are valid for layout
157 unsafe { Layout::from_size_align_unchecked(self.cap, self.alignment()) }
158 }
159
160 /// Clears the vector, removing all values.
161 ///
162 /// Note that this method has no effect on the allocated capacity of the
163 /// vector.
164 ///
165 /// # Examples
166 /// ```
167 /// # use bevy_platform::collections::AlignedVec;
168 /// let mut v = AlignedVec::new(16);
169 /// v.extend_from_slice(&[1, 2, 3, 4]);
170 ///
171 /// v.clear();
172 ///
173 /// assert!(v.is_empty());
174 /// ```
175 #[inline]
176 pub fn clear(&mut self) {
177 self.len = 0;
178 }
179
180 /// Change capacity of vector.
181 ///
182 /// Will set capacity to exactly `new_cap`.
183 /// Can be used to either grow or shrink capacity.
184 /// Backing memory will be reallocated.
185 ///
186 /// Usually the safe methods `reserve` or `reserve_exact` are a better
187 /// choice. This method only exists as a micro-optimization for very
188 /// performance-sensitive code where the calculation of capacity
189 /// required has already been performed, and you want to avoid doing it
190 /// again, or if you want to implement a different growth strategy.
191 ///
192 /// # Safety
193 ///
194 /// - `new_cap` when rounded up to the nearest multiple of align must not overflow `isize`
195 /// - `new_cap` must be greater than or equal to [`len()`](AlignedVec::len)
196 pub unsafe fn change_capacity(&mut self, new_cap: usize) {
197 debug_assert!(new_cap <= self.max_capacity());
198 debug_assert!(new_cap >= self.len);
199
200 if new_cap > 0 {
201 let new_ptr = if self.cap > 0 {
202 // SAFETY:
203 // - `self.ptr` is currently allocated because `self.cap` is
204 // greater than zero.
205 // - `self.layout()` always matches the layout used to allocate
206 // the current block of memory.
207 // - We checked that `new_cap` is greater than zero.
208 let new_ptr = unsafe { realloc(self.ptr.as_ptr(), self.layout(), new_cap) };
209 if new_ptr.is_null() {
210 // SAFETY:
211 // - `self.align` is always guaranteed to be a nonzero power
212 // of two.
213 // - We checked that `new_cap` doesn't overflow `isize` when
214 // rounded up to the nearest power of two.
215 let layout =
216 unsafe { Layout::from_size_align_unchecked(new_cap, self.alignment()) };
217 handle_alloc_error(layout);
218 }
219 new_ptr
220 } else {
221 // SAFETY:
222 // - `self.align` is always guaranteed to be a nonzero power of
223 // two.
224 // - We checked that `new_cap` doesn't overflow `isize` when
225 // rounded up to the nearest power of two.
226 let layout =
227 unsafe { Layout::from_size_align_unchecked(new_cap, self.alignment()) };
228 // SAFETY: We checked that `new_cap` has non-zero size.
229 let new_ptr = unsafe { alloc(layout) };
230 if new_ptr.is_null() {
231 handle_alloc_error(layout);
232 }
233 new_ptr
234 };
235 // SAFETY: We checked that `new_ptr` is non-null in each of the
236 // branches.
237 self.ptr = unsafe { NonNull::new_unchecked(new_ptr) };
238 self.cap = new_cap;
239 } else if self.cap > 0 {
240 // SAFETY: Because the capacity is nonzero, `self.ptr` points to a
241 // currently-allocated memory block. All memory blocks are allocated
242 // with a layout of `self.layout()`.
243 unsafe {
244 dealloc(self.ptr.as_ptr(), self.layout());
245 }
246 self.ptr = NonNull::without_provenance(
247 // SAFETY: `align` is checked to be non-zero.
248 unsafe { core::num::NonZero::<usize>::new_unchecked(self.alignment()) },
249 );
250 self.cap = 0;
251 }
252 }
253
254 /// Shrinks the capacity of the vector as much as possible.
255 ///
256 /// It will drop down as close as possible to the length but the allocator
257 /// may still inform the vector that there is space for a few more
258 /// elements.
259 ///
260 /// # Examples
261 /// ```
262 /// # use bevy_platform::collections::AlignedVec;
263 /// let mut vec = AlignedVec::with_capacity(16, 10);
264 /// vec.extend_from_slice(&[1, 2, 3]);
265 /// assert_eq!(vec.capacity(), 10);
266 /// vec.shrink_to_fit();
267 /// assert!(vec.capacity() >= 3);
268 ///
269 /// vec.clear();
270 /// vec.shrink_to_fit();
271 /// assert!(vec.capacity() == 0);
272 /// ```
273 #[inline]
274 pub fn shrink_to_fit(&mut self) {
275 if self.cap != self.len {
276 // SAFETY: New capacity is equal to length, and cannot exceed max as it's shrinking
277 unsafe { self.change_capacity(self.len) };
278 }
279 }
280
281 /// Returns an unsafe mutable pointer to the vector's buffer.
282 ///
283 /// The caller must ensure that the vector outlives the pointer this
284 /// function returns, or else it will end up pointing to garbage.
285 /// Modifying the vector may cause its buffer to be reallocated, which
286 /// would also make any pointers to it invalid.
287 ///
288 /// # Examples
289 /// ```
290 /// # use bevy_platform::collections::AlignedVec;
291 /// // Allocate 1-aligned vector big enough for 4 bytes.
292 /// let size = 4;
293 /// let mut x = AlignedVec::with_capacity(1, size);
294 /// let x_ptr = x.as_mut_ptr();
295 ///
296 /// // Initialize elements via raw pointer writes, then set length.
297 /// unsafe {
298 /// for i in 0..size {
299 /// *x_ptr.add(i) = i as u8;
300 /// }
301 /// x.set_len(size);
302 /// }
303 /// assert_eq!(&*x, &[0, 1, 2, 3]);
304 /// ```
305 #[inline]
306 pub fn as_mut_ptr(&mut self) -> *mut u8 {
307 self.ptr.as_ptr()
308 }
309
310 /// Extracts a mutable slice of the entire vector.
311 ///
312 /// Equivalent to `&mut s[..]`.
313 ///
314 /// # Examples
315 /// ```
316 /// # use bevy_platform::collections::AlignedVec;
317 /// let mut vec = AlignedVec::new(16);
318 /// vec.extend_from_slice(&[1, 2, 3, 4, 5]);
319 /// assert_eq!(vec.as_mut_slice().len(), 5);
320 /// for i in 0..5 {
321 /// assert_eq!(vec.as_mut_slice()[i], i as u8 + 1);
322 /// vec.as_mut_slice()[i] = i as u8;
323 /// assert_eq!(vec.as_mut_slice()[i], i as u8);
324 /// }
325 /// ```
326 #[inline]
327 pub fn as_mut_slice(&mut self) -> &mut [u8] {
328 // SAFETY: `ptr` and `len` are valid to construct slice
329 unsafe { slice::from_raw_parts_mut(self.ptr.as_ptr(), self.len) }
330 }
331
332 /// Returns a raw pointer to the vector's buffer.
333 ///
334 /// The caller must ensure that the vector outlives the pointer this
335 /// function returns, or else it will end up pointing to garbage.
336 /// Modifying the vector may cause its buffer to be reallocated, which
337 /// would also make any pointers to it invalid.
338 ///
339 /// The caller must also ensure that the memory the pointer
340 /// (non-transitively) points to is never written to (except inside an
341 /// `UnsafeCell`) using this pointer or any pointer derived from it. If
342 /// you need to mutate the contents of the slice, use
343 /// [`as_mut_ptr`](AlignedVec::as_mut_ptr).
344 ///
345 /// # Examples
346 /// ```
347 /// # use bevy_platform::collections::AlignedVec;
348 /// let mut x = AlignedVec::new(16);
349 /// x.extend_from_slice(&[1, 2, 4]);
350 /// let x_ptr = x.as_ptr();
351 ///
352 /// unsafe {
353 /// for i in 0..x.len() {
354 /// assert_eq!(*x_ptr.add(i), 1 << i);
355 /// }
356 /// }
357 /// ```
358 #[inline]
359 pub fn as_ptr(&self) -> *const u8 {
360 self.ptr.as_ptr()
361 }
362
363 /// Extracts a slice containing the entire vector.
364 ///
365 /// Equivalent to `&s[..]`.
366 ///
367 /// # Examples
368 /// ```
369 /// # use bevy_platform::collections::AlignedVec;
370 /// let mut vec = AlignedVec::new(16);
371 /// vec.extend_from_slice(&[1, 2, 3, 4, 5]);
372 /// assert_eq!(vec.as_slice().len(), 5);
373 /// for i in 0..5 {
374 /// assert_eq!(vec.as_slice()[i], i as u8 + 1);
375 /// }
376 /// ```
377 #[inline]
378 pub fn as_slice(&self) -> &[u8] {
379 // SAFETY: `ptr` and `len` are valid to construct slice
380 unsafe { slice::from_raw_parts(self.ptr.as_ptr(), self.len) }
381 }
382
383 /// Returns the number of elements the vector can hold without reallocating.
384 ///
385 /// # Examples
386 /// ```
387 /// # use bevy_platform::collections::AlignedVec;
388 /// let vec = AlignedVec::with_capacity(16, 10);
389 /// assert_eq!(vec.capacity(), 10);
390 /// ```
391 #[inline]
392 pub fn capacity(&self) -> usize {
393 self.cap
394 }
395
396 /// Reserves capacity for at least `additional` more bytes to be inserted
397 /// into the given `AlignedVec`. The collection may reserve more space
398 /// to avoid frequent reallocations. After calling `reserve`, capacity
399 /// will be greater than or equal to `self.len() + additional`. Does
400 /// nothing if capacity is already sufficient.
401 ///
402 /// # Panics
403 ///
404 /// Panics if the new capacity when rounded up to the nearest multiple of align overflow `isize`.
405 ///
406 /// # Examples
407 /// ```
408 /// # use bevy_platform::collections::AlignedVec;
409 ///
410 /// let mut vec = AlignedVec::new(16);
411 /// vec.push(1);
412 /// vec.reserve(10);
413 /// assert!(vec.capacity() >= 11);
414 /// ```
415 pub fn reserve(&mut self, additional: usize) {
416 // Cannot wrap because capacity always exceeds len,
417 // but avoids having to handle potential overflow here
418 let remaining = self.cap.wrapping_sub(self.len);
419 if additional > remaining {
420 self.do_reserve(additional);
421 }
422 }
423
424 /// Extend capacity after `reserve` has found it's necessary.
425 ///
426 /// Actually performing the extension is in this separate function marked
427 /// `#[cold]` to hint to compiler that this branch is not often taken.
428 /// This keeps the path for common case where capacity is already sufficient
429 /// as fast as possible, and makes `reserve` more likely to be inlined.
430 /// This is the same trick that Rust's `Vec::reserve` uses.
431 #[cold]
432 fn do_reserve(&mut self, additional: usize) {
433 let new_cap = self
434 .len
435 .checked_add(additional)
436 .expect("cannot reserve a larger AlignedVec");
437 // SAFETY: `do_reserve` is only called when capacity grows
438 unsafe { self.grow_capacity_to(new_cap) };
439 }
440
441 /// Grows total capacity of vector to `new_cap` or more.
442 ///
443 /// Capacity after this call will be `new_cap` rounded up to next power of
444 /// 2, unless that would exceed maximum capacity, in which case capacity
445 /// is capped at the maximum.
446 ///
447 /// This is same growth strategy used by `reserve`, `push` and
448 /// `extend_from_slice`.
449 ///
450 /// Usually the safe methods `reserve` or `reserve_exact` are a better
451 /// choice. This method only exists as a micro-optimization for very
452 /// performance-sensitive code where the calculation of capacity
453 /// required has already been performed, and you want to avoid doing it
454 /// again.
455 ///
456 /// Maximum capacity is `isize::MAX + 1 - self.align` bytes.
457 ///
458 /// # Panics
459 ///
460 /// Panics if the new capacity when rounded up to the nearest multiple of align overflow `isize`.
461 ///
462 /// # Safety
463 ///
464 /// - `new_cap` must be greater than current
465 /// [`capacity()`](AlignedVec::capacity)
466 ///
467 /// # Examples
468 /// ```
469 /// # use bevy_platform::collections::AlignedVec;
470 ///
471 /// let mut vec = AlignedVec::new(16);
472 /// vec.push(1);
473 /// unsafe { vec.grow_capacity_to(50) };
474 /// assert_eq!(vec.len(), 1);
475 /// assert_eq!(vec.capacity(), 64);
476 /// ```
477 pub unsafe fn grow_capacity_to(&mut self, new_cap: usize) {
478 debug_assert!(new_cap > self.cap);
479
480 let new_cap = if new_cap > (isize::MAX as usize + 1) >> 1 {
481 // Rounding up to next power of 2 would result in `isize::MAX + 1`
482 // or higher, which exceeds max capacity. So cap at max
483 // instead.
484 assert!(
485 new_cap <= self.max_capacity(),
486 "cannot reserve a larger AlignedVec"
487 );
488 self.max_capacity()
489 } else {
490 // Cannot overflow due to check above
491 new_cap.next_power_of_two()
492 };
493 let min_non_zero_cap = 8;
494 let new_cap = core::cmp::max(new_cap, min_non_zero_cap);
495 // SAFETY: We just checked that `new_cap` is greater than or equal to
496 // `len` and less than or equal to `max_capacity`.
497 unsafe {
498 self.change_capacity(new_cap);
499 }
500 }
501
502 /// Resizes the Vec in-place so that len is equal to `new_len`.
503 ///
504 /// If `new_len` is greater than len, the Vec is extended by the difference,
505 /// with each additional slot filled with value. If `new_len` is less than
506 /// len, the Vec is simply truncated.
507 ///
508 /// # Panics
509 ///
510 /// Panics if the new length when rounded up to the nearest multiple of align overflow `isize`.
511 ///
512 /// # Examples
513 /// ```
514 /// # use bevy_platform::collections::AlignedVec;
515 ///
516 /// let mut vec = AlignedVec::new(16);
517 /// vec.push(3);
518 /// vec.resize(3, 2);
519 /// assert_eq!(vec.as_slice(), &[3, 2, 2]);
520 ///
521 /// let mut vec = AlignedVec::new(16);
522 /// vec.extend_from_slice(&[1, 2, 3, 4]);
523 /// vec.resize(2, 0);
524 /// assert_eq!(vec.as_slice(), &[1, 2]);
525 /// ```
526 pub fn resize(&mut self, new_len: usize, value: u8) {
527 if new_len > self.len {
528 let additional = new_len - self.len;
529 self.reserve(additional);
530 // SAFETY: ptr is valid to write after `reserve`
531 unsafe {
532 core::ptr::write_bytes(self.ptr.as_ptr().add(self.len), value, additional);
533 }
534 }
535 // SAFETY: required elements are initialized for `new_len`
536 unsafe {
537 self.set_len(new_len);
538 }
539 }
540
541 /// Returns `true` if the vector contains no elements.
542 ///
543 /// # Examples
544 /// ```
545 /// # use bevy_platform::collections::AlignedVec;
546 ///
547 /// let mut v = Vec::new();
548 /// assert!(v.is_empty());
549 ///
550 /// v.push(1);
551 /// assert!(!v.is_empty());
552 /// ```
553 #[inline]
554 pub fn is_empty(&self) -> bool {
555 self.len == 0
556 }
557
558 /// Returns the number of elements in the vector, also referred to as its
559 /// 'length'.
560 ///
561 /// # Examples
562 /// ```
563 /// # use bevy_platform::collections::AlignedVec;
564 ///
565 /// let mut a = AlignedVec::new(16);
566 /// a.extend_from_slice(&[1, 2, 3]);
567 /// assert_eq!(a.len(), 3);
568 /// ```
569 #[inline]
570 pub fn len(&self) -> usize {
571 self.len
572 }
573
574 /// Consumes and leaks the `AlignedVec`, returning a mutable reference to
575 /// the contents, `&'static mut [u8]`.
576 ///
577 /// This method does not reallocate or shrink the `AlignedVec`, so the
578 /// leaked allocation may include unused capacity that is not part of the
579 /// returned slice.
580 ///
581 /// This function is mainly useful for data that lives for the remainder of
582 /// the program's life. Dropping the returned reference will cause a memory
583 /// leak.
584 ///
585 /// # Examples
586 ///
587 /// Simple usage:
588 ///
589 /// ```
590 /// # use std::alloc::{Layout, dealloc};
591 /// # use bevy_platform::collections::AlignedVec;
592 ///
593 /// let mut x = AlignedVec::new(16);
594 /// x.extend_from_slice(&[1, 2, 3]);
595 /// # let layout = Layout::from_size_align(x.capacity(), 16).unwrap();
596 /// let static_ref: &'static mut [u8] = x.leak();
597 /// static_ref[0] += 1;
598 /// assert_eq!(static_ref, &[2, 2, 3]);
599 /// # // Need to manually dealloc to avoid triggering Miri's leak check
600 /// # unsafe {
601 /// # dealloc(static_ref.as_mut_ptr(), layout);
602 /// # }
603 /// ```
604 pub fn leak(self) -> &'static mut [u8] {
605 let mut me = ManuallyDrop::new(self);
606 // SAFETY: `ptr` and `len` are valid to construct slice
607 unsafe { slice::from_raw_parts_mut(me.as_mut_ptr(), me.len) }
608 }
609
610 /// Copies and appends all bytes in a slice to the `AlignedVec`.
611 ///
612 /// The elements of the slice are appended in-order.
613 ///
614 /// # Examples
615 /// ```
616 /// # use bevy_platform::collections::AlignedVec;
617 ///
618 /// let mut vec = AlignedVec::new(16);
619 /// vec.push(1);
620 /// vec.extend_from_slice(&[2, 3, 4]);
621 /// assert_eq!(vec.as_slice(), &[1, 2, 3, 4]);
622 /// ```
623 pub fn extend_from_slice(&mut self, other: &[u8]) {
624 self.reserve(other.len());
625 // SAFETY: memory is reserved for copy
626 unsafe {
627 core::ptr::copy_nonoverlapping(
628 other.as_ptr(),
629 self.as_mut_ptr().add(self.len()),
630 other.len(),
631 );
632 }
633 self.len += other.len();
634 }
635
636 /// Removes the last element from a vector and returns it, or `None` if it
637 /// is empty.
638 ///
639 /// # Examples
640 /// ```
641 /// # use bevy_platform::collections::AlignedVec;
642 ///
643 /// let mut vec = AlignedVec::new(16);
644 /// vec.extend_from_slice(&[1, 2, 3]);
645 /// assert_eq!(vec.pop(), Some(3));
646 /// assert_eq!(vec.as_slice(), &[1, 2]);
647 /// ```
648 #[inline]
649 pub fn pop(&mut self) -> Option<u8> {
650 if self.len == 0 {
651 None
652 } else {
653 let result = self[self.len - 1];
654 self.len -= 1;
655 Some(result)
656 }
657 }
658
659 /// Appends an element to the back of a collection.
660 ///
661 /// # Panics
662 ///
663 /// Panics if the new capacity when rounded up to the nearest multiple of align overflow `isize`.
664 ///
665 /// # Examples
666 /// ```
667 /// # use bevy_platform::collections::AlignedVec;
668 ///
669 /// let mut vec = AlignedVec::new(16);
670 /// vec.extend_from_slice(&[1, 2]);
671 /// vec.push(3);
672 /// assert_eq!(vec.as_slice(), &[1, 2, 3]);
673 /// ```
674 #[inline]
675 pub fn push(&mut self, value: u8) {
676 if self.len == self.cap {
677 self.reserve_for_push();
678 }
679
680 // SAFETY: memory is reserved for writing.
681 unsafe {
682 self.as_mut_ptr().add(self.len).write(value);
683 self.len += 1;
684 }
685 }
686
687 /// Extend capacity by at least 1 byte after `push` has found it's
688 /// necessary.
689 ///
690 /// Actually performing the extension is in this separate function marked
691 /// `#[cold]` to hint to compiler that this branch is not often taken.
692 /// This keeps the path for common case where capacity is already sufficient
693 /// as fast as possible, and makes `push` more likely to be inlined.
694 /// This is the same trick that Rust's `Vec::push` uses.
695 #[cold]
696 fn reserve_for_push(&mut self) {
697 // `len` is always less than `isize::MAX`, so no possibility of overflow
698 // here
699 let new_cap = self.len + 1;
700 // SAFETY: `reserve_for_push` is only called when capacity grows
701 unsafe { self.grow_capacity_to(new_cap) };
702 }
703
704 /// Reserves the minimum capacity for exactly `additional` more elements to
705 /// be inserted in the given `AlignedVec`. After calling
706 /// `reserve_exact`, capacity will be greater than or equal
707 /// to `self.len() + additional`. Does nothing if the capacity is already
708 /// sufficient.
709 ///
710 /// Note that the allocator may give the collection more space than it
711 /// requests. Therefore, capacity can not be relied upon to be precisely
712 /// minimal. Prefer reserve if future insertions are expected.
713 ///
714 /// # Panics
715 ///
716 /// Panics if the new capacity when rounded up to the nearest multiple of align overflow `isize`.
717 ///
718 /// # Examples
719 /// ```
720 /// # use bevy_platform::collections::AlignedVec;
721 ///
722 /// let mut vec = AlignedVec::new(16);
723 /// vec.push(1);
724 /// vec.reserve_exact(10);
725 /// assert!(vec.capacity() >= 11);
726 /// ```
727 pub fn reserve_exact(&mut self, additional: usize) {
728 // This function does not use the hot/cold paths trick that `reserve`
729 // and `push` do, on assumption that user probably knows this will
730 // require an increase in capacity. Otherwise, they'd likely use
731 // `reserve`.
732 let new_cap = self
733 .len
734 .checked_add(additional)
735 .expect("cannot reserve a larger AlignedVec");
736 if new_cap > self.cap {
737 assert!(
738 new_cap <= self.max_capacity(),
739 "cannot reserve a larger AlignedVec"
740 );
741 // SAFETY: `new_cap` is `self.len + additional` thus it is >= `self.len`
742 unsafe { self.change_capacity(new_cap) };
743 }
744 }
745
746 /// Forces the length of the vector to `new_len`.
747 ///
748 /// This is a low-level operation that maintains none of the normal
749 /// invariants of the type.
750 ///
751 /// # Safety
752 ///
753 /// - `new_len` must be less than or equal to
754 /// [`capacity()`](AlignedVec::capacity)
755 /// - The elements at `old_len..new_len` must be initialized
756 ///
757 /// # Examples
758 /// ```
759 /// # use bevy_platform::collections::AlignedVec;
760 /// let mut vec = AlignedVec::with_capacity(16, 3);
761 /// vec.extend_from_slice(&[1, 2, 3]);
762 ///
763 /// // SAFETY:
764 /// // 1. `old_len..0` is empty to no elements need to be initialized.
765 /// // 2. `0 <= capacity` always holds whatever capacity is.
766 /// unsafe {
767 /// vec.set_len(0);
768 /// }
769 /// ```
770 pub unsafe fn set_len(&mut self, new_len: usize) {
771 debug_assert!(new_len <= self.capacity());
772
773 self.len = new_len;
774 }
775
776 /// Converts the vector into `Vec<T>`.
777 ///
778 /// Panics if any of the following assertions fail:
779 /// ```rust,ignore
780 /// assert!(align_of::<T>() == self.alignment());
781 /// assert!(self.len().is_multiple_of(size_of::<T>()));
782 /// assert!(self.capacity().is_multiple_of(size_of::<T>()));
783 /// ```
784 ///
785 /// # Examples
786 /// ```
787 /// # use bevy_platform::collections::AlignedVec;
788 /// let mut v = AlignedVec::new(2);
789 /// v.extend_from_slice(&[1, 2, 3, 4]);
790 ///
791 /// let vec: Vec<u16> = v.into_vec();
792 /// assert_eq!(vec.len(), 2);
793 /// assert_eq!(vec.as_slice(), &[513, 1027]);
794 /// ```
795 #[cfg(feature = "bytemuck")]
796 pub fn into_vec<T: bytemuck::AnyBitPattern>(self) -> Vec<T> {
797 const {
798 assert!(size_of::<T>() != 0);
799 }
800 assert!(align_of::<T>() == self.alignment());
801 assert!(self.len().is_multiple_of(size_of::<T>()));
802 assert!(self.capacity().is_multiple_of(size_of::<T>()));
803 let (ptr, _align, len, cap) = self.into_raw_parts();
804 // SAFETY: the raw parts from `self` are valid to be used as `Vec`
805 unsafe {
806 Vec::from_raw_parts(
807 ptr.cast::<T>().as_ptr(),
808 len / size_of::<T>(),
809 cap / size_of::<T>(),
810 )
811 }
812 }
813
814 /// Casts the vector to a slice of `T`.
815 ///
816 /// Panics:
817 /// * If `T` has a greater alignment requirement than the `AlignedVec`.
818 /// * If the size of `AlignedVec` is not a multiple of `size_of::<T>()`
819 #[cfg(feature = "bytemuck")]
820 pub fn cast_slice<T: bytemuck::AnyBitPattern>(&self) -> &[T] {
821 assert!(align_of::<T>() <= self.alignment());
822 bytemuck::cast_slice(self.as_slice())
823 }
824
825 /// Casts the vector to a mutable slice of `T`.
826 ///
827 /// Panics:
828 /// * If `T` has a greater alignment requirement than the `AlignedVec`.
829 /// * If the size of `AlignedVec` is not a multiple of `size_of::<T>()`
830 #[cfg(feature = "bytemuck")]
831 pub fn cast_slice_mut<T: bytemuck::AnyBitPattern + bytemuck::NoUninit>(&mut self) -> &mut [T] {
832 assert!(align_of::<T>() <= self.alignment());
833 bytemuck::cast_slice_mut(self.as_mut_slice())
834 }
835
836 /// Decompose an [`AlignedVec`] into its raw components: `(NonNull pointer, align,
837 /// length, capacity)`.
838 ///
839 /// The returned parts can be used to re-assemble the [`AlignedVec`] using
840 /// the [`from_raw_parts`](AlignedVec::from_raw_parts) function.
841 ///
842 /// After calling this function, the caller is responsible for the memory
843 /// previously managed by the [`AlignedVec`]. The only way to do this is
844 /// to convert the [`NonNull`] pointer, the length and the capacity back
845 /// into an [`AlignedVec`] using the [`from_raw_parts`](AlignedVec::from_raw_parts)
846 /// function, allowing the destructor to perform the cleanup.
847 ///
848 /// # Example
849 ///
850 /// ```
851 /// use bevy_platform::collections::AlignedVec;
852 ///
853 /// let mut v: AlignedVec = AlignedVec::new(16);
854 /// for i in 1..=5 {
855 /// v.push(i);
856 /// }
857 ///
858 /// let (ptr, align, len, cap) = v.into_raw_parts();
859 ///
860 /// let rebuilt: AlignedVec =
861 /// unsafe { AlignedVec::from_raw_parts(ptr, align, len, cap) };
862 /// assert_eq!(rebuilt.as_slice(), &[1, 2, 3, 4, 5]);
863 /// ```
864 #[must_use = "losing the pointer will leak memory"]
865 pub fn into_raw_parts(self) -> (NonNull<u8>, usize, usize, usize) {
866 let this = ManuallyDrop::new(self);
867 (this.ptr, this.align, this.len, this.cap)
868 }
869
870 /// Create an [`AlignedVec`] directly from a [`NonNull`] pointer, a length
871 /// and a capacity.
872 ///
873 /// # Safety
874 ///
875 /// This is highly unsafe, due to the number of invariants that aren't
876 /// checked:
877 ///
878 /// * `align` must be a non-zero power of two, and must be less than
879 /// `isize::MAX`.
880 /// * `capacity`, when rounded up to the nearest multiple of `align`, must
881 /// not overflow `isize`.
882 /// * If the capacity is nonzero, `ptr` must have been allocated using
883 /// the global allocator, such as via the [`alloc::alloc`] function,
884 /// with a [`Layout`] using this exact `align` and a `size` of `capacity`.
885 /// (Because similar to alignment, [`dealloc`] must be called with the
886 /// same layout `size`.)
887 /// * If the capacity is zero, `ptr` need not point to allocated memory,
888 /// but it must still be aligned to `align` bytes (i.e.
889 /// `ptr.as_ptr() as usize % align == 0`).
890 /// * `length` needs to be less than or equal to `capacity`.
891 ///
892 /// # Example
893 ///
894 /// ```
895 /// use bevy_platform::collections::AlignedVec;
896 ///
897 /// let mut v: AlignedVec = AlignedVec::new(16);
898 /// for i in 1..=5 {
899 /// v.push(i);
900 /// }
901 ///
902 /// let (ptr, align, len, cap) = v.into_raw_parts();
903 ///
904 /// let rebuilt: AlignedVec =
905 /// unsafe { AlignedVec::from_raw_parts(ptr, align, len, cap) };
906 /// assert_eq!(rebuilt.as_slice(), &[1, 2, 3, 4, 5]);
907 /// ```
908 pub unsafe fn from_raw_parts(ptr: NonNull<u8>, align: usize, len: usize, cap: usize) -> Self {
909 Self {
910 ptr,
911 align,
912 len,
913 cap,
914 }
915 }
916}
917
918impl AsMut<[u8]> for AlignedVec {
919 fn as_mut(&mut self) -> &mut [u8] {
920 self.as_mut_slice()
921 }
922}
923
924impl AsRef<[u8]> for AlignedVec {
925 fn as_ref(&self) -> &[u8] {
926 self.as_slice()
927 }
928}
929
930impl Borrow<[u8]> for AlignedVec {
931 fn borrow(&self) -> &[u8] {
932 self.as_slice()
933 }
934}
935
936impl BorrowMut<[u8]> for AlignedVec {
937 fn borrow_mut(&mut self) -> &mut [u8] {
938 self.as_mut_slice()
939 }
940}
941
942impl Clone for AlignedVec {
943 fn clone(&self) -> Self {
944 let mut result = Self::with_capacity(self.align, self.len);
945 result.len = self.len;
946 // SAFETY: Both pointers are valid to do full copy and not overlap
947 unsafe { core::ptr::copy_nonoverlapping(self.as_ptr(), result.as_mut_ptr(), self.len) };
948 result
949 }
950}
951
952impl fmt::Debug for AlignedVec {
953 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
954 self.as_slice().fmt(f)
955 }
956}
957
958impl Deref for AlignedVec {
959 type Target = [u8];
960
961 fn deref(&self) -> &Self::Target {
962 self.as_slice()
963 }
964}
965
966impl DerefMut for AlignedVec {
967 fn deref_mut(&mut self) -> &mut Self::Target {
968 self.as_mut_slice()
969 }
970}
971
972impl<I: slice::SliceIndex<[u8]>> Index<I> for AlignedVec {
973 type Output = <I as slice::SliceIndex<[u8]>>::Output;
974
975 fn index(&self, index: I) -> &Self::Output {
976 &self.as_slice()[index]
977 }
978}
979
980impl<I: slice::SliceIndex<[u8]>> IndexMut<I> for AlignedVec {
981 fn index_mut(&mut self, index: I) -> &mut Self::Output {
982 &mut self.as_mut_slice()[index]
983 }
984}
985
986#[cfg(feature = "bytemuck")]
987impl<T: bytemuck::NoUninit> From<Vec<T>> for AlignedVec {
988 fn from(value: Vec<T>) -> Self {
989 let (ptr, len, cap) = value.into_raw_parts();
990 // SAFETY: `ptr` from `Vec` is non-null
991 let ptr = unsafe { NonNull::new_unchecked(ptr.cast::<u8>()) };
992 // SAFETY: the raw parts from `Vec` are valid to be used as `AlignedVec`
993 unsafe {
994 AlignedVec::from_raw_parts(
995 ptr,
996 align_of::<T>(),
997 len * size_of::<T>(),
998 cap * size_of::<T>(),
999 )
1000 }
1001 }
1002}
1003
1004// SAFETY: `AlignedVec`, like `Vec<u8>`, is safe to send to another thread
1005unsafe impl Send for AlignedVec {}
1006
1007// SAFETY: `AlignedVec`, like `Vec<u8>`, is safe to share between threads
1008unsafe impl Sync for AlignedVec {}
1009
1010impl Unpin for AlignedVec {}