1use std::any::type_name;
5use std::cmp::Ordering;
6use std::collections::Bound;
7use std::fmt::Debug;
8use std::fmt::Formatter;
9use std::hash::Hash;
10use std::hash::Hasher;
11use std::ops::Deref;
12use std::ops::RangeBounds;
13use std::ptr::NonNull;
14use std::sync::Arc;
15
16use bytes::Buf;
17use bytes::Bytes;
18use vortex_error::VortexExpect;
19use vortex_error::vortex_panic;
20
21use crate::Alignment;
22use crate::Allocation;
23use crate::BufferAllocatorRef;
24use crate::BufferBacking;
25use crate::BufferMut;
26use crate::ByteBuffer;
27use crate::debug::TruncatedDebug;
28use crate::trusted_len::TrustedLen;
29
30#[derive(Clone)]
55pub struct Buffer<T> {
56 pub(crate) ptr: NonNull<T>,
58 pub(crate) length: usize,
60 pub(crate) alignment: Alignment,
62 pub(crate) backing: Option<Arc<BufferBacking>>,
64}
65
66unsafe impl<T: Send> Send for Buffer<T> {}
69unsafe impl<T: Sync> Sync for Buffer<T> {}
71
72impl<T> Default for Buffer<T> {
73 fn default() -> Self {
74 Self {
75 ptr: empty_ptr(),
76 length: 0,
77 alignment: Alignment::of::<T>(),
78 backing: None,
79 }
80 }
81}
82
83impl<T: PartialEq> PartialEq for Buffer<T> {
84 #[inline]
85 fn eq(&self, other: &Self) -> bool {
86 self.as_slice() == other.as_slice()
87 }
88}
89
90impl<T: Eq> Eq for Buffer<T> {}
91
92impl<T: Ord> Ord for Buffer<T> {
93 #[inline]
94 fn cmp(&self, other: &Self) -> Ordering {
95 self.as_slice().cmp(other.as_slice())
96 }
97}
98
99impl<T: PartialOrd> PartialOrd for Buffer<T> {
100 #[inline]
101 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
102 self.as_slice().partial_cmp(other.as_slice())
103 }
104}
105
106impl<T: Hash> Hash for Buffer<T> {
107 #[inline]
108 fn hash<H: Hasher>(&self, state: &mut H) {
109 self.as_slice().hash(state)
110 }
111}
112
113impl<T> Buffer<T> {
114 pub(crate) fn from_allocation(
115 allocation: Allocation,
116 offset: usize,
117 length: usize,
118 alignment: Alignment,
119 ) -> Self {
120 let ptr = unsafe { allocation.ptr().add(offset).cast() };
122 Self {
123 ptr,
124 length,
125 alignment,
126 backing: Some(Arc::new(BufferBacking::Owned(allocation))),
127 }
128 }
129
130 fn from_bytes(bytes: Bytes, alignment: Alignment) -> Self {
131 let length = bytes.len() / size_of::<T>();
132 if length == 0 {
133 return Self::empty_aligned(alignment);
134 }
135 let ptr =
136 NonNull::new(bytes.as_ptr().cast_mut().cast()).vortex_expect("Bytes pointer is null");
137 Self {
138 ptr,
139 length,
140 alignment,
141 backing: Some(Arc::new(BufferBacking::Bytes(bytes))),
142 }
143 }
144
145 #[cfg(feature = "arrow")]
146 pub(crate) fn from_arrow_owner(
147 arrow: arrow_buffer::Buffer,
148 length: usize,
149 alignment: Alignment,
150 ) -> Self {
151 if length == 0 {
152 return Self::empty_aligned(alignment);
153 }
154 let ptr = NonNull::new(arrow.as_ptr().cast_mut().cast())
155 .vortex_expect("Arrow buffer pointer is null");
156 Self {
157 ptr,
158 length,
159 alignment,
160 backing: Some(Arc::new(BufferBacking::Arrow(arrow))),
161 }
162 }
163
164 pub fn copy_from(values: impl AsRef<[T]>) -> Self
171 where
172 T: Copy,
173 {
174 BufferMut::copy_from(values).freeze()
175 }
176
177 pub fn copy_from_in(values: impl AsRef<[T]>, allocator: BufferAllocatorRef) -> Self
179 where
180 T: Copy,
181 {
182 BufferMut::copy_from_in(values, allocator).freeze()
183 }
184
185 pub fn copy_from_aligned(values: impl AsRef<[T]>, alignment: Alignment) -> Self
192 where
193 T: Copy,
194 {
195 Self::copy_from_preferred_aligned(values, alignment, Some(Alignment::DEFAULT_ALIGNMENT))
196 }
197
198 pub fn copy_from_preferred_aligned(
203 values: impl AsRef<[T]>,
204 alignment: Alignment,
205 preferred_alignment: Option<Alignment>,
206 ) -> Self
207 where
208 T: Copy,
209 {
210 BufferMut::copy_from_preferred_aligned(values, alignment, preferred_alignment).freeze()
211 }
212
213 pub fn zeroed(len: usize) -> Self {
215 Self::zeroed_aligned(len, Alignment::of::<T>())
216 }
217
218 pub fn zeroed_in(len: usize, allocator: BufferAllocatorRef) -> Self {
220 BufferMut::zeroed_in(len, allocator).freeze()
221 }
222
223 pub fn zeroed_aligned(len: usize, alignment: Alignment) -> Self {
230 Self::zeroed_preferred_aligned(len, alignment, Some(Alignment::DEFAULT_ALIGNMENT))
231 }
232
233 pub fn zeroed_preferred_aligned(
238 len: usize,
239 alignment: Alignment,
240 preferred_alignment: Option<Alignment>,
241 ) -> Self {
242 BufferMut::zeroed_preferred_aligned(len, alignment, preferred_alignment).freeze()
243 }
244
245 pub fn empty() -> Self {
247 Self::empty_aligned(Alignment::of::<T>())
248 }
249
250 pub fn empty_aligned(alignment: Alignment) -> Self {
254 const { assert!(size_of::<T>() != 0, "ZSTs are not supported") };
255 if !alignment.is_aligned_to(Alignment::of::<T>()) {
256 misaligned_scalar_type(alignment, Alignment::of::<T>());
257 }
258 Self {
259 ptr: empty_ptr(),
260 length: 0,
261 alignment,
262 backing: None,
263 }
264 }
265
266 pub fn full(item: T, len: usize) -> Self
268 where
269 T: Copy,
270 {
271 BufferMut::full(item, len).freeze()
272 }
273
274 pub fn full_in(item: T, len: usize, allocator: BufferAllocatorRef) -> Self
276 where
277 T: Copy,
278 {
279 BufferMut::full_in(item, len, allocator).freeze()
280 }
281
282 pub fn from_byte_buffer(buffer: ByteBuffer) -> Self {
289 Self::from_byte_buffer_aligned(buffer, Alignment::of::<T>())
291 }
292
293 pub fn from_byte_buffer_aligned(buffer: ByteBuffer, alignment: Alignment) -> Self {
300 const { assert!(size_of::<T>() != 0, "ZSTs are not supported") };
301 if !alignment.is_aligned_to(Alignment::of::<T>()) {
302 incompatible_scalar_alignment(alignment, Alignment::of::<T>());
303 }
304 if !alignment.is_ptr_aligned(buffer.as_ptr()) {
305 buffer_not_aligned(alignment);
306 }
307 if !buffer.len().is_multiple_of(size_of::<T>()) {
308 buffer_len_not_multiple(buffer.len(), size_of::<T>());
309 }
310 Self {
311 ptr: buffer.ptr.cast(),
312 length: buffer.length / size_of::<T>(),
313 alignment,
314 backing: buffer.backing,
315 }
316 }
317
318 pub fn from_bytes_aligned(bytes: Bytes, alignment: Alignment) -> Self {
325 const { assert!(size_of::<T>() != 0, "ZSTs are not supported") };
326 if !alignment.is_aligned_to(Alignment::of::<T>()) {
327 incompatible_scalar_alignment(alignment, Alignment::of::<T>());
328 }
329 if !alignment.is_ptr_aligned(bytes.as_ptr()) {
330 bytes_not_aligned(alignment);
331 }
332 if !bytes.len().is_multiple_of(size_of::<T>()) {
333 bytes_len_not_multiple(bytes.len(), size_of::<T>());
334 }
335 Self::from_bytes(bytes, alignment)
336 }
337
338 pub fn from_trusted_len_iter<I: TrustedLen<Item = T>>(iter: I) -> Self {
341 BufferMut::from_trusted_len_iter(iter).freeze()
342 }
343
344 pub fn clear(&mut self) {
346 self.length = 0;
347 }
348
349 #[allow(clippy::inline_always)]
351 #[inline(always)]
352 pub fn len(&self) -> usize {
353 self.length
354 }
355
356 #[allow(clippy::inline_always)]
358 #[inline(always)]
359 pub fn is_empty(&self) -> bool {
360 self.length == 0
361 }
362
363 #[allow(clippy::inline_always)]
365 #[inline(always)]
366 pub fn alignment(&self) -> Alignment {
367 self.alignment
368 }
369
370 pub(crate) fn allocator(&self) -> &BufferAllocatorRef {
371 match self.backing.as_deref() {
372 Some(backing) => backing.allocator(),
373 None => BufferAllocatorRef::static_ref(),
374 }
375 }
376
377 #[allow(clippy::inline_always)]
379 #[inline(always)]
380 pub fn as_ptr(&self) -> *const T {
381 self.ptr.as_ptr()
382 }
383
384 #[allow(clippy::inline_always)]
386 #[inline(always)]
387 pub fn as_slice(&self) -> &[T] {
388 unsafe { std::slice::from_raw_parts(self.ptr.as_ptr(), self.length) }
390 }
391
392 #[allow(clippy::inline_always)]
394 #[inline(always)]
395 pub fn as_bytes(&self) -> &[u8] {
396 unsafe {
398 std::slice::from_raw_parts(self.ptr.as_ptr().cast(), size_of_val(self.as_slice()))
399 }
400 }
401
402 pub fn iter(&self) -> Iter<'_, T> {
404 Iter {
405 inner: self.as_slice().iter(),
406 }
407 }
408
409 #[allow(clippy::inline_always)]
416 #[inline(always)]
417 pub fn slice(&self, range: impl RangeBounds<usize>) -> Self {
418 self.slice_with_alignment(range, self.alignment)
419 }
420
421 #[allow(clippy::inline_always)]
428 #[inline(always)]
429 pub fn slice_unaligned(&self, range: impl RangeBounds<usize>) -> Self {
430 self.slice_with_alignment(range, Alignment::of::<u8>())
431 }
432
433 pub fn slice_with_alignment(
441 &self,
442 range: impl RangeBounds<usize>,
443 alignment: Alignment,
444 ) -> Self {
445 let len = self.len();
446 let begin = match range.start_bound() {
447 Bound::Included(&n) => n,
448 Bound::Excluded(&n) => n.checked_add(1).vortex_expect("out of range"),
449 Bound::Unbounded => 0,
450 };
451 let end = match range.end_bound() {
452 Bound::Included(&n) => n.checked_add(1).vortex_expect("out of range"),
453 Bound::Excluded(&n) => n,
454 Bound::Unbounded => len,
455 };
456
457 if begin > end {
458 slice_range_inverted(begin, end);
459 }
460 if end > len {
461 slice_range_out_of_bounds(end, len);
462 }
463
464 if end == begin {
465 return Self::empty_aligned(alignment);
468 }
469
470 let begin_byte = begin * size_of::<T>();
471 if !alignment.is_offset_aligned(begin_byte) {
472 slice_start_misaligned(alignment, begin_byte);
473 }
474 if !alignment.is_aligned_to(Alignment::of::<T>()) {
475 vortex_panic!("Slice alignment must at least align to type T")
476 }
477
478 Self {
479 ptr: unsafe { self.ptr.add(begin) },
481 length: end - begin,
482 alignment,
483 backing: self.backing.clone(),
484 }
485 }
486
487 #[allow(clippy::inline_always)]
496 #[inline(always)]
497 pub fn slice_ref(&self, subset: &[T]) -> Self {
498 self.slice_ref_with_alignment(subset, Alignment::of::<T>())
499 }
500
501 pub fn slice_ref_with_alignment(&self, subset: &[T], alignment: Alignment) -> Self {
511 if !alignment.is_aligned_to(Alignment::of::<T>()) {
512 vortex_panic!("slice_ref alignment must at least align to type T")
513 }
514
515 if !self.alignment.is_aligned_to(alignment) {
516 vortex_panic!("slice_ref subset alignment must at least align to the buffer alignment")
517 }
518
519 if !alignment.is_ptr_aligned(subset.as_ptr()) {
520 vortex_panic!("slice_ref subset must be aligned to {:?}", alignment);
521 }
522
523 let start = self.as_ptr().addr();
524 let end = start + size_of_val(self.as_slice());
525 let subset_start = subset.as_ptr().addr();
526 let subset_end = subset_start
527 .checked_add(size_of_val(subset))
528 .vortex_expect("slice_ref address overflow");
529 if subset_start < start || subset_end > end {
530 vortex_panic!("slice_ref subset must be contained in the buffer");
531 }
532
533 Self {
534 ptr: NonNull::new(subset.as_ptr().cast_mut()).vortex_expect("slice pointer is null"),
535 length: subset.len(),
536 alignment,
537 backing: self.backing.clone(),
538 }
539 }
540
541 pub fn into_bytes(self) -> Bytes {
543 if let Some(backing) = self.backing.as_ref()
544 && let BufferBacking::Bytes(bytes) = backing.as_ref()
545 {
546 let offset = self.ptr.cast::<u8>().addr().get() - bytes.as_ptr().addr();
547 let length = self.length * size_of::<T>();
548 if offset == 0 && length == bytes.len() && Arc::strong_count(backing) == 1 {
549 return match self.backing {
550 Some(backing) => match Arc::try_unwrap(backing) {
551 Ok(BufferBacking::Bytes(bytes)) => bytes,
552 _ => unreachable!(),
553 },
554 None => unreachable!(),
555 };
556 }
557 return bytes.slice(offset..offset + length);
558 }
559 match self.backing {
560 Some(backing) => Bytes::from_owner(BufferBytesOwner {
561 ptr: self.ptr.cast(),
562 length: self.length * size_of::<T>(),
563 backing,
564 }),
565 None => Bytes::new(),
566 }
567 }
568
569 pub fn into_byte_buffer(self) -> ByteBuffer {
571 ByteBuffer {
572 ptr: self.ptr.cast(),
573 length: self.length * size_of::<T>(),
574 alignment: self.alignment,
575 backing: self.backing,
576 }
577 }
578
579 pub fn try_into_mut(self) -> Result<BufferMut<T>, Self> {
581 let Self {
582 ptr,
583 length,
584 alignment,
585 backing,
586 } = self;
587 let Some(backing) = backing else {
588 return Ok(BufferMut::empty_aligned(alignment));
589 };
590 if !matches!(backing.as_ref(), BufferBacking::Owned(_)) {
591 return Err(Self {
592 ptr,
593 length,
594 alignment,
595 backing: Some(backing),
596 });
597 }
598 match Arc::try_unwrap(backing) {
599 Ok(BufferBacking::Owned(allocation)) => {
600 let offset = ptr.addr().get() - allocation.ptr().addr().get();
601 let capacity = if allocation.size() == 0 {
602 0
603 } else {
604 (allocation.size() - offset) / size_of::<T>()
605 };
606 Ok(BufferMut {
607 allocation,
608 ptr,
609 length,
610 capacity,
611 alignment,
612 _marker: Default::default(),
613 })
614 }
615 Ok(_) => unreachable!(),
616 Err(backing) => Err(Self {
617 ptr,
618 length,
619 alignment,
620 backing: Some(backing),
621 }),
622 }
623 }
624
625 pub fn into_mut(self) -> BufferMut<T>
627 where
628 T: Copy,
629 {
630 self.try_into_mut().unwrap_or_else(|buffer| {
631 let allocator = buffer.allocator().clone();
632 BufferMut::<T>::copy_from_aligned_in(&buffer, buffer.alignment, allocator)
633 })
634 }
635
636 pub fn is_aligned(&self, alignment: Alignment) -> bool {
638 alignment.is_ptr_aligned(self.as_ptr())
639 }
640
641 pub fn aligned(mut self, alignment: Alignment) -> Self
643 where
644 T: Copy,
645 {
646 if alignment.is_ptr_aligned(self.as_ptr()) {
647 self.alignment = alignment;
648 self
649 } else {
650 #[cfg(feature = "warn-copy")]
651 {
652 let bt = std::backtrace::Backtrace::capture();
653 tracing::warn!(
654 "Buffer is not aligned to requested alignment {alignment}, copying: {bt}"
655 )
656 }
657 let allocator = self.allocator().clone();
658 BufferMut::copy_from_aligned_in(self, alignment, allocator).freeze()
659 }
660 }
661
662 pub fn ensure_aligned(mut self, alignment: Alignment) -> Self {
664 if alignment.is_ptr_aligned(self.as_ptr()) {
665 self.alignment = alignment;
666 self
667 } else {
668 vortex_panic!("Buffer is not aligned to requested alignment {}", alignment)
669 }
670 }
671}
672
673impl<T> Buffer<T> {
674 pub unsafe fn transmute<U>(self) -> Buffer<U> {
686 assert_eq!(size_of::<T>(), size_of::<U>(), "Buffer type size mismatch");
687 assert_eq!(
688 align_of::<T>(),
689 align_of::<U>(),
690 "Buffer type alignment mismatch"
691 );
692
693 Buffer {
694 ptr: self.ptr.cast(),
695 length: self.length,
696 alignment: self.alignment,
697 backing: self.backing,
698 }
699 }
700}
701
702pub struct Iter<'a, T> {
706 inner: std::slice::Iter<'a, T>,
707}
708
709impl<'a, T> Iterator for Iter<'a, T> {
710 type Item = &'a T;
711
712 #[inline]
713 fn next(&mut self) -> Option<Self::Item> {
714 self.inner.next()
715 }
716
717 #[inline]
718 fn size_hint(&self) -> (usize, Option<usize>) {
719 self.inner.size_hint()
720 }
721
722 #[inline]
723 fn count(self) -> usize {
724 self.inner.count()
725 }
726
727 #[inline]
728 fn last(self) -> Option<Self::Item> {
729 self.inner.last()
730 }
731
732 #[inline]
733 fn nth(&mut self, n: usize) -> Option<Self::Item> {
734 self.inner.nth(n)
735 }
736}
737
738impl<T> ExactSizeIterator for Iter<'_, T> {
739 #[inline]
740 fn len(&self) -> usize {
741 self.inner.len()
742 }
743}
744
745impl<T: Debug> Debug for Buffer<T> {
746 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
747 f.debug_struct(&format!("Buffer<{}>", type_name::<T>()))
748 .field("length", &self.length)
749 .field("alignment", &self.alignment)
750 .field("as_slice", &TruncatedDebug(self.as_slice()))
751 .finish()
752 }
753}
754
755impl<T> Deref for Buffer<T> {
756 type Target = [T];
757
758 #[inline]
759 fn deref(&self) -> &Self::Target {
760 self.as_slice()
761 }
762}
763
764impl<T> AsRef<[T]> for Buffer<T> {
765 #[inline]
766 fn as_ref(&self) -> &[T] {
767 self.as_slice()
768 }
769}
770
771impl<T> FromIterator<T> for Buffer<T> {
772 #[inline]
773 fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self {
774 BufferMut::from_iter(iter).freeze()
775 }
776}
777
778impl<T> From<Vec<T>> for Buffer<T>
779where
780 T: Send + Sync + 'static,
781{
782 fn from(value: Vec<T>) -> Self {
783 const { assert!(size_of::<T>() != 0, "ZSTs are not supported") };
784 let length = value.len();
785 let alignment = Alignment::of::<T>();
786 if std::mem::needs_drop::<T>() {
787 Self {
789 ptr: NonNull::new(value.as_ptr().cast_mut())
790 .vortex_expect("a Vec always has a non-null pointer"),
791 length,
792 alignment,
793 backing: Some(Arc::new(BufferBacking::External {
794 _owner: Box::new(value),
795 })),
796 }
797 } else {
798 Self::from_allocation(Allocation::from_vec(value), 0, length, alignment)
799 }
800 }
801}
802
803impl From<Bytes> for ByteBuffer {
804 fn from(bytes: Bytes) -> Self {
805 Self::from_bytes(bytes, Alignment::of::<u8>())
806 }
807}
808
809impl Buf for ByteBuffer {
810 #[inline]
811 fn remaining(&self) -> usize {
812 self.len()
813 }
814
815 #[inline]
816 fn chunk(&self) -> &[u8] {
817 self.as_slice()
818 }
819
820 #[inline]
821 fn advance(&mut self, cnt: usize) {
822 if !self.alignment.is_offset_aligned(cnt) {
823 vortex_panic!(
824 "Cannot advance buffer by {} items, resulting alignment is not {}",
825 cnt,
826 self.alignment
827 );
828 }
829 assert!(cnt <= self.length, "cannot advance past the buffer length");
830 self.ptr = unsafe { self.ptr.add(cnt) };
832 self.length -= cnt;
833 }
834}
835
836struct BufferBytesOwner {
837 ptr: NonNull<u8>,
838 length: usize,
839 backing: Arc<BufferBacking>,
840}
841
842unsafe impl Send for BufferBytesOwner {}
844unsafe impl Sync for BufferBytesOwner {}
845
846impl AsRef<[u8]> for BufferBytesOwner {
847 fn as_ref(&self) -> &[u8] {
848 let _ = &self.backing;
849 unsafe { std::slice::from_raw_parts(self.ptr.as_ptr(), self.length) }
851 }
852}
853
854fn empty_ptr<T>() -> NonNull<T> {
855 let addr = 1usize << (usize::BITS - 1);
856 NonNull::new(std::ptr::without_provenance_mut(addr)).vortex_expect("empty pointer is non-null")
857}
858
859pub struct BufferIterator<T: Copy> {
861 _buffer: Buffer<T>,
863 ptr: *const T,
864 end: *const T,
865}
866
867unsafe impl<T: Copy + Send> Send for BufferIterator<T> {}
870unsafe impl<T: Copy + Sync> Sync for BufferIterator<T> {}
871
872impl<T: Copy> Iterator for BufferIterator<T> {
873 type Item = T;
874
875 #[inline]
876 fn next(&mut self) -> Option<Self::Item> {
877 if self.ptr == self.end {
878 None
879 } else {
880 let value = unsafe { self.ptr.read() };
882 self.ptr = unsafe { self.ptr.add(1) };
883 Some(value)
884 }
885 }
886
887 #[inline]
888 fn size_hint(&self) -> (usize, Option<usize>) {
889 let remaining = unsafe { self.end.offset_from(self.ptr) } as usize;
890 (remaining, Some(remaining))
891 }
892}
893
894impl<T: Copy> ExactSizeIterator for BufferIterator<T> {}
895
896impl<T: Copy> IntoIterator for Buffer<T> {
897 type Item = T;
898 type IntoIter = BufferIterator<T>;
899
900 #[inline]
901 fn into_iter(self) -> Self::IntoIter {
902 let ptr = self.as_slice().as_ptr();
903 let end = unsafe { ptr.add(self.len()) };
904 BufferIterator {
905 _buffer: self,
906 ptr,
907 end,
908 }
909 }
910}
911
912impl<T> From<BufferMut<T>> for Buffer<T> {
913 #[inline]
914 fn from(value: BufferMut<T>) -> Self {
915 value.freeze()
916 }
917}
918
919#[cold]
924#[inline(never)]
925fn misaligned_scalar_type(alignment: Alignment, scalar_align: Alignment) -> ! {
926 vortex_panic!("Alignment {alignment} must align to the scalar type's alignment {scalar_align}")
927}
928
929#[cold]
930#[inline(never)]
931fn incompatible_scalar_alignment(alignment: Alignment, scalar_align: Alignment) -> ! {
932 vortex_panic!(
933 "Alignment {alignment} must be compatible with the scalar type's alignment {scalar_align}"
934 )
935}
936
937#[cold]
938#[inline(never)]
939fn buffer_not_aligned(alignment: Alignment) -> ! {
940 vortex_panic!("Buffer must align to the requested alignment {alignment}")
941}
942
943#[cold]
944#[inline(never)]
945fn bytes_not_aligned(alignment: Alignment) -> ! {
946 vortex_panic!("Bytes alignment must align to the requested alignment {alignment}")
947}
948
949#[cold]
950#[inline(never)]
951fn buffer_len_not_multiple(len: usize, scalar_size: usize) -> ! {
952 vortex_panic!("Buffer length {len} must be a multiple of the scalar type's size {scalar_size}")
953}
954
955#[cold]
956#[inline(never)]
957fn bytes_len_not_multiple(len: usize, scalar_size: usize) -> ! {
958 vortex_panic!("Bytes length {len} must be a multiple of the scalar type's size {scalar_size}")
959}
960
961#[cold]
962#[inline(never)]
963fn slice_range_inverted(begin: usize, end: usize) -> ! {
964 vortex_panic!("range start must not be greater than end: {begin:?} <= {end:?}")
965}
966
967#[cold]
968#[inline(never)]
969fn slice_range_out_of_bounds(end: usize, len: usize) -> ! {
970 vortex_panic!("range end out of bounds: {end:?} > {len:?}")
971}
972
973#[cold]
974#[inline(never)]
975fn slice_start_misaligned(alignment: Alignment, begin_byte: usize) -> ! {
976 vortex_panic!("range start must be aligned to {alignment:?}, byte {begin_byte}")
977}
978
979#[cfg(test)]
980mod test {
981 use std::mem::align_of;
982 use std::sync::Arc;
983 use std::sync::atomic::AtomicUsize;
984 use std::sync::atomic::Ordering;
985
986 use bytes::Buf;
987 use bytes::Bytes;
988
989 use crate::Alignment;
990 use crate::Buffer;
991 use crate::BufferBacking;
992 use crate::ByteBuffer;
993 use crate::buffer;
994
995 #[test]
996 fn align() {
997 let buf = buffer![0u8, 1, 2];
998 let aligned = buf.aligned(Alignment::new(32));
999 assert_eq!(aligned.alignment(), Alignment::new(32));
1000 assert_eq!(aligned.as_slice(), &[0, 1, 2]);
1001 }
1002
1003 #[test]
1004 fn buffer_iterator_send_sync() {
1005 fn assert_send_sync<T: Send + Sync>(_: &T) {}
1006
1007 let mut iter = buffer![0i32, 1, 2, 3].into_iter();
1008 assert_send_sync(&iter);
1009 iter.next();
1010 let remaining: Vec<i32> = std::thread::spawn(move || iter.collect()).join().unwrap();
1011 assert_eq!(remaining, vec![1, 2, 3]);
1012 }
1013
1014 #[test]
1015 fn slice() {
1016 let buf = buffer![0, 1, 2, 3, 4];
1017 assert_eq!(buf.slice(1..3).as_slice(), &[1, 2]);
1018 assert_eq!(buf.slice(1..=3).as_slice(), &[1, 2, 3]);
1019 }
1020
1021 #[test]
1022 fn slice_unaligned() {
1023 let buf = buffer![0i32, 1, 2, 3, 4].into_byte_buffer();
1024 let sliced = buf.slice_unaligned(1..2);
1026 assert_eq!(sliced.len(), 1);
1028 assert_eq!(sliced.as_slice(), &[0]);
1031 }
1032
1033 #[test]
1034 #[should_panic]
1035 fn slice_bad_alignment() {
1036 let buf = buffer![0i32, 1, 2, 3, 4].into_byte_buffer();
1037 buf.slice(1..2);
1039 }
1040
1041 #[test]
1042 fn bytes_buf() {
1043 let mut buf = ByteBuffer::copy_from("helloworld".as_bytes());
1044 assert_eq!(buf.remaining(), 10);
1045 assert_eq!(buf.chunk(), b"helloworld");
1046
1047 buf.advance(5);
1048 assert_eq!(buf.remaining(), 5);
1049 assert_eq!(buf.as_slice(), b"world");
1050 assert_eq!(buf.chunk(), b"world");
1051 }
1052
1053 #[test]
1054 fn buffer_zeroed() {
1055 const LEN: usize = 17;
1056
1057 let buf = Buffer::<u32>::zeroed(LEN);
1058
1059 assert!(buf.is_aligned(Alignment::of::<u32>()));
1060 assert_eq!(buf.as_slice(), &[0; LEN]);
1061 }
1062
1063 #[test]
1064 fn buffer_zeroed_aligned() {
1065 const LEN: usize = 17;
1066 let alignment = Alignment::new(64);
1067
1068 let buf = Buffer::<u32>::zeroed_aligned(LEN, alignment);
1069
1070 assert!(buf.is_aligned(alignment));
1071 assert_eq!(buf.as_slice(), &[0; LEN]);
1072 }
1073
1074 #[test]
1075 fn copy_from_over_aligns_to_default() {
1076 let values = [1u32, 2, 3];
1077 let buf = Buffer::<u32>::copy_from(values);
1078
1079 assert_eq!(buf.alignment(), Alignment::of::<u32>());
1081 assert!(buf.is_aligned(Alignment::DEFAULT_ALIGNMENT));
1083 assert_eq!(buf.as_slice(), &values);
1084 }
1085
1086 #[test]
1087 fn zeroed_over_aligns_to_default() {
1088 const LEN: usize = 17;
1089
1090 let buf = Buffer::<u32>::zeroed(LEN);
1091
1092 assert_eq!(buf.alignment(), Alignment::of::<u32>());
1093 assert!(buf.is_aligned(Alignment::DEFAULT_ALIGNMENT));
1094 assert_eq!(buf.as_slice(), &[0; LEN]);
1095 }
1096
1097 #[test]
1098 fn from_vec() {
1099 let vec = vec![1, 2, 3, 4, 5];
1100 let buff = Buffer::from(vec.clone());
1101 assert!(buff.is_aligned(Alignment::of::<i32>()));
1102 assert_eq!(vec, buff.as_ref());
1103 }
1104
1105 #[test]
1106 fn from_vec_adopts_allocation() {
1107 let mut vec = Vec::with_capacity(16);
1108 vec.extend([1u32, 2, 3, 4, 5]);
1109 let ptr = vec.as_ptr();
1110 let capacity = vec.capacity();
1111
1112 let buffer = Buffer::from(vec);
1113 assert_eq!(buffer.as_ptr(), ptr);
1114
1115 let Ok(mut buffer) = buffer.try_into_mut() else {
1116 panic!("Vec-backed buffer should be uniquely owned")
1117 };
1118 assert_eq!(buffer.capacity(), capacity);
1119 assert_eq!(buffer.allocation.alignment(), align_of::<u32>());
1120
1121 buffer.extend(6..=32);
1122 assert_eq!(buffer.as_slice(), (1..=32).collect::<Vec<_>>());
1123 assert_eq!(buffer.allocation.alignment(), align_of::<u32>());
1124 }
1125
1126 #[test]
1127 fn byte_owner_preserves_slice_and_lifetime() {
1128 struct Owner {
1129 values: Vec<u8>,
1130 drops: Arc<AtomicUsize>,
1131 }
1132
1133 impl AsRef<[u8]> for Owner {
1134 fn as_ref(&self) -> &[u8] {
1135 &self.values[1..4]
1136 }
1137 }
1138
1139 impl Drop for Owner {
1140 fn drop(&mut self) {
1141 self.drops.fetch_add(1, Ordering::Relaxed);
1142 }
1143 }
1144
1145 let drops = Arc::new(AtomicUsize::new(0));
1146 let owner = Owner {
1147 values: vec![0, 1, 2, 3, 4],
1148 drops: Arc::clone(&drops),
1149 };
1150 let ptr = owner.as_ref().as_ptr();
1151 let buffer = ByteBuffer::from(Bytes::from_owner(owner));
1152 assert_eq!(buffer.as_ptr(), ptr);
1153 assert_eq!(buffer.as_slice(), [1, 2, 3]);
1154 let view = buffer.slice(1..);
1155 drop(buffer);
1156 assert_eq!(drops.load(Ordering::Relaxed), 0);
1157 assert_eq!(view.as_slice(), [2, 3]);
1158 drop(view);
1159 assert_eq!(drops.load(Ordering::Relaxed), 1);
1160 }
1161
1162 #[test]
1163 fn bytes_round_trip_reuses_owner() {
1164 let bytes = Bytes::from_static(&[1, 2, 3, 4]);
1165 let ptr = bytes.as_ptr();
1166
1167 let buffer = ByteBuffer::from(bytes);
1168 assert!(matches!(
1169 buffer.backing.as_deref(),
1170 Some(BufferBacking::Bytes(_))
1171 ));
1172 let bytes = buffer.into_bytes();
1173
1174 assert_eq!(bytes.as_ptr(), ptr);
1175 assert_eq!(bytes.as_ref(), &[1, 2, 3, 4]);
1176 }
1177
1178 #[test]
1179 fn external_try_into_mut_preserves_backing() {
1180 let buffer = ByteBuffer::from(Bytes::from_static(&[1, 2, 3, 4]));
1181 let Some(original_backing) = buffer.backing.as_ref() else {
1182 panic!("external buffer has no backing")
1183 };
1184 let backing = Arc::as_ptr(original_backing);
1185
1186 let Err(buffer) = buffer.try_into_mut() else {
1187 panic!("external buffer became mutable")
1188 };
1189
1190 let Some(new_backing) = buffer.backing.as_ref() else {
1191 panic!("external buffer has no backing")
1192 };
1193 assert_eq!(Arc::as_ptr(new_backing), backing);
1194 }
1195
1196 #[test]
1197 fn from_u8_vec_preserves_capacity() {
1198 let mut vec = Vec::with_capacity(16);
1199 vec.extend([1u8, 2, 3]);
1200
1201 let buffer = Buffer::from(vec);
1202 let Ok(buffer) = buffer.try_into_mut() else {
1203 panic!("Vec-backed buffer should be uniquely owned")
1204 };
1205 assert_eq!(buffer.capacity(), 16);
1206 }
1207
1208 #[test]
1209 fn sliced_buffer_into_mut_has_safe_capacity() {
1210 let mut original = crate::BufferMut::with_capacity(128);
1211 original.extend(0u32..100);
1212 let original = original.freeze();
1213 let sliced = original.slice(64..96);
1214 drop(original);
1215
1216 let Ok(mut sliced) = sliced.try_into_mut() else {
1217 panic!("uniquely owned slice should become mutable")
1218 };
1219 let ptr = sliced.as_ptr();
1220 let capacity = sliced.capacity();
1221 sliced.push_n(0, capacity - sliced.len());
1222 assert_eq!(sliced.len(), capacity);
1223 assert_eq!(sliced.as_ptr(), ptr);
1224 sliced.push(42);
1225 assert_eq!(&sliced[..32], (64u32..96).collect::<Vec<_>>());
1226 assert_eq!(&sliced[32..capacity], vec![0; capacity - 32]);
1227 assert_eq!(sliced[capacity], 42);
1228 }
1229
1230 #[test]
1231 fn from_vec_preserves_drop_glue() {
1232 struct DropValue(Arc<AtomicUsize>);
1233
1234 impl Drop for DropValue {
1235 fn drop(&mut self) {
1236 self.0.fetch_add(1, Ordering::Relaxed);
1237 }
1238 }
1239
1240 let drops = Arc::new(AtomicUsize::new(0));
1241 let values = (0..3)
1242 .map(|_| DropValue(Arc::clone(&drops)))
1243 .collect::<Vec<_>>();
1244 let buffer = Buffer::from(values);
1245
1246 assert_eq!(drops.load(Ordering::Relaxed), 0);
1247 drop(buffer);
1248 assert_eq!(drops.load(Ordering::Relaxed), 3);
1249 }
1250
1251 #[test]
1252 fn empty_aligned_max_alignment() {
1253 let buf = Buffer::<u8>::empty_aligned(Alignment::MAX);
1255 assert!(buf.is_empty());
1256 assert!(buf.is_aligned(Alignment::MAX));
1257 }
1258
1259 #[test]
1260 fn empty_has_no_backing() {
1261 assert!(Buffer::<u8>::empty().backing.is_none());
1262 }
1263
1264 #[test]
1265 fn empty_slice_preserves_alignment() {
1266 let buf = Buffer::<u64>::zeroed_aligned(8, Alignment::new(64));
1267 let sliced = buf.slice(0..0);
1268 assert!(sliced.is_empty());
1269 assert_eq!(sliced.alignment(), Alignment::new(64));
1270 assert!(sliced.is_aligned(Alignment::new(64)));
1271 }
1272
1273 #[test]
1274 fn empty_into_mut_preserves_alignment() {
1275 let buf = Buffer::<u8>::empty_aligned(Alignment::new(64));
1276 let buf_mut = buf.into_mut();
1277 assert_eq!(buf_mut.alignment(), Alignment::new(64));
1278 assert!(buf_mut.is_empty());
1279 }
1280
1281 #[test]
1282 fn test_slice_unaligned_end_pos() {
1283 let data = vec![0u8; 2];
1284 let aligned_buffer = Buffer::copy_from_aligned(&data, Alignment::new(8));
1286 aligned_buffer.slice(0..1);
1291 }
1292
1293 #[test]
1294 fn test_empty_equality() {
1295 let a = Buffer::<u16>::empty();
1296 let b = Buffer::<u16>::empty();
1297
1298 assert_eq!(a, b);
1299 }
1300}