1use 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
25pub struct BufferMut<T> {
39 pub(crate) allocation: Allocation,
41 pub(crate) ptr: std::ptr::NonNull<T>,
43 pub(crate) length: usize,
45 pub(crate) capacity: usize,
47 pub(crate) alignment: Alignment,
49 pub(crate) _marker: std::marker::PhantomData<T>,
51}
52
53unsafe impl<T: Send> Send for BufferMut<T> {}
55unsafe impl<T: Sync> Sync for BufferMut<T> {}
57
58impl<T> BufferMut<T> {
59 pub fn with_capacity(capacity: usize) -> Self {
61 Self::with_capacity_in(capacity, BufferAllocatorRef::statically_allocated())
62 }
63
64 pub fn with_capacity_in(capacity: usize, allocator: BufferAllocatorRef) -> Self {
66 Self::with_capacity_aligned_in(capacity, Alignment::of::<T>(), allocator)
67 }
68
69 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 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 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 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 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 pub fn zeroed(len: usize) -> Self {
162 Self::zeroed_in(len, BufferAllocatorRef::statically_allocated())
163 }
164
165 pub fn zeroed_in(len: usize, allocator: BufferAllocatorRef) -> Self {
167 Self::zeroed_aligned_in(len, Alignment::of::<T>(), allocator)
168 }
169
170 pub fn zeroed_aligned(len: usize, alignment: Alignment) -> Self {
177 Self::zeroed_aligned_in(len, alignment, BufferAllocatorRef::statically_allocated())
178 }
179
180 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 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 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 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 pub fn empty() -> Self {
254 Self::empty_aligned(Alignment::of::<T>())
255 }
256
257 pub fn empty_aligned(alignment: Alignment) -> Self {
264 Self::empty_aligned_in(alignment, BufferAllocatorRef::statically_allocated())
265 }
266
267 pub fn empty_aligned_in(alignment: Alignment, allocator: BufferAllocatorRef) -> Self {
269 Self::with_capacity_aligned_in(0, alignment, allocator)
270 }
271
272 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 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 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 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 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 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 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 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 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 #[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 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 #[allow(clippy::inline_always)]
426 #[inline(always)]
427 pub fn len(&self) -> usize {
428 self.length
429 }
430
431 #[allow(clippy::inline_always)]
433 #[inline(always)]
434 pub fn is_empty(&self) -> bool {
435 self.length == 0
436 }
437
438 #[inline]
440 pub fn capacity(&self) -> usize {
441 self.capacity
442 }
443
444 #[allow(clippy::inline_always)]
446 #[inline(always)]
447 pub fn as_ptr(&self) -> *const T {
448 self.ptr.as_ptr()
449 }
450
451 #[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 #[inline]
460 pub fn as_slice(&self) -> &[T] {
461 unsafe { std::slice::from_raw_parts(self.as_ptr(), self.length) }
463 }
464
465 #[inline]
467 pub fn as_mut_slice(&mut self) -> &mut [T] {
468 unsafe { std::slice::from_raw_parts_mut(self.as_mut_ptr(), self.length) }
470 }
471
472 #[inline]
474 pub fn clear(&mut self) {
475 self.length = 0;
476 }
477
478 #[inline]
486 pub fn truncate(&mut self, len: usize) {
487 if len <= self.len() {
488 unsafe { self.set_len(len) };
490 }
491 }
492
493 #[inline]
495 pub fn reserve(&mut self, additional: usize) {
496 if additional <= self.capacity() - self.length {
497 return;
499 }
500
501 self.reserve_allocate(additional);
503 }
504
505 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 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 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 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 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 self.ptr = unsafe { self.allocation.ptr().add(data_offset).cast() };
607 self.capacity = new_capacity_bytes / size_of::<T>();
608 }
609
610 #[inline]
646 pub fn spare_capacity_mut(&mut self) -> &mut [MaybeUninit<T>] {
647 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 #[inline]
661 pub unsafe fn set_len(&mut self, len: usize) {
662 debug_assert!(len <= self.capacity());
663 self.length = len;
664 }
665
666 #[inline]
668 pub fn push(&mut self, value: T) {
669 self.reserve(1);
670 unsafe { self.push_unchecked(value) }
671 }
672
673 #[inline]
679 pub unsafe fn push_unchecked(&mut self, item: T) {
680 unsafe {
682 let dst = self.as_mut_ptr().add(self.length);
683 dst.write(item);
684 }
685 self.length += 1;
686 }
687
688 #[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 #[inline]
706 pub unsafe fn push_n_unchecked(&mut self, item: T, n: usize)
707 where
708 T: Copy,
709 {
710 let mut dst = unsafe { self.as_mut_ptr().add(self.length) };
712 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 #[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 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 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 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 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 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 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 fn extend_iter(&mut self, mut iter: impl Iterator<Item = T>) {
925 let (lower_bound, _) = iter.size_hint();
928
929 self.reserve(lower_bound);
932
933 let unwritten = self.capacity() - self.len();
934
935 let begin: *const T = self.spare_capacity_mut().as_mut_ptr().cast();
937 let mut dst: *mut T = begin.cast_mut();
938
939 for _ in 0..unwritten {
941 let Some(item) = iter.next() else {
942 break;
944 };
945
946 unsafe { dst.write(item) };
949
950 unsafe { dst = dst.add(1) };
955 }
956
957 let items_written = unsafe { dst.offset_from_unsigned(begin) };
960 let length = self.len() + items_written;
961
962 unsafe { self.set_len(length) };
964
965 iter.for_each(|item| self.push(item));
968 }
969
970 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 unsafe { dst.write(item) };
988
989 unsafe { dst = dst.add(1) };
994 });
995
996 let items_written = unsafe { dst.offset_from_unsigned(begin) };
999 let length = self.len() + items_written;
1000
1001 unsafe { self.set_len(length) };
1003 }
1004
1005 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 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 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 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 buf[1] = 0;
1288 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 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}