Skip to main content

vortex_buffer/
buffer_mut.rs

1// SPDX-License-Identifier: Apache-2.0
2// SPDX-FileCopyrightText: Copyright the Vortex contributors
3
4use core::mem::MaybeUninit;
5use std::alloc::Layout;
6use std::any::type_name;
7use std::cmp::max;
8use std::fmt::Debug;
9use std::fmt::Formatter;
10use std::ops::Deref;
11use std::ops::DerefMut;
12
13use itertools::Itertools;
14use vortex_error::VortexExpect;
15use vortex_error::vortex_panic;
16
17use crate::Alignment;
18use crate::Allocation;
19use crate::Buffer;
20use crate::BufferAllocatorRef;
21use crate::ByteBufferMut;
22use crate::debug::TruncatedDebug;
23use crate::trusted_len::TrustedLen;
24
25/// A mutable buffer that maintains a runtime-defined alignment through resizing operations.
26///
27/// Zero-sized element types are rejected at compile time when constructing a buffer.
28///
29/// ```compile_fail
30/// use vortex_buffer::BufferMut;
31/// let _ = BufferMut::<()>::empty();
32/// ```
33///
34/// ```compile_fail
35/// use vortex_buffer::BufferMut;
36/// let _ = BufferMut::<()>::zeroed(3);
37/// ```
38pub struct BufferMut<T> {
39    /// The owned allocation, including any bytes before `ptr` used for alignment.
40    pub(crate) allocation: Allocation,
41    /// The first element, aligned to `alignment`; it may dangle for an empty buffer.
42    pub(crate) ptr: std::ptr::NonNull<T>,
43    /// The number of initialized `T` values starting at `ptr`.
44    pub(crate) length: usize,
45    /// The number of `T` values that fit from `ptr`.
46    pub(crate) capacity: usize,
47    /// The minimum alignment maintained for `ptr` across reallocations.
48    pub(crate) alignment: Alignment,
49    /// Marks the buffer as logically owning values of `T` despite storing an erased allocation.
50    pub(crate) _marker: std::marker::PhantomData<T>,
51}
52
53// SAFETY: BufferMut uniquely owns its allocation and only exposes T across threads.
54unsafe impl<T: Send> Send for BufferMut<T> {}
55// SAFETY: shared access to BufferMut only exposes shared access to T.
56unsafe impl<T: Sync> Sync for BufferMut<T> {}
57
58impl<T> BufferMut<T> {
59    /// Create a new `BufferMut` with the requested alignment and capacity.
60    pub fn with_capacity(capacity: usize) -> Self {
61        Self::with_capacity_in(capacity, BufferAllocatorRef::statically_allocated())
62    }
63
64    /// Create a new `BufferMut` with the requested capacity and allocator.
65    pub fn with_capacity_in(capacity: usize, allocator: BufferAllocatorRef) -> Self {
66        Self::with_capacity_aligned_in(capacity, Alignment::of::<T>(), allocator)
67    }
68
69    /// Create a new `BufferMut` with the requested alignment and capacity.
70    ///
71    /// The allocation is over-aligned to [`Alignment::DEFAULT_ALIGNMENT`] when that is larger than
72    /// `alignment`. Use [`with_capacity_preferred_aligned`] to control the over-alignment.
73    ///
74    /// [`with_capacity_preferred_aligned`]: Self::with_capacity_preferred_aligned
75    pub fn with_capacity_aligned(capacity: usize, alignment: Alignment) -> Self {
76        Self::with_capacity_aligned_in(
77            capacity,
78            alignment,
79            BufferAllocatorRef::statically_allocated(),
80        )
81    }
82
83    /// Create a new `BufferMut` with the requested alignment, capacity, and allocator.
84    pub fn with_capacity_aligned_in(
85        capacity: usize,
86        alignment: Alignment,
87        allocator: BufferAllocatorRef,
88    ) -> Self {
89        Self::with_capacity_preferred_aligned_in(
90            capacity,
91            alignment,
92            Some(Alignment::DEFAULT_ALIGNMENT),
93            allocator,
94        )
95    }
96
97    /// Create a new `BufferMut` with the requested alignment and capacity.
98    ///
99    /// The buffer reports `alignment`, but the underlying allocation is over-aligned to the larger
100    /// of `alignment` and `preferred_alignment`.
101    pub fn with_capacity_preferred_aligned(
102        capacity: usize,
103        alignment: Alignment,
104        preferred_alignment: Option<Alignment>,
105    ) -> Self {
106        Self::with_capacity_preferred_aligned_in(
107            capacity,
108            alignment,
109            preferred_alignment,
110            BufferAllocatorRef::statically_allocated(),
111        )
112    }
113
114    /// Create a new allocator-backed `BufferMut` with a requested and preferred alignment.
115    pub fn with_capacity_preferred_aligned_in(
116        capacity: usize,
117        alignment: Alignment,
118        preferred_alignment: Option<Alignment>,
119        allocator: BufferAllocatorRef,
120    ) -> Self {
121        const { assert!(size_of::<T>() != 0, "ZSTs are not supported") };
122        let actual = max(
123            alignment,
124            preferred_alignment.unwrap_or(Alignment::of::<u8>()),
125        );
126
127        if !alignment.is_aligned_to(Alignment::of::<T>()) {
128            misaligned_scalar_type(alignment, Alignment::of::<T>());
129        }
130
131        let size = capacity
132            .checked_mul(size_of::<T>())
133            .vortex_expect("buffer capacity overflow");
134        let layout = if size == 0 {
135            Layout::from_size_align(0, actual.as_usize())
136                .unwrap_or_else(|_| vortex_panic!("invalid empty buffer alignment"))
137        } else {
138            let allocation_size = size
139                .checked_add(actual.as_usize())
140                .vortex_expect("buffer capacity overflow");
141            Layout::from_size_align(allocation_size, 1).unwrap_or_else(|_| {
142                vortex_panic!("buffer capacity exceeds maximum allocation size")
143            })
144        };
145        let allocation = Allocation::allocate(layout, allocator);
146        let offset = allocation.ptr().as_ptr().align_offset(actual.as_usize());
147        // SAFETY: the allocation includes enough padding to reach this aligned pointer.
148        let ptr = unsafe { allocation.ptr().add(offset).cast() };
149        let capacity = (allocation.size() - offset) / size_of::<T>();
150        Self {
151            allocation,
152            ptr,
153            length: 0,
154            capacity,
155            alignment,
156            _marker: Default::default(),
157        }
158    }
159
160    /// Create a new zeroed `BufferMut`.
161    pub fn zeroed(len: usize) -> Self {
162        Self::zeroed_in(len, BufferAllocatorRef::statically_allocated())
163    }
164
165    /// Create a new zeroed `BufferMut` with the requested allocator.
166    pub fn zeroed_in(len: usize, allocator: BufferAllocatorRef) -> Self {
167        Self::zeroed_aligned_in(len, Alignment::of::<T>(), allocator)
168    }
169
170    /// Create a new zeroed `BufferMut` with the requested alignment.
171    ///
172    /// The allocation is over-aligned to [`Alignment::DEFAULT_ALIGNMENT`] when that is larger than
173    /// `alignment`. Use [`zeroed_preferred_aligned`] to control the over-alignment.
174    ///
175    /// [`zeroed_preferred_aligned`]: Self::zeroed_preferred_aligned
176    pub fn zeroed_aligned(len: usize, alignment: Alignment) -> Self {
177        Self::zeroed_aligned_in(len, alignment, BufferAllocatorRef::statically_allocated())
178    }
179
180    /// Create a zeroed `BufferMut` with an alignment and allocator.
181    pub fn zeroed_aligned_in(
182        len: usize,
183        alignment: Alignment,
184        allocator: BufferAllocatorRef,
185    ) -> Self {
186        Self::zeroed_preferred_aligned_in(
187            len,
188            alignment,
189            Some(Alignment::DEFAULT_ALIGNMENT),
190            allocator,
191        )
192    }
193
194    /// Create a new zeroed `BufferMut` with the requested alignment.
195    ///
196    /// The buffer reports `alignment`, but the underlying allocation is over-aligned to the larger
197    /// of `alignment` and `preferred_alignment`.
198    pub fn zeroed_preferred_aligned(
199        len: usize,
200        alignment: Alignment,
201        preferred_alignment: Option<Alignment>,
202    ) -> Self {
203        Self::zeroed_preferred_aligned_in(
204            len,
205            alignment,
206            preferred_alignment,
207            BufferAllocatorRef::statically_allocated(),
208        )
209    }
210
211    /// Create a zeroed allocator-backed buffer with a requested and preferred alignment.
212    pub fn zeroed_preferred_aligned_in(
213        len: usize,
214        alignment: Alignment,
215        preferred_alignment: Option<Alignment>,
216        allocator: BufferAllocatorRef,
217    ) -> Self {
218        const { assert!(size_of::<T>() != 0, "ZSTs are not supported") };
219        let preferred_alignment = preferred_alignment.unwrap_or(Alignment::of::<u8>());
220        let actual_alignment = max(preferred_alignment, alignment);
221        let size = len
222            .checked_mul(size_of::<T>())
223            .vortex_expect("buffer length overflow");
224        let layout = if size == 0 {
225            Layout::from_size_align(0, actual_alignment.as_usize())
226                .unwrap_or_else(|_| vortex_panic!("invalid empty buffer alignment"))
227        } else {
228            let allocation_size = size
229                .checked_add(actual_alignment.as_usize())
230                .vortex_expect("buffer length overflow");
231            Layout::from_size_align(allocation_size, 1)
232                .unwrap_or_else(|_| vortex_panic!("buffer length exceeds maximum allocation size"))
233        };
234        let allocation = Allocation::allocate_zeroed(layout, allocator);
235        let offset = allocation
236            .ptr()
237            .as_ptr()
238            .align_offset(actual_alignment.as_usize());
239        // SAFETY: the allocation includes enough padding to reach this aligned pointer.
240        let ptr = unsafe { allocation.ptr().add(offset).cast() };
241        let capacity = (allocation.size() - offset) / size_of::<T>();
242        Self {
243            allocation,
244            ptr,
245            length: len,
246            capacity,
247            alignment,
248            _marker: Default::default(),
249        }
250    }
251
252    /// Create a new empty `BufferMut` with the provided alignment.
253    pub fn empty() -> Self {
254        Self::empty_aligned(Alignment::of::<T>())
255    }
256
257    /// Create a new empty `BufferMut` with the provided alignment.
258    ///
259    /// The allocation is over-aligned to [`Alignment::DEFAULT_ALIGNMENT`] when that is larger than
260    /// `alignment`. Use [`empty_preferred_aligned`] to control the over-alignment.
261    ///
262    /// [`empty_preferred_aligned`]: Self::empty_preferred_aligned
263    pub fn empty_aligned(alignment: Alignment) -> Self {
264        Self::empty_aligned_in(alignment, BufferAllocatorRef::statically_allocated())
265    }
266
267    /// Create an empty `BufferMut` with an alignment and allocator.
268    pub fn empty_aligned_in(alignment: Alignment, allocator: BufferAllocatorRef) -> Self {
269        Self::with_capacity_aligned_in(0, alignment, allocator)
270    }
271
272    /// Create a new empty `BufferMut` with the provided alignment.
273    ///
274    /// The buffer reports `alignment`, but the underlying allocation is over-aligned to the larger
275    /// of `alignment` and `preferred_alignment`.
276    pub fn empty_preferred_aligned(
277        alignment: Alignment,
278        preferred_alignment: Option<Alignment>,
279    ) -> Self {
280        BufferMut::with_capacity_preferred_aligned_in(
281            0,
282            alignment,
283            preferred_alignment,
284            BufferAllocatorRef::statically_allocated(),
285        )
286    }
287
288    /// Create a new full `BufferMut` with the given value.
289    pub fn full(item: T, len: usize) -> Self
290    where
291        T: Copy,
292    {
293        Self::full_in(item, len, BufferAllocatorRef::statically_allocated())
294    }
295
296    /// Create a full `BufferMut` with the given value and allocator.
297    pub fn full_in(item: T, len: usize, allocator: BufferAllocatorRef) -> Self
298    where
299        T: Copy,
300    {
301        let mut buffer = BufferMut::<T>::with_capacity_in(len, allocator);
302        buffer.push_n(item, len);
303        buffer
304    }
305
306    /// Create a mutable scalar buffer by copying the contents of the slice.
307    pub fn copy_from(other: impl AsRef<[T]>) -> Self
308    where
309        T: Copy,
310    {
311        Self::copy_from_in(other, BufferAllocatorRef::statically_allocated())
312    }
313
314    /// Create a mutable scalar buffer by copying with the given allocator.
315    pub fn copy_from_in(other: impl AsRef<[T]>, allocator: BufferAllocatorRef) -> Self
316    where
317        T: Copy,
318    {
319        Self::copy_from_aligned_in(other, Alignment::of::<T>(), allocator)
320    }
321
322    /// Create a mutable scalar buffer with the alignment by copying the contents of the slice.
323    ///
324    /// The allocation is over-aligned to [`Alignment::DEFAULT_ALIGNMENT`] when that is larger than
325    /// `alignment`. Use [`copy_from_preferred_aligned`] to control the over-alignment.
326    ///
327    /// [`copy_from_preferred_aligned`]: Self::copy_from_preferred_aligned
328    ///
329    /// ## Panics
330    ///
331    /// Panics when the requested alignment isn't itself aligned to type T.
332    pub fn copy_from_aligned(other: impl AsRef<[T]>, alignment: Alignment) -> Self
333    where
334        T: Copy,
335    {
336        Self::copy_from_aligned_in(other, alignment, BufferAllocatorRef::statically_allocated())
337    }
338
339    /// Copy values into a mutable buffer with the given alignment and allocator.
340    pub fn copy_from_aligned_in(
341        other: impl AsRef<[T]>,
342        alignment: Alignment,
343        allocator: BufferAllocatorRef,
344    ) -> Self
345    where
346        T: Copy,
347    {
348        Self::copy_from_preferred_aligned_in(
349            other,
350            alignment,
351            Some(Alignment::DEFAULT_ALIGNMENT),
352            allocator,
353        )
354    }
355
356    /// Create a mutable scalar buffer with the alignment by copying the contents of the slice.
357    ///
358    /// The buffer reports `alignment`, but the underlying allocation is over-aligned to the larger
359    /// of `alignment` and `preferred_alignment`.
360    ///
361    /// ## Panics
362    ///
363    /// Panics when the requested alignment isn't itself aligned to type T.
364    pub fn copy_from_preferred_aligned(
365        other: impl AsRef<[T]>,
366        alignment: Alignment,
367        preferred_alignment: Option<Alignment>,
368    ) -> Self
369    where
370        T: Copy,
371    {
372        Self::copy_from_preferred_aligned_in(
373            other,
374            alignment,
375            preferred_alignment,
376            BufferAllocatorRef::statically_allocated(),
377        )
378    }
379
380    /// Copy values with the given allocator, requested alignment, and preferred alignment.
381    pub fn copy_from_preferred_aligned_in(
382        other: impl AsRef<[T]>,
383        alignment: Alignment,
384        preferred_alignment: Option<Alignment>,
385        allocator: BufferAllocatorRef,
386    ) -> Self
387    where
388        T: Copy,
389    {
390        if !alignment.is_aligned_to(Alignment::of::<T>()) {
391            vortex_panic!("Given alignment is not aligned to type T")
392        }
393        let other = other.as_ref();
394        let mut buffer = Self::with_capacity_preferred_aligned_in(
395            other.len(),
396            alignment,
397            preferred_alignment,
398            allocator,
399        );
400        buffer.extend_from_slice(other);
401        debug_assert_eq!(buffer.alignment(), alignment);
402        buffer
403    }
404
405    /// Get the alignment of the buffer.
406    #[allow(clippy::inline_always)]
407    #[inline(always)]
408    pub fn alignment(&self) -> Alignment {
409        self.alignment
410    }
411
412    #[cfg(test)]
413    pub(crate) fn allocator(&self) -> &BufferAllocatorRef {
414        self.allocation.allocator()
415    }
416
417    /// Takes the buffer, leaving an empty buffer with the same alignment and allocator.
418    pub fn take(&mut self) -> Self {
419        let replacement =
420            Self::empty_aligned_in(self.alignment, self.allocation.allocator().clone());
421        std::mem::replace(self, replacement)
422    }
423
424    /// Returns the length of the buffer.
425    #[allow(clippy::inline_always)]
426    #[inline(always)]
427    pub fn len(&self) -> usize {
428        self.length
429    }
430
431    /// Returns whether the buffer is empty.
432    #[allow(clippy::inline_always)]
433    #[inline(always)]
434    pub fn is_empty(&self) -> bool {
435        self.length == 0
436    }
437
438    /// Returns the capacity of the buffer.
439    #[inline]
440    pub fn capacity(&self) -> usize {
441        self.capacity
442    }
443
444    /// Returns a raw pointer to the buffer's data.
445    #[allow(clippy::inline_always)]
446    #[inline(always)]
447    pub fn as_ptr(&self) -> *const T {
448        self.ptr.as_ptr()
449    }
450
451    /// Returns a mutable raw pointer to the buffer's data.
452    #[allow(clippy::inline_always)]
453    #[inline(always)]
454    pub fn as_mut_ptr(&mut self) -> *mut T {
455        self.ptr.as_ptr()
456    }
457
458    /// Returns a slice over the buffer of elements of type T.
459    #[inline]
460    pub fn as_slice(&self) -> &[T] {
461        // SAFETY: ptr is in the live allocation and construction checks its alignment.
462        unsafe { std::slice::from_raw_parts(self.as_ptr(), self.length) }
463    }
464
465    /// Returns a slice over the buffer of elements of type T.
466    #[inline]
467    pub fn as_mut_slice(&mut self) -> &mut [T] {
468        // SAFETY: BufferMut uniquely owns the allocation and the initialized range is in bounds.
469        unsafe { std::slice::from_raw_parts_mut(self.as_mut_ptr(), self.length) }
470    }
471
472    /// Clear the buffer, retaining any existing capacity.
473    #[inline]
474    pub fn clear(&mut self) {
475        self.length = 0;
476    }
477
478    /// Shortens the buffer, keeping the first `len` bytes and dropping the
479    /// rest.
480    ///
481    /// If `len` is greater than the buffer's current length, this has no
482    /// effect.
483    ///
484    /// Existing underlying capacity is preserved.
485    #[inline]
486    pub fn truncate(&mut self, len: usize) {
487        if len <= self.len() {
488            // SAFETY: Shrinking the buffer cannot expose uninitialized bytes.
489            unsafe { self.set_len(len) };
490        }
491    }
492
493    /// Reserves capacity for at least `additional` more elements to be inserted in the buffer.
494    #[inline]
495    pub fn reserve(&mut self, additional: usize) {
496        if additional <= self.capacity() - self.length {
497            // We can fit the additional bytes in the remaining capacity. Nothing to do.
498            return;
499        }
500
501        // Otherwise, reserve additional + alignment bytes in case we need to realign the buffer.
502        self.reserve_allocate(additional);
503    }
504
505    /// Keeps allocation work out of the inline fast path in [`Self::reserve`].
506    ///
507    /// Buffer capacity measures the space available from the data pointer. The allocation also
508    /// includes any bytes before that pointer, which can come from alignment padding or slicing.
509    /// The new layout follows the buffer growth policy without retaining that old prefix.
510    ///
511    /// For a byte buffer:
512    ///
513    /// ```text
514    /// Before reserve(100): allocation = 1,000 bytes, capacity = 100 bytes.
515    /// | 900 bytes before slice | 100 data |
516    ///                          ^ data pointer
517    ///
518    /// After reserve(100): allocation = 257 bytes, capacity = 256 bytes.
519    /// | 100 data | 156 spare | 1 unused |
520    /// ^ data pointer
521    /// ```
522    ///
523    /// [`Allocator::grow`] requires the new allocation to be at least as large as the entire old
524    /// allocation. If the new layout is smaller, allocate a separate block and copy the initialized
525    /// data instead of violating that safety contract.
526    ///
527    /// [`Allocator::grow`]: allocator_api2::alloc::Allocator::grow
528    fn reserve_allocate(&mut self, additional: usize) {
529        let required_capacity = self
530            .length
531            .checked_add(additional)
532            .vortex_expect("buffer capacity overflow");
533        let required_bytes = required_capacity
534            .checked_mul(size_of::<T>())
535            .vortex_expect("buffer capacity overflow");
536        let capacity_bytes = self
537            .capacity
538            .checked_mul(size_of::<T>())
539            .vortex_expect("buffer capacity overflow");
540        let new_capacity_bytes = required_bytes
541            .max(capacity_bytes.saturating_mul(2))
542            .max(Alignment::DEFAULT_ALIGNMENT.as_usize());
543
544        // Reserve space before the data so its pointer can satisfy the buffer's alignment.
545        let data_alignment = self.alignment.as_usize();
546        let new_allocation_bytes = new_capacity_bytes
547            .checked_add(data_alignment)
548            .vortex_expect("buffer capacity overflow");
549        let allocation_alignment = if self.allocation.size() == 0 {
550            1
551        } else {
552            self.allocation.alignment()
553        };
554        let new_layout = Layout::from_size_align(new_allocation_bytes, allocation_alignment)
555            .unwrap_or_else(|_| vortex_panic!("buffer capacity exceeds maximum allocation size"));
556        let initialized_bytes = self.length * size_of::<T>();
557
558        // The default global allocator (`is_statically_allocated`) uses allocate-and-copy. Custom
559        // allocators must also allocate and copy when the new layout is smaller, because
560        // `Allocator::grow` forbids shrinking.
561        let needs_new_allocation = self.allocation.allocator().is_statically_allocated()
562            || new_layout.size() < self.allocation.size();
563
564        let data_offset = if needs_new_allocation {
565            let new_allocation =
566                Allocation::allocate(new_layout, self.allocation.allocator().clone());
567            let new_data_offset = new_allocation.ptr().as_ptr().align_offset(data_alignment);
568
569            // SAFETY: self.ptr addresses initialized_bytes of live data. The new allocation has
570            // room for those bytes after alignment padding and is disjoint from the old allocation.
571            unsafe {
572                std::ptr::copy_nonoverlapping(
573                    self.ptr.cast::<u8>().as_ptr(),
574                    new_allocation.ptr().as_ptr().add(new_data_offset),
575                    initialized_bytes,
576                );
577            }
578
579            self.allocation = new_allocation;
580
581            new_data_offset
582        } else {
583            let old_data_offset =
584                self.ptr.cast::<u8>().addr().get() - self.allocation.ptr().addr().get();
585            self.allocation.grow(new_layout);
586
587            let new_data_offset = self.allocation.ptr().as_ptr().align_offset(data_alignment);
588
589            if new_data_offset != old_data_offset {
590                // SAFETY: grow preserved initialized_bytes at old_data_offset. The reserved padding
591                // leaves room for the data at new_data_offset, and copy permits overlap.
592                unsafe {
593                    std::ptr::copy(
594                        self.allocation.ptr().as_ptr().add(old_data_offset),
595                        self.allocation.ptr().as_ptr().add(new_data_offset),
596                        initialized_bytes,
597                    );
598                }
599            }
600
601            new_data_offset
602        };
603
604        // SAFETY: data_offset satisfies the required alignment and leaves new_capacity_bytes
605        // available within the allocation.
606        self.ptr = unsafe { self.allocation.ptr().add(data_offset).cast() };
607        self.capacity = new_capacity_bytes / size_of::<T>();
608    }
609
610    /// Returns the spare capacity of the buffer as a slice of `MaybeUninit<T>`.
611    /// Has identical semantics to [`Vec::spare_capacity_mut`].
612    ///
613    /// The returned slice can be used to fill the buffer with data (e.g. by
614    /// reading from a file) before marking the data as initialized using the
615    /// [`set_len`] method.
616    ///
617    /// Note that the returned slice may be larger than the capacity requested at
618    /// construction, since the underlying allocation can be rounded up (e.g. to
619    /// satisfy alignment requirements).
620    ///
621    /// [`set_len`]: BufferMut::set_len
622    /// [`Vec::spare_capacity_mut`]: Vec::spare_capacity_mut
623    ///
624    /// # Examples
625    ///
626    /// ```
627    /// use vortex_buffer::BufferMut;
628    ///
629    /// // Allocate vector big enough for 10 elements.
630    /// let mut b = BufferMut::<u64>::with_capacity(10);
631    ///
632    /// // Fill in the first 3 elements.
633    /// let uninit = b.spare_capacity_mut();
634    /// uninit[0].write(0);
635    /// uninit[1].write(1);
636    /// uninit[2].write(2);
637    ///
638    /// // Mark the first 3 elements of the vector as being initialized.
639    /// unsafe {
640    ///     b.set_len(3);
641    /// }
642    ///
643    /// assert_eq!(b.as_slice(), &[0u64, 1, 2]);
644    /// ```
645    #[inline]
646    pub fn spare_capacity_mut(&mut self) -> &mut [MaybeUninit<T>] {
647        // SAFETY: offset + length is within the allocation and points at spare capacity.
648        let dst = unsafe { self.as_mut_ptr().add(self.length) }.cast::<MaybeUninit<T>>();
649        unsafe { std::slice::from_raw_parts_mut(dst, self.capacity() - self.length) }
650    }
651
652    /// Sets the length of the buffer.
653    ///
654    /// # Safety
655    ///
656    /// - `new_len` must be less than or equal to [`capacity()`].
657    /// - The elements at `old_len..new_len` must be initialized.
658    ///
659    /// [`capacity()`]: Self::capacity
660    #[inline]
661    pub unsafe fn set_len(&mut self, len: usize) {
662        debug_assert!(len <= self.capacity());
663        self.length = len;
664    }
665
666    /// Appends a scalar to the buffer.
667    #[inline]
668    pub fn push(&mut self, value: T) {
669        self.reserve(1);
670        unsafe { self.push_unchecked(value) }
671    }
672
673    /// Appends a scalar to the buffer without checking for sufficient capacity.
674    ///
675    /// ## Safety
676    ///
677    /// The caller must ensure there is sufficient capacity in the array.
678    #[inline]
679    pub unsafe fn push_unchecked(&mut self, item: T) {
680        // SAFETY: the caller ensures we have sufficient capacity
681        unsafe {
682            let dst = self.as_mut_ptr().add(self.length);
683            dst.write(item);
684        }
685        self.length += 1;
686    }
687
688    /// Appends n scalars to the buffer.
689    ///
690    /// This function is slightly more optimized than `extend(iter::repeat_n(item, b))`.
691    #[inline]
692    pub fn push_n(&mut self, item: T, n: usize)
693    where
694        T: Copy,
695    {
696        self.reserve(n);
697        unsafe { self.push_n_unchecked(item, n) }
698    }
699
700    /// Appends n scalars to the buffer.
701    ///
702    /// ## Safety
703    ///
704    /// The caller must ensure there is sufficient capacity in the array.
705    #[inline]
706    pub unsafe fn push_n_unchecked(&mut self, item: T, n: usize)
707    where
708        T: Copy,
709    {
710        // SAFETY: the caller guarantees enough spare capacity.
711        let mut dst = unsafe { self.as_mut_ptr().add(self.length) };
712        // SAFETY: we checked the capacity in the reserve call
713        unsafe {
714            let end = dst.add(n);
715            while dst < end {
716                dst.write(item);
717                dst = dst.add(1);
718            }
719        }
720        self.length += n;
721    }
722
723    /// Appends a slice by copying its elements, growing the internal buffer as needed.
724    ///
725    /// This does not call [`Clone::clone`].
726    ///
727    /// # Example
728    ///
729    /// ```
730    /// use vortex_buffer::BufferMut;
731    ///
732    /// let mut buffer = BufferMut::from_iter([1, 2]);
733    /// buffer.extend_from_slice(&[3, 4]);
734    /// assert_eq!(buffer.as_slice(), &[1, 2, 3, 4]);
735    /// ```
736    ///
737    /// Elements must implement `Copy`, even when they implement `Clone`.
738    ///
739    /// ```compile_fail,E0277
740    /// use vortex_buffer::BufferMut;
741    ///
742    /// #[derive(Clone)]
743    /// struct NotCopy(u32);
744    ///
745    /// let mut buffer = BufferMut::with_capacity(1);
746    /// buffer.extend_from_slice(&[NotCopy(1)]);
747    /// ```
748    #[inline]
749    pub fn extend_from_slice(&mut self, slice: &[T])
750    where
751        T: Copy,
752    {
753        self.reserve(slice.len());
754        let dst = self
755            .spare_capacity_mut()
756            .get_mut(..slice.len())
757            .vortex_expect("reserve guarantees sufficient spare capacity");
758        dst.write_copy_of_slice(slice);
759        self.length += slice.len();
760    }
761
762    /// Return the [`ByteBufferMut`] for this [`BufferMut`].
763    pub fn into_byte_buffer(self) -> ByteBufferMut {
764        let capacity = self
765            .capacity
766            .checked_mul(size_of::<T>())
767            .vortex_expect("buffer capacity overflow");
768        ByteBufferMut {
769            allocation: self.allocation,
770            ptr: self.ptr.cast(),
771            length: self.length * size_of::<T>(),
772            capacity,
773            alignment: self.alignment,
774            _marker: Default::default(),
775        }
776    }
777
778    /// Freeze the `BufferMut` into a `Buffer`.
779    pub fn freeze(self) -> Buffer<T> {
780        let offset = self.ptr.cast::<u8>().addr().get() - self.allocation.ptr().addr().get();
781        Buffer::from_allocation(self.allocation, offset, self.length, self.alignment)
782    }
783
784    /// Map each element of the buffer with a closure.
785    pub fn map_each_in_place<R, F>(self, mut f: F) -> BufferMut<R>
786    where
787        T: Copy,
788        F: FnMut(T) -> R,
789    {
790        assert_eq!(
791            size_of::<T>(),
792            size_of::<R>(),
793            "Size of T and R do not match"
794        );
795        // SAFETY: we have checked that `size_of::<T>` == `size_of::<R>`.
796        let mut buf: BufferMut<R> = unsafe { std::mem::transmute(self) };
797        buf.iter_mut()
798            .for_each(|item| *item = f(unsafe { std::mem::transmute_copy(item) }));
799        buf
800    }
801
802    /// Return a `BufferMut<T>` with the same data as this one with the given alignment.
803    ///
804    /// If the data is already properly aligned, this is a metadata-only operation.
805    ///
806    /// If the data is not aligned, we copy it into a new allocation.
807    pub fn aligned(self, alignment: Alignment) -> Self
808    where
809        T: Copy,
810    {
811        if self.as_ptr().align_offset(alignment.as_usize()) == 0 {
812            Self { alignment, ..self }
813        } else {
814            let capacity = self.capacity();
815            let allocator = self.allocation.allocator().clone();
816            let mut aligned = Self::with_capacity_aligned_in(capacity, alignment, allocator);
817            aligned.extend_from_slice(&self);
818            aligned.capacity = capacity;
819            aligned
820        }
821    }
822
823    /// Transmute a `Buffer<T>` into a `Buffer<U>`.
824    ///
825    /// # Safety
826    ///
827    /// The caller must ensure that all possible bit representations of type `T` are valid when
828    /// interpreted as type `U`.
829    /// See [`std::mem::transmute`] for more details.
830    ///
831    /// # Panics
832    ///
833    /// Panics if the type `U` does not have the same size and alignment as `T`.
834    pub unsafe fn transmute<U>(self) -> BufferMut<U> {
835        assert_eq!(size_of::<T>(), size_of::<U>(), "Buffer type size mismatch");
836        assert_eq!(
837            align_of::<T>(),
838            align_of::<U>(),
839            "Buffer type alignment mismatch"
840        );
841
842        BufferMut {
843            allocation: self.allocation,
844            ptr: self.ptr.cast(),
845            length: self.length,
846            capacity: self.capacity,
847            alignment: self.alignment,
848            _marker: std::marker::PhantomData,
849        }
850    }
851}
852
853impl<T: Copy> Clone for BufferMut<T> {
854    fn clone(&self) -> Self {
855        let mut buffer = BufferMut::<T>::with_capacity_aligned_in(
856            self.capacity(),
857            self.alignment,
858            self.allocation.allocator().clone(),
859        );
860        buffer.extend_from_slice(self.as_slice());
861        buffer
862    }
863}
864
865impl<T: PartialEq> PartialEq for BufferMut<T> {
866    fn eq(&self, other: &Self) -> bool {
867        self.as_slice() == other.as_slice()
868    }
869}
870
871impl<T: Eq> Eq for BufferMut<T> {}
872
873impl<T: Debug> Debug for BufferMut<T> {
874    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
875        f.debug_struct(&format!("BufferMut<{}>", type_name::<T>()))
876            .field("length", &self.length)
877            .field("alignment", &self.alignment)
878            .field("as_slice", &TruncatedDebug(self.as_slice()))
879            .finish()
880    }
881}
882
883impl<T> Default for BufferMut<T> {
884    fn default() -> Self {
885        Self::empty()
886    }
887}
888
889impl<T> Deref for BufferMut<T> {
890    type Target = [T];
891
892    #[inline]
893    fn deref(&self) -> &Self::Target {
894        self.as_slice()
895    }
896}
897
898impl<T> DerefMut for BufferMut<T> {
899    #[inline]
900    fn deref_mut(&mut self) -> &mut Self::Target {
901        self.as_mut_slice()
902    }
903}
904
905impl<T> AsRef<[T]> for BufferMut<T> {
906    #[inline]
907    fn as_ref(&self) -> &[T] {
908        self.as_slice()
909    }
910}
911
912impl<T> AsMut<[T]> for BufferMut<T> {
913    #[inline]
914    fn as_mut(&mut self) -> &mut [T] {
915        self.as_mut_slice()
916    }
917}
918
919impl<T> BufferMut<T> {
920    /// A helper method for the two [`Extend`] implementations.
921    ///
922    /// We use the lower bound hint on the iterator to manually write data, and then we continue to
923    /// push items normally past the lower bound.
924    fn extend_iter(&mut self, mut iter: impl Iterator<Item = T>) {
925        // Since we do not know the length of the iterator, we can only guess how much memory we
926        // need to reserve. Note that these hints may be inaccurate.
927        let (lower_bound, _) = iter.size_hint();
928
929        // We choose not to use the optional upper bound size hint to match the standard library.
930
931        self.reserve(lower_bound);
932
933        let unwritten = self.capacity() - self.len();
934
935        // We store `begin` in the case that the lower bound hint is incorrect.
936        let begin: *const T = self.spare_capacity_mut().as_mut_ptr().cast();
937        let mut dst: *mut T = begin.cast_mut();
938
939        // As a first step, we manually iterate the iterator up to the known capacity.
940        for _ in 0..unwritten {
941            let Some(item) = iter.next() else {
942                // The lower bound hint may be incorrect.
943                break;
944            };
945
946            // SAFETY: We have reserved enough capacity to hold this item, and `dst` is a pointer
947            // derived from a valid reference to byte data.
948            unsafe { dst.write(item) };
949
950            // Note: We used to have `dst.add(iteration).write(item)`, here. However this was much
951            // slower than just incrementing `dst`.
952            // SAFETY: The offsets fits in `isize`, and because we were able to reserve the memory
953            // we know that `add` will not overflow.
954            unsafe { dst = dst.add(1) };
955        }
956
957        // SAFETY: `dst` was derived from `begin`, which were both valid references to byte data,
958        // and since the only operation that `dst` has is `add`, we know that `dst >= begin`.
959        let items_written = unsafe { dst.offset_from_unsigned(begin) };
960        let length = self.len() + items_written;
961
962        // SAFETY: We have written valid items between the old length and the new length.
963        unsafe { self.set_len(length) };
964
965        // Finally, since the iterator will have arbitrarily more items to yield, we push the
966        // remaining items normally.
967        iter.for_each(|item| self.push(item));
968    }
969
970    /// Extends the `BufferMut` with an iterator with `TrustedLen`.
971    ///
972    /// The caller guarantees that the iterator will have a trusted upper bound, which allows the
973    /// implementation to reserve all of the memory needed up front.
974    pub fn extend_trusted<I: TrustedLen<Item = T>>(&mut self, iter: I) {
975        let (_, upper_bound) = iter.size_hint();
976        self.reserve(
977            upper_bound
978                .vortex_expect("`TrustedLen` iterator somehow didn't have valid upper bound"),
979        );
980
981        let begin: *const T = self.spare_capacity_mut().as_mut_ptr().cast();
982        let mut dst: *mut T = begin.cast_mut();
983
984        iter.for_each(|item| {
985            // SAFETY: We have reserved enough capacity to hold this item, and `dst` is a pointer
986            // derived from a valid reference to byte data.
987            unsafe { dst.write(item) };
988
989            // Note: We used to have `dst.add(iteration).write(item)`, here. However this was much
990            // slower than just incrementing `dst`.
991            // SAFETY: The offset fits in `isize`, and because we were able to reserve the memory
992            // we know that `add` will not overflow.
993            unsafe { dst = dst.add(1) };
994        });
995
996        // SAFETY: `dst` starts at `begin` and advances by one for each item, so both pointers refer
997        // to the same allocation and `dst` is at or after `begin`.
998        let items_written = unsafe { dst.offset_from_unsigned(begin) };
999        let length = self.len() + items_written;
1000
1001        // SAFETY: We have written valid items between the old length and the new length.
1002        unsafe { self.set_len(length) };
1003    }
1004
1005    /// Creates a `BufferMut` from an iterator with a trusted length.
1006    ///
1007    /// Internally, this calls [`extend_trusted()`](Self::extend_trusted).
1008    pub fn from_trusted_len_iter<I>(iter: I) -> Self
1009    where
1010        I: TrustedLen<Item = T>,
1011    {
1012        let (_, upper_bound) = iter.size_hint();
1013        let mut buffer = Self::with_capacity(
1014            upper_bound
1015                .vortex_expect("`TrustedLen` iterator somehow didn't have valid upper bound"),
1016        );
1017
1018        buffer.extend_trusted(iter);
1019        buffer
1020    }
1021
1022    /// Like [`extend_trusted()`](Self::extend_trusted), but the iterator yields `Result<T, E>`
1023    /// and the extension short-circuits on the first `Err`.
1024    ///
1025    /// On error, items written before the failure remain in the buffer.
1026    pub fn try_extend_trusted<E, I>(&mut self, iter: I) -> Result<(), E>
1027    where
1028        I: TrustedLen<Item = Result<T, E>>,
1029    {
1030        iter.process_results(|values| self.extend_trusted(values))
1031    }
1032
1033    /// Like [`from_trusted_len_iter()`](Self::from_trusted_len_iter), but the iterator yields
1034    /// `Result<T, E>` and construction short-circuits on the first `Err`.
1035    pub fn try_from_trusted_len_iter<E, I>(iter: I) -> Result<Self, E>
1036    where
1037        I: TrustedLen<Item = Result<T, E>>,
1038    {
1039        iter.process_results(|values| Self::from_trusted_len_iter(values))
1040    }
1041}
1042
1043impl<T> Extend<T> for BufferMut<T> {
1044    #[inline]
1045    fn extend<I: IntoIterator<Item = T>>(&mut self, iter: I) {
1046        self.extend_iter(iter.into_iter())
1047    }
1048}
1049
1050impl<'a, T> Extend<&'a T> for BufferMut<T>
1051where
1052    T: Copy + 'a,
1053{
1054    #[inline]
1055    fn extend<I: IntoIterator<Item = &'a T>>(&mut self, iter: I) {
1056        self.extend_iter(iter.into_iter().copied())
1057    }
1058}
1059
1060impl<T> FromIterator<T> for BufferMut<T> {
1061    fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self {
1062        let iter = iter.into_iter();
1063        let mut buffer = Self::with_capacity(iter.size_hint().0);
1064        buffer.extend(iter);
1065        buffer
1066    }
1067}
1068
1069#[cold]
1070#[inline(never)]
1071fn misaligned_scalar_type(alignment: Alignment, scalar_align: Alignment) -> ! {
1072    vortex_panic!("Alignment {alignment} must align to the scalar type's alignment {scalar_align}")
1073}
1074
1075#[cfg(test)]
1076mod tests {
1077    use std::cell::Cell;
1078
1079    use allocator_api2::alloc::Global;
1080
1081    use crate::Alignment;
1082    use crate::BufferAllocatorRef;
1083    use crate::BufferMut;
1084    use crate::buffer_mut;
1085
1086    #[derive(Copy, Debug, PartialEq)]
1087    struct CopyWithCloneCounter<'a> {
1088        value: u32,
1089        clones: &'a Cell<usize>,
1090    }
1091
1092    #[allow(clippy::non_canonical_clone_impl)]
1093    impl Clone for CopyWithCloneCounter<'_> {
1094        fn clone(&self) -> Self {
1095            self.clones.set(self.clones.get() + 1);
1096            *self
1097        }
1098    }
1099
1100    #[test]
1101    fn extend_from_slice_skips_clone() {
1102        let clones = Cell::new(0);
1103        let source = [CopyWithCloneCounter {
1104            value: 42,
1105            clones: &clones,
1106        }];
1107        let mut buffer = BufferMut::empty();
1108        buffer.extend_from_slice(&source);
1109        buffer.extend_from_slice(&source);
1110        buffer.extend_from_slice(&[]);
1111        assert_eq!(clones.get(), 0);
1112        assert_eq!(buffer.as_slice(), &[source[0], source[0]]);
1113        assert_eq!(buffer.clone().as_slice(), buffer.as_slice());
1114        assert_eq!(clones.get(), 0);
1115    }
1116
1117    #[test]
1118    fn capacity() {
1119        let mut n = 57;
1120        let mut buf = BufferMut::<i32>::with_capacity_aligned(n, Alignment::new(1024));
1121        assert!(buf.capacity() >= 57);
1122
1123        while n > 0 {
1124            buf.push(0);
1125            assert!(buf.capacity() >= n);
1126            n -= 1
1127        }
1128
1129        assert_eq!(buf.alignment(), Alignment::new(1024));
1130    }
1131
1132    #[test]
1133    fn take_preserves_alignment_and_allocator() {
1134        let alignment = Alignment::new(1024);
1135        let allocator = BufferAllocatorRef::new(Global);
1136        let mut buffer = BufferMut::with_capacity_aligned_in(4, alignment, allocator.clone());
1137        buffer.extend([1u32, 2, 3]);
1138
1139        let taken = buffer.take();
1140
1141        assert_eq!(taken.as_slice(), [1, 2, 3]);
1142        assert!(taken.allocator().ptr_eq(&allocator));
1143        assert!(buffer.is_empty());
1144        assert_eq!(buffer.alignment(), alignment);
1145        assert!(buffer.allocator().ptr_eq(&allocator));
1146    }
1147
1148    #[test]
1149    fn growth_preserves_alignment_and_values() {
1150        let alignment = Alignment::new(4096);
1151        let mut buffer = BufferMut::<u64>::with_capacity_aligned(1, alignment);
1152
1153        for value in 0..10_000 {
1154            buffer.push(value);
1155            assert!(alignment.is_offset_aligned(buffer.as_ptr().addr()));
1156        }
1157
1158        assert_eq!(buffer.as_slice(), (0..10_000).collect::<Vec<_>>());
1159    }
1160
1161    #[test]
1162    fn growth_seeds_and_doubles_logical_capacity() {
1163        let alignment = Alignment::new(64);
1164        let mut buffer = BufferMut::<u8>::empty_aligned(alignment);
1165
1166        buffer.push(0);
1167        let capacity = buffer.capacity();
1168        assert_eq!(capacity, Alignment::DEFAULT_ALIGNMENT.as_usize());
1169
1170        buffer.reserve(capacity);
1171        assert_eq!(buffer.capacity(), capacity * 2);
1172    }
1173
1174    #[test]
1175    fn static_growth_copies_live_data() {
1176        let mut buffer = BufferMut::<u32>::with_capacity(1);
1177        let capacity = buffer.capacity();
1178        buffer.extend(std::iter::repeat_n(7, capacity));
1179        let old_ptr = buffer.as_ptr();
1180
1181        buffer.push(u32::MAX);
1182
1183        assert_ne!(buffer.as_ptr(), old_ptr);
1184        assert_eq!(&buffer[..capacity], vec![7; capacity]);
1185        assert_eq!(buffer[capacity], u32::MAX);
1186    }
1187
1188    #[test]
1189    fn growth_of_sliced_buffer_preserves_allocator_and_values() {
1190        let allocator = BufferAllocatorRef::new(Global);
1191        let mut buffer = BufferMut::<u32>::with_capacity_preferred_aligned_in(
1192            1024,
1193            Alignment::of::<u32>(),
1194            None,
1195            allocator.clone(),
1196        );
1197        buffer.extend_from_slice(&[7; 1024]);
1198        let sliced_ptr = buffer.as_ptr().wrapping_add(1016);
1199        let sliced = buffer.freeze().slice(1016..);
1200        let mut buffer = sliced.try_into_mut().unwrap();
1201        assert_eq!(buffer.as_ptr(), sliced_ptr);
1202
1203        // The slice retains a large backing allocation, but needs only a small capacity increase.
1204        buffer.extend_from_slice(&[8; 16]);
1205
1206        assert!(buffer.allocator().ptr_eq(&allocator));
1207        assert_eq!(&buffer[..8], &[7; 8]);
1208        assert_eq!(&buffer[8..], &[8; 16]);
1209    }
1210
1211    #[test]
1212    fn raising_logical_alignment_preserves_capacity() {
1213        let buffer =
1214            BufferMut::<u8>::with_capacity_preferred_aligned(1, Alignment::of::<u8>(), None);
1215        let capacity = buffer.capacity();
1216
1217        let mut buffer = buffer.aligned(Alignment::new(2));
1218
1219        assert_eq!(buffer.capacity(), capacity);
1220        buffer.extend(0..100);
1221        assert!(Alignment::new(2).is_ptr_aligned(buffer.as_ptr()));
1222        assert_eq!(buffer.as_slice(), (0..100).collect::<Vec<_>>());
1223    }
1224
1225    #[test]
1226    fn from_iter() {
1227        let buf = BufferMut::from_iter([0, 10, 20, 30]);
1228        assert_eq!(buf.as_slice(), &[0, 10, 20, 30]);
1229    }
1230
1231    #[test]
1232    fn try_from_trusted_len_iter_ok() {
1233        let buf = BufferMut::<i32>::try_from_trusted_len_iter(
1234            [0, 10, 20, 30].iter().map(|&v| Ok::<_, ()>(v)),
1235        )
1236        .unwrap();
1237        assert_eq!(buf.as_slice(), &[0, 10, 20, 30]);
1238    }
1239
1240    #[test]
1241    fn try_from_trusted_len_iter_err() {
1242        let result: Result<BufferMut<i32>, &'static str> = BufferMut::try_from_trusted_len_iter(
1243            [0, 10, 20, 30]
1244                .iter()
1245                .map(|&v| if v == 20 { Err("bad") } else { Ok(v) }),
1246        );
1247        assert_eq!(result.err(), Some("bad"));
1248    }
1249
1250    #[test]
1251    fn try_extend_trusted_retains_values_before_error() {
1252        let mut buf = BufferMut::from_iter([0, 10]);
1253        let result = buf.try_extend_trusted([Ok(20), Err("bad"), Ok(30)].into_iter());
1254
1255        assert_eq!(result, Err("bad"));
1256        assert_eq!(buf.as_slice(), &[0, 10, 20]);
1257    }
1258
1259    #[test]
1260    fn extend() {
1261        let mut buf = BufferMut::empty();
1262        buf.extend([0i32, 10, 20, 30]);
1263        buf.extend([40, 50, 60]);
1264        assert_eq!(buf.as_slice(), &[0, 10, 20, 30, 40, 50, 60]);
1265    }
1266
1267    #[test]
1268    fn push() {
1269        let mut buf = BufferMut::empty();
1270        buf.push(1);
1271        buf.push(2);
1272        buf.push(3);
1273        assert_eq!(buf.as_slice(), &[1, 2, 3]);
1274    }
1275
1276    #[test]
1277    fn push_n() {
1278        let mut buf = BufferMut::empty();
1279        buf.push_n(0, 100);
1280        assert_eq!(buf.as_slice(), &[0; 100]);
1281    }
1282
1283    #[test]
1284    fn as_mut() {
1285        let mut buf = buffer_mut![0, 1, 2];
1286        // Uses DerefMut
1287        buf[1] = 0;
1288        // Uses as_mut
1289        buf.as_mut()[2] = 0;
1290        assert_eq!(buf.as_slice(), &[0, 0, 0]);
1291    }
1292
1293    #[test]
1294    fn map_each() {
1295        let buf = buffer_mut![0i32, 1, 2];
1296        // Add one, and cast to an unsigned u32 in the same closure
1297        let buf = buf.map_each_in_place(|i| (i + 1) as u32);
1298        assert_eq!(buf.as_slice(), &[1u32, 2, 3]);
1299    }
1300
1301    #[test]
1302    fn buffer_mut_zeroed() {
1303        const LEN: usize = 17;
1304
1305        let mut buf = BufferMut::<u32>::zeroed(LEN);
1306
1307        assert_eq!(
1308            buf.as_ptr().align_offset(Alignment::of::<u32>().as_usize()),
1309            0
1310        );
1311        assert_eq!(buf.as_slice(), &[0; LEN]);
1312
1313        buf[3] = 7;
1314        assert_eq!(buf.as_slice()[3], 7);
1315    }
1316
1317    #[test]
1318    fn buffer_mut_zeroed_aligned() {
1319        const LEN: usize = 17;
1320        let alignment = Alignment::new(64);
1321
1322        let mut buf = BufferMut::<u32>::zeroed_aligned(LEN, alignment);
1323
1324        assert_eq!(buf.as_ptr().align_offset(alignment.as_usize()), 0);
1325        assert_eq!(buf.as_slice(), &[0; LEN]);
1326
1327        buf[3] = 7;
1328        assert_eq!(buf.as_slice()[3], 7);
1329    }
1330}