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 vortex_panic!(
129 "Alignment {} must align to the scalar type's alignment {}",
130 alignment,
131 align_of::<T>()
132 );
133 }
134
135 let size = capacity
136 .checked_mul(size_of::<T>())
137 .vortex_expect("buffer capacity overflow");
138 let layout = if size == 0 {
139 Layout::from_size_align(0, actual.as_usize())
140 .unwrap_or_else(|_| vortex_panic!("invalid empty buffer alignment"))
141 } else {
142 let allocation_size = size
143 .checked_add(actual.as_usize())
144 .vortex_expect("buffer capacity overflow");
145 Layout::from_size_align(allocation_size, 1).unwrap_or_else(|_| {
146 vortex_panic!("buffer capacity exceeds maximum allocation size")
147 })
148 };
149 let allocation = Allocation::allocate(layout, allocator);
150 let offset = allocation.ptr().as_ptr().align_offset(actual.as_usize());
151 let ptr = unsafe { allocation.ptr().add(offset).cast() };
153 let capacity = (allocation.size() - offset) / size_of::<T>();
154 Self {
155 allocation,
156 ptr,
157 length: 0,
158 capacity,
159 alignment,
160 _marker: Default::default(),
161 }
162 }
163
164 pub fn zeroed(len: usize) -> Self {
166 Self::zeroed_in(len, BufferAllocatorRef::statically_allocated())
167 }
168
169 pub fn zeroed_in(len: usize, allocator: BufferAllocatorRef) -> Self {
171 Self::zeroed_aligned_in(len, Alignment::of::<T>(), allocator)
172 }
173
174 pub fn zeroed_aligned(len: usize, alignment: Alignment) -> Self {
181 Self::zeroed_aligned_in(len, alignment, BufferAllocatorRef::statically_allocated())
182 }
183
184 pub fn zeroed_aligned_in(
186 len: usize,
187 alignment: Alignment,
188 allocator: BufferAllocatorRef,
189 ) -> Self {
190 Self::zeroed_preferred_aligned_in(
191 len,
192 alignment,
193 Some(Alignment::DEFAULT_ALIGNMENT),
194 allocator,
195 )
196 }
197
198 pub fn zeroed_preferred_aligned(
203 len: usize,
204 alignment: Alignment,
205 preferred_alignment: Option<Alignment>,
206 ) -> Self {
207 Self::zeroed_preferred_aligned_in(
208 len,
209 alignment,
210 preferred_alignment,
211 BufferAllocatorRef::statically_allocated(),
212 )
213 }
214
215 pub fn zeroed_preferred_aligned_in(
217 len: usize,
218 alignment: Alignment,
219 preferred_alignment: Option<Alignment>,
220 allocator: BufferAllocatorRef,
221 ) -> Self {
222 const { assert!(size_of::<T>() != 0, "ZSTs are not supported") };
223 let preferred_alignment = preferred_alignment.unwrap_or(Alignment::of::<u8>());
224 let actual_alignment = max(preferred_alignment, alignment);
225 let size = len
226 .checked_mul(size_of::<T>())
227 .vortex_expect("buffer length overflow");
228 let layout = if size == 0 {
229 Layout::from_size_align(0, actual_alignment.as_usize())
230 .unwrap_or_else(|_| vortex_panic!("invalid empty buffer alignment"))
231 } else {
232 let allocation_size = size
233 .checked_add(actual_alignment.as_usize())
234 .vortex_expect("buffer length overflow");
235 Layout::from_size_align(allocation_size, 1)
236 .unwrap_or_else(|_| vortex_panic!("buffer length exceeds maximum allocation size"))
237 };
238 let allocation = Allocation::allocate_zeroed(layout, allocator);
239 let offset = allocation
240 .ptr()
241 .as_ptr()
242 .align_offset(actual_alignment.as_usize());
243 let ptr = unsafe { allocation.ptr().add(offset).cast() };
245 let capacity = (allocation.size() - offset) / size_of::<T>();
246 Self {
247 allocation,
248 ptr,
249 length: len,
250 capacity,
251 alignment,
252 _marker: Default::default(),
253 }
254 }
255
256 pub fn empty() -> Self {
258 Self::empty_aligned(Alignment::of::<T>())
259 }
260
261 pub fn empty_aligned(alignment: Alignment) -> Self {
268 Self::empty_aligned_in(alignment, BufferAllocatorRef::statically_allocated())
269 }
270
271 pub fn empty_aligned_in(alignment: Alignment, allocator: BufferAllocatorRef) -> Self {
273 Self::with_capacity_aligned_in(0, alignment, allocator)
274 }
275
276 pub fn empty_preferred_aligned(
281 alignment: Alignment,
282 preferred_alignment: Option<Alignment>,
283 ) -> Self {
284 BufferMut::with_capacity_preferred_aligned_in(
285 0,
286 alignment,
287 preferred_alignment,
288 BufferAllocatorRef::statically_allocated(),
289 )
290 }
291
292 pub fn full(item: T, len: usize) -> Self
294 where
295 T: Copy,
296 {
297 Self::full_in(item, len, BufferAllocatorRef::statically_allocated())
298 }
299
300 pub fn full_in(item: T, len: usize, allocator: BufferAllocatorRef) -> Self
302 where
303 T: Copy,
304 {
305 let mut buffer = BufferMut::<T>::with_capacity_in(len, allocator);
306 buffer.push_n(item, len);
307 buffer
308 }
309
310 pub fn copy_from(other: impl AsRef<[T]>) -> Self {
312 Self::copy_from_in(other, BufferAllocatorRef::statically_allocated())
313 }
314
315 pub fn copy_from_in(other: impl AsRef<[T]>, allocator: BufferAllocatorRef) -> Self {
317 Self::copy_from_aligned_in(other, Alignment::of::<T>(), allocator)
318 }
319
320 pub fn copy_from_aligned(other: impl AsRef<[T]>, alignment: Alignment) -> Self {
331 Self::copy_from_aligned_in(other, alignment, BufferAllocatorRef::statically_allocated())
332 }
333
334 pub fn copy_from_aligned_in(
336 other: impl AsRef<[T]>,
337 alignment: Alignment,
338 allocator: BufferAllocatorRef,
339 ) -> Self {
340 Self::copy_from_preferred_aligned_in(
341 other,
342 alignment,
343 Some(Alignment::DEFAULT_ALIGNMENT),
344 allocator,
345 )
346 }
347
348 pub fn copy_from_preferred_aligned(
357 other: impl AsRef<[T]>,
358 alignment: Alignment,
359 preferred_alignment: Option<Alignment>,
360 ) -> Self {
361 Self::copy_from_preferred_aligned_in(
362 other,
363 alignment,
364 preferred_alignment,
365 BufferAllocatorRef::statically_allocated(),
366 )
367 }
368
369 pub fn copy_from_preferred_aligned_in(
371 other: impl AsRef<[T]>,
372 alignment: Alignment,
373 preferred_alignment: Option<Alignment>,
374 allocator: BufferAllocatorRef,
375 ) -> Self {
376 if !alignment.is_aligned_to(Alignment::of::<T>()) {
377 vortex_panic!("Given alignment is not aligned to type T")
378 }
379 let other = other.as_ref();
380 let mut buffer = Self::with_capacity_preferred_aligned_in(
381 other.len(),
382 alignment,
383 preferred_alignment,
384 allocator,
385 );
386 buffer.extend_from_slice(other);
387 debug_assert_eq!(buffer.alignment(), alignment);
388 buffer
389 }
390
391 #[allow(clippy::inline_always)]
393 #[inline(always)]
394 pub fn alignment(&self) -> Alignment {
395 self.alignment
396 }
397
398 pub fn allocator(&self) -> &BufferAllocatorRef {
400 self.allocation.allocator()
401 }
402
403 #[allow(clippy::inline_always)]
405 #[inline(always)]
406 pub fn len(&self) -> usize {
407 self.length
408 }
409
410 #[allow(clippy::inline_always)]
412 #[inline(always)]
413 pub fn is_empty(&self) -> bool {
414 self.length == 0
415 }
416
417 #[inline]
419 pub fn capacity(&self) -> usize {
420 self.capacity
421 }
422
423 #[allow(clippy::inline_always)]
425 #[inline(always)]
426 pub fn as_ptr(&self) -> *const T {
427 self.ptr.as_ptr()
428 }
429
430 #[allow(clippy::inline_always)]
432 #[inline(always)]
433 pub fn as_mut_ptr(&mut self) -> *mut T {
434 self.ptr.as_ptr()
435 }
436
437 #[inline]
439 pub fn as_slice(&self) -> &[T] {
440 unsafe { std::slice::from_raw_parts(self.as_ptr(), self.length) }
442 }
443
444 #[inline]
446 pub fn as_mut_slice(&mut self) -> &mut [T] {
447 unsafe { std::slice::from_raw_parts_mut(self.as_mut_ptr(), self.length) }
449 }
450
451 #[inline]
453 pub fn clear(&mut self) {
454 self.length = 0;
455 }
456
457 #[inline]
465 pub fn truncate(&mut self, len: usize) {
466 if len <= self.len() {
467 unsafe { self.set_len(len) };
469 }
470 }
471
472 #[inline]
474 pub fn reserve(&mut self, additional: usize) {
475 if additional <= self.capacity() - self.length {
476 return;
478 }
479
480 self.reserve_allocate(additional);
482 }
483
484 fn reserve_allocate(&mut self, additional: usize) {
486 let required = self
487 .length
488 .checked_add(additional)
489 .vortex_expect("buffer capacity overflow");
490 let required_size = required
491 .checked_mul(size_of::<T>())
492 .vortex_expect("buffer capacity overflow");
493 let alignment = self.alignment;
494 let current_size = self
495 .capacity
496 .checked_mul(size_of::<T>())
497 .vortex_expect("buffer capacity overflow");
498 let logical_size = required_size
499 .max(current_size.saturating_mul(2))
500 .max(Alignment::DEFAULT_ALIGNMENT.as_usize());
501 let allocation_size = logical_size
502 .checked_add(alignment.as_usize())
503 .vortex_expect("buffer capacity overflow");
504 let allocation_alignment = if self.allocation.size() == 0 {
505 1
506 } else {
507 self.allocation.alignment()
508 };
509 let layout = Layout::from_size_align(allocation_size, allocation_alignment)
510 .unwrap_or_else(|_| vortex_panic!("buffer capacity exceeds maximum allocation size"));
511
512 let old_offset = self.ptr.cast::<u8>().addr().get() - self.allocation.ptr().addr().get();
513 let new_offset = if self.allocation.allocator().is_statically_allocated() {
514 let allocation =
515 Allocation::allocate(layout, BufferAllocatorRef::statically_allocated());
516 let new_offset = allocation.ptr().as_ptr().align_offset(alignment.as_usize());
517 unsafe {
519 std::ptr::copy_nonoverlapping(
520 self.ptr.cast::<u8>().as_ptr(),
521 allocation.ptr().as_ptr().add(new_offset),
522 self.length * size_of::<T>(),
523 );
524 }
525 self.allocation = allocation;
526 new_offset
527 } else {
528 self.allocation.grow(layout);
529 let new_offset = self
530 .allocation
531 .ptr()
532 .as_ptr()
533 .align_offset(alignment.as_usize());
534 if new_offset != old_offset {
535 unsafe {
539 std::ptr::copy(
540 self.allocation.ptr().as_ptr().add(old_offset),
541 self.allocation.ptr().as_ptr().add(new_offset),
542 self.length * size_of::<T>(),
543 );
544 }
545 }
546 new_offset
547 };
548 self.ptr = unsafe { self.allocation.ptr().add(new_offset).cast() };
550 self.capacity = logical_size / size_of::<T>();
551 }
552
553 #[inline]
589 pub fn spare_capacity_mut(&mut self) -> &mut [MaybeUninit<T>] {
590 let dst = unsafe { self.as_mut_ptr().add(self.length) }.cast::<MaybeUninit<T>>();
592 unsafe { std::slice::from_raw_parts_mut(dst, self.capacity() - self.length) }
593 }
594
595 #[inline]
604 pub unsafe fn set_len(&mut self, len: usize) {
605 debug_assert!(len <= self.capacity());
606 self.length = len;
607 }
608
609 #[inline]
611 pub fn push(&mut self, value: T) {
612 self.reserve(1);
613 unsafe { self.push_unchecked(value) }
614 }
615
616 #[inline]
622 pub unsafe fn push_unchecked(&mut self, item: T) {
623 unsafe {
625 let dst = self.as_mut_ptr().add(self.length);
626 dst.write(item);
627 }
628 self.length += 1;
629 }
630
631 #[inline]
635 pub fn push_n(&mut self, item: T, n: usize)
636 where
637 T: Copy,
638 {
639 self.reserve(n);
640 unsafe { self.push_n_unchecked(item, n) }
641 }
642
643 #[inline]
649 pub unsafe fn push_n_unchecked(&mut self, item: T, n: usize)
650 where
651 T: Copy,
652 {
653 let mut dst = unsafe { self.as_mut_ptr().add(self.length) };
655 unsafe {
657 let end = dst.add(n);
658 while dst < end {
659 dst.write(item);
660 dst = dst.add(1);
661 }
662 }
663 self.length += n;
664 }
665
666 #[inline]
679 pub fn extend_from_slice(&mut self, slice: &[T]) {
680 self.reserve(slice.len());
681 unsafe {
683 std::ptr::copy_nonoverlapping(
684 slice.as_ptr(),
685 self.as_mut_ptr().add(self.length),
686 slice.len(),
687 );
688 }
689 self.length += slice.len();
690 }
691
692 pub fn into_byte_buffer(self) -> ByteBufferMut {
694 let capacity = self
695 .capacity
696 .checked_mul(size_of::<T>())
697 .vortex_expect("buffer capacity overflow");
698 ByteBufferMut {
699 allocation: self.allocation,
700 ptr: self.ptr.cast(),
701 length: self.length * size_of::<T>(),
702 capacity,
703 alignment: self.alignment,
704 _marker: Default::default(),
705 }
706 }
707
708 pub fn freeze(self) -> Buffer<T> {
710 let offset = self.ptr.cast::<u8>().addr().get() - self.allocation.ptr().addr().get();
711 Buffer::from_allocation(self.allocation, offset, self.length, self.alignment)
712 }
713
714 pub fn map_each_in_place<R, F>(self, mut f: F) -> BufferMut<R>
716 where
717 T: Copy,
718 F: FnMut(T) -> R,
719 {
720 assert_eq!(
721 size_of::<T>(),
722 size_of::<R>(),
723 "Size of T and R do not match"
724 );
725 let mut buf: BufferMut<R> = unsafe { std::mem::transmute(self) };
727 buf.iter_mut()
728 .for_each(|item| *item = f(unsafe { std::mem::transmute_copy(item) }));
729 buf
730 }
731
732 pub fn aligned(self, alignment: Alignment) -> Self {
738 if self.as_ptr().align_offset(alignment.as_usize()) == 0 {
739 Self { alignment, ..self }
740 } else {
741 let capacity = self.capacity();
742 let allocator = self.allocation.allocator().clone();
743 let mut aligned = Self::with_capacity_aligned_in(capacity, alignment, allocator);
744 aligned.extend_from_slice(&self);
745 aligned.capacity = capacity;
746 aligned
747 }
748 }
749
750 pub unsafe fn transmute<U>(self) -> BufferMut<U> {
762 assert_eq!(size_of::<T>(), size_of::<U>(), "Buffer type size mismatch");
763 assert_eq!(
764 align_of::<T>(),
765 align_of::<U>(),
766 "Buffer type alignment mismatch"
767 );
768
769 BufferMut {
770 allocation: self.allocation,
771 ptr: self.ptr.cast(),
772 length: self.length,
773 capacity: self.capacity,
774 alignment: self.alignment,
775 _marker: std::marker::PhantomData,
776 }
777 }
778}
779
780impl<T> Clone for BufferMut<T> {
781 fn clone(&self) -> Self {
782 let mut buffer = BufferMut::<T>::with_capacity_aligned_in(
783 self.capacity(),
784 self.alignment,
785 self.allocation.allocator().clone(),
786 );
787 buffer.extend_from_slice(self.as_slice());
788 buffer
789 }
790}
791
792impl<T: PartialEq> PartialEq for BufferMut<T> {
793 fn eq(&self, other: &Self) -> bool {
794 self.as_slice() == other.as_slice()
795 }
796}
797
798impl<T: Eq> Eq for BufferMut<T> {}
799
800impl<T: Debug> Debug for BufferMut<T> {
801 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
802 f.debug_struct(&format!("BufferMut<{}>", type_name::<T>()))
803 .field("length", &self.length)
804 .field("alignment", &self.alignment)
805 .field("as_slice", &TruncatedDebug(self.as_slice()))
806 .finish()
807 }
808}
809
810impl<T> Default for BufferMut<T> {
811 fn default() -> Self {
812 Self::empty()
813 }
814}
815
816impl<T> Deref for BufferMut<T> {
817 type Target = [T];
818
819 #[inline]
820 fn deref(&self) -> &Self::Target {
821 self.as_slice()
822 }
823}
824
825impl<T> DerefMut for BufferMut<T> {
826 #[inline]
827 fn deref_mut(&mut self) -> &mut Self::Target {
828 self.as_mut_slice()
829 }
830}
831
832impl<T> AsRef<[T]> for BufferMut<T> {
833 #[inline]
834 fn as_ref(&self) -> &[T] {
835 self.as_slice()
836 }
837}
838
839impl<T> AsMut<[T]> for BufferMut<T> {
840 #[inline]
841 fn as_mut(&mut self) -> &mut [T] {
842 self.as_mut_slice()
843 }
844}
845
846impl<T> BufferMut<T> {
847 fn extend_iter(&mut self, mut iter: impl Iterator<Item = T>) {
852 let (lower_bound, _) = iter.size_hint();
855
856 self.reserve(lower_bound);
859
860 let unwritten = self.capacity() - self.len();
861
862 let begin: *const T = self.spare_capacity_mut().as_mut_ptr().cast();
864 let mut dst: *mut T = begin.cast_mut();
865
866 for _ in 0..unwritten {
868 let Some(item) = iter.next() else {
869 break;
871 };
872
873 unsafe { dst.write(item) };
876
877 unsafe { dst = dst.add(1) };
882 }
883
884 let items_written = unsafe { dst.offset_from_unsigned(begin) };
887 let length = self.len() + items_written;
888
889 unsafe { self.set_len(length) };
891
892 iter.for_each(|item| self.push(item));
895 }
896
897 pub fn extend_trusted<I: TrustedLen<Item = T>>(&mut self, iter: I) {
902 let (_, upper_bound) = iter.size_hint();
903 self.reserve(
904 upper_bound
905 .vortex_expect("`TrustedLen` iterator somehow didn't have valid upper bound"),
906 );
907
908 let begin: *const T = self.spare_capacity_mut().as_mut_ptr().cast();
909 let mut dst: *mut T = begin.cast_mut();
910
911 iter.for_each(|item| {
912 unsafe { dst.write(item) };
915
916 unsafe { dst = dst.add(1) };
921 });
922
923 let items_written = unsafe { dst.offset_from_unsigned(begin) };
926 let length = self.len() + items_written;
927
928 unsafe { self.set_len(length) };
930 }
931
932 pub fn from_trusted_len_iter<I>(iter: I) -> Self
936 where
937 I: TrustedLen<Item = T>,
938 {
939 let (_, upper_bound) = iter.size_hint();
940 let mut buffer = Self::with_capacity(
941 upper_bound
942 .vortex_expect("`TrustedLen` iterator somehow didn't have valid upper bound"),
943 );
944
945 buffer.extend_trusted(iter);
946 buffer
947 }
948
949 pub fn try_extend_trusted<E, I>(&mut self, iter: I) -> Result<(), E>
954 where
955 I: TrustedLen<Item = Result<T, E>>,
956 {
957 iter.process_results(|values| self.extend_trusted(values))
958 }
959
960 pub fn try_from_trusted_len_iter<E, I>(iter: I) -> Result<Self, E>
963 where
964 I: TrustedLen<Item = Result<T, E>>,
965 {
966 iter.process_results(|values| Self::from_trusted_len_iter(values))
967 }
968}
969
970impl<T> Extend<T> for BufferMut<T> {
971 #[inline]
972 fn extend<I: IntoIterator<Item = T>>(&mut self, iter: I) {
973 self.extend_iter(iter.into_iter())
974 }
975}
976
977impl<'a, T> Extend<&'a T> for BufferMut<T>
978where
979 T: Copy + 'a,
980{
981 #[inline]
982 fn extend<I: IntoIterator<Item = &'a T>>(&mut self, iter: I) {
983 self.extend_iter(iter.into_iter().copied())
984 }
985}
986
987impl<T> FromIterator<T> for BufferMut<T> {
988 fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self {
989 let iter = iter.into_iter();
990 let mut buffer = Self::with_capacity(iter.size_hint().0);
991 buffer.extend(iter);
992 buffer
993 }
994}
995
996#[cfg(test)]
997mod test {
998 use crate::Alignment;
999 use crate::BufferMut;
1000 use crate::buffer_mut;
1001
1002 #[test]
1003 fn capacity() {
1004 let mut n = 57;
1005 let mut buf = BufferMut::<i32>::with_capacity_aligned(n, Alignment::new(1024));
1006 assert!(buf.capacity() >= 57);
1007
1008 while n > 0 {
1009 buf.push(0);
1010 assert!(buf.capacity() >= n);
1011 n -= 1
1012 }
1013
1014 assert_eq!(buf.alignment(), Alignment::new(1024));
1015 }
1016
1017 #[test]
1018 fn growth_preserves_alignment_and_values() {
1019 let alignment = Alignment::new(4096);
1020 let mut buffer = BufferMut::<u64>::with_capacity_aligned(1, alignment);
1021
1022 for value in 0..10_000 {
1023 buffer.push(value);
1024 assert!(alignment.is_offset_aligned(buffer.as_ptr().addr()));
1025 }
1026
1027 assert_eq!(buffer.as_slice(), (0..10_000).collect::<Vec<_>>());
1028 }
1029
1030 #[test]
1031 fn growth_seeds_and_doubles_logical_capacity() {
1032 let alignment = Alignment::new(64);
1033 let mut buffer = BufferMut::<u8>::empty_aligned(alignment);
1034
1035 buffer.push(0);
1036 let capacity = buffer.capacity();
1037 assert_eq!(capacity, Alignment::DEFAULT_ALIGNMENT.as_usize());
1038
1039 buffer.reserve(capacity);
1040 assert_eq!(buffer.capacity(), capacity * 2);
1041 }
1042
1043 #[test]
1044 fn static_growth_copies_live_data() {
1045 let mut buffer = BufferMut::<u32>::with_capacity(1);
1046 let capacity = buffer.capacity();
1047 buffer.extend(std::iter::repeat_n(7, capacity));
1048 let old_ptr = buffer.as_ptr();
1049
1050 buffer.push(u32::MAX);
1051
1052 assert_ne!(buffer.as_ptr(), old_ptr);
1053 assert_eq!(&buffer[..capacity], vec![7; capacity]);
1054 assert_eq!(buffer[capacity], u32::MAX);
1055 }
1056
1057 #[test]
1058 fn raising_logical_alignment_preserves_capacity() {
1059 let buffer =
1060 BufferMut::<u8>::with_capacity_preferred_aligned(1, Alignment::of::<u8>(), None);
1061 let capacity = buffer.capacity();
1062
1063 let mut buffer = buffer.aligned(Alignment::new(2));
1064
1065 assert_eq!(buffer.capacity(), capacity);
1066 buffer.extend(0..100);
1067 assert!(Alignment::new(2).is_ptr_aligned(buffer.as_ptr()));
1068 assert_eq!(buffer.as_slice(), (0..100).collect::<Vec<_>>());
1069 }
1070
1071 #[test]
1072 fn from_iter() {
1073 let buf = BufferMut::from_iter([0, 10, 20, 30]);
1074 assert_eq!(buf.as_slice(), &[0, 10, 20, 30]);
1075 }
1076
1077 #[test]
1078 fn try_from_trusted_len_iter_ok() {
1079 let buf = BufferMut::<i32>::try_from_trusted_len_iter(
1080 [0, 10, 20, 30].iter().map(|&v| Ok::<_, ()>(v)),
1081 )
1082 .unwrap();
1083 assert_eq!(buf.as_slice(), &[0, 10, 20, 30]);
1084 }
1085
1086 #[test]
1087 fn try_from_trusted_len_iter_err() {
1088 let result: Result<BufferMut<i32>, &'static str> = BufferMut::try_from_trusted_len_iter(
1089 [0, 10, 20, 30]
1090 .iter()
1091 .map(|&v| if v == 20 { Err("bad") } else { Ok(v) }),
1092 );
1093 assert_eq!(result.err(), Some("bad"));
1094 }
1095
1096 #[test]
1097 fn try_extend_trusted_retains_values_before_error() {
1098 let mut buf = BufferMut::from_iter([0, 10]);
1099 let result = buf.try_extend_trusted([Ok(20), Err("bad"), Ok(30)].into_iter());
1100
1101 assert_eq!(result, Err("bad"));
1102 assert_eq!(buf.as_slice(), &[0, 10, 20]);
1103 }
1104
1105 #[test]
1106 fn extend() {
1107 let mut buf = BufferMut::empty();
1108 buf.extend([0i32, 10, 20, 30]);
1109 buf.extend([40, 50, 60]);
1110 assert_eq!(buf.as_slice(), &[0, 10, 20, 30, 40, 50, 60]);
1111 }
1112
1113 #[test]
1114 fn push() {
1115 let mut buf = BufferMut::empty();
1116 buf.push(1);
1117 buf.push(2);
1118 buf.push(3);
1119 assert_eq!(buf.as_slice(), &[1, 2, 3]);
1120 }
1121
1122 #[test]
1123 fn push_n() {
1124 let mut buf = BufferMut::empty();
1125 buf.push_n(0, 100);
1126 assert_eq!(buf.as_slice(), &[0; 100]);
1127 }
1128
1129 #[test]
1130 fn as_mut() {
1131 let mut buf = buffer_mut![0, 1, 2];
1132 buf[1] = 0;
1134 buf.as_mut()[2] = 0;
1136 assert_eq!(buf.as_slice(), &[0, 0, 0]);
1137 }
1138
1139 #[test]
1140 fn map_each() {
1141 let buf = buffer_mut![0i32, 1, 2];
1142 let buf = buf.map_each_in_place(|i| (i + 1) as u32);
1144 assert_eq!(buf.as_slice(), &[1u32, 2, 3]);
1145 }
1146
1147 #[test]
1148 fn buffer_mut_zeroed() {
1149 const LEN: usize = 17;
1150
1151 let mut buf = BufferMut::<u32>::zeroed(LEN);
1152
1153 assert_eq!(
1154 buf.as_ptr().align_offset(Alignment::of::<u32>().as_usize()),
1155 0
1156 );
1157 assert_eq!(buf.as_slice(), &[0; LEN]);
1158
1159 buf[3] = 7;
1160 assert_eq!(buf.as_slice()[3], 7);
1161 }
1162
1163 #[test]
1164 fn buffer_mut_zeroed_aligned() {
1165 const LEN: usize = 17;
1166 let alignment = Alignment::new(64);
1167
1168 let mut buf = BufferMut::<u32>::zeroed_aligned(LEN, alignment);
1169
1170 assert_eq!(buf.as_ptr().align_offset(alignment.as_usize()), 0);
1171 assert_eq!(buf.as_slice(), &[0; LEN]);
1172
1173 buf[3] = 7;
1174 assert_eq!(buf.as_slice()[3], 7);
1175 }
1176}