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 BufferMut::copy_from(values).freeze()
172 }
173
174 pub fn copy_from_in(values: impl AsRef<[T]>, allocator: BufferAllocatorRef) -> Self {
176 BufferMut::copy_from_in(values, allocator).freeze()
177 }
178
179 pub fn copy_from_aligned(values: impl AsRef<[T]>, alignment: Alignment) -> Self {
186 Self::copy_from_preferred_aligned(values, alignment, Some(Alignment::DEFAULT_ALIGNMENT))
187 }
188
189 pub fn copy_from_preferred_aligned(
194 values: impl AsRef<[T]>,
195 alignment: Alignment,
196 preferred_alignment: Option<Alignment>,
197 ) -> Self {
198 BufferMut::copy_from_preferred_aligned(values, alignment, preferred_alignment).freeze()
199 }
200
201 pub fn zeroed(len: usize) -> Self {
203 Self::zeroed_aligned(len, Alignment::of::<T>())
204 }
205
206 pub fn zeroed_in(len: usize, allocator: BufferAllocatorRef) -> Self {
208 BufferMut::zeroed_in(len, allocator).freeze()
209 }
210
211 pub fn zeroed_aligned(len: usize, alignment: Alignment) -> Self {
218 Self::zeroed_preferred_aligned(len, alignment, Some(Alignment::DEFAULT_ALIGNMENT))
219 }
220
221 pub fn zeroed_preferred_aligned(
226 len: usize,
227 alignment: Alignment,
228 preferred_alignment: Option<Alignment>,
229 ) -> Self {
230 BufferMut::zeroed_preferred_aligned(len, alignment, preferred_alignment).freeze()
231 }
232
233 pub fn empty() -> Self {
235 Self::empty_aligned(Alignment::of::<T>())
236 }
237
238 pub fn empty_aligned(alignment: Alignment) -> Self {
242 const { assert!(size_of::<T>() != 0, "ZSTs are not supported") };
243 if !alignment.is_aligned_to(Alignment::of::<T>()) {
244 vortex_panic!(
245 "Alignment {} must align to the scalar type's alignment {}",
246 alignment,
247 Alignment::of::<T>(),
248 );
249 }
250 Self {
251 ptr: empty_ptr(),
252 length: 0,
253 alignment,
254 backing: None,
255 }
256 }
257
258 pub fn full(item: T, len: usize) -> Self
260 where
261 T: Copy,
262 {
263 BufferMut::full(item, len).freeze()
264 }
265
266 pub fn full_in(item: T, len: usize, allocator: BufferAllocatorRef) -> Self
268 where
269 T: Copy,
270 {
271 BufferMut::full_in(item, len, allocator).freeze()
272 }
273
274 pub fn from_byte_buffer(buffer: ByteBuffer) -> Self {
281 Self::from_byte_buffer_aligned(buffer, Alignment::of::<T>())
283 }
284
285 pub fn from_byte_buffer_aligned(buffer: ByteBuffer, alignment: Alignment) -> Self {
292 const { assert!(size_of::<T>() != 0, "ZSTs are not supported") };
293 if !alignment.is_aligned_to(Alignment::of::<T>()) {
294 vortex_panic!(
295 "Alignment {} must be compatible with the scalar type's alignment {}",
296 alignment,
297 Alignment::of::<T>(),
298 );
299 }
300 if !alignment.is_ptr_aligned(buffer.as_ptr()) {
301 vortex_panic!("Buffer must align to the requested alignment {}", alignment);
302 }
303 if !buffer.len().is_multiple_of(size_of::<T>()) {
304 vortex_panic!(
305 "Buffer length {} must be a multiple of the scalar type's size {}",
306 buffer.len(),
307 size_of::<T>()
308 );
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 vortex_panic!(
328 "Alignment {} must be compatible with the scalar type's alignment {}",
329 alignment,
330 Alignment::of::<T>(),
331 );
332 }
333 if !alignment.is_ptr_aligned(bytes.as_ptr()) {
334 vortex_panic!(
335 "Bytes alignment must align to the requested alignment {}",
336 alignment,
337 );
338 }
339 if !bytes.len().is_multiple_of(size_of::<T>()) {
340 vortex_panic!(
341 "Bytes length {} must be a multiple of the scalar type's size {}",
342 bytes.len(),
343 size_of::<T>()
344 );
345 }
346 Self::from_bytes(bytes, alignment)
347 }
348
349 pub fn from_trusted_len_iter<I: TrustedLen<Item = T>>(iter: I) -> Self {
352 BufferMut::from_trusted_len_iter(iter).freeze()
353 }
354
355 pub fn map_each_in_place<R, F>(self, mut f: F) -> BufferMut<R>
357 where
358 T: Copy,
359 F: FnMut(T) -> R,
360 {
361 match self.try_into_mut() {
362 Ok(mut_buf) => mut_buf.map_each_in_place(f),
363 Err(buf) => {
364 let len = buf.len();
365 let allocator = buf.allocator().clone();
366 let mut out_buf = BufferMut::with_capacity_in(len, allocator);
367 out_buf
368 .spare_capacity_mut()
369 .iter_mut()
370 .zip(buf)
371 .for_each(|(out, in_)| {
372 out.write(f(in_));
373 });
374 unsafe { out_buf.set_len(len) }
376 out_buf
377 }
378 }
379 }
380
381 pub fn clear(&mut self) {
383 self.length = 0;
384 }
385
386 #[allow(clippy::inline_always)]
388 #[inline(always)]
389 pub fn len(&self) -> usize {
390 self.length
391 }
392
393 #[allow(clippy::inline_always)]
395 #[inline(always)]
396 pub fn is_empty(&self) -> bool {
397 self.length == 0
398 }
399
400 #[allow(clippy::inline_always)]
402 #[inline(always)]
403 pub fn alignment(&self) -> Alignment {
404 self.alignment
405 }
406
407 pub fn allocator(&self) -> &BufferAllocatorRef {
411 match self.backing.as_deref() {
412 Some(backing) => backing.allocator(),
413 None => BufferAllocatorRef::static_ref(),
414 }
415 }
416
417 #[allow(clippy::inline_always)]
419 #[inline(always)]
420 pub fn as_ptr(&self) -> *const T {
421 self.ptr.as_ptr()
422 }
423
424 #[allow(clippy::inline_always)]
426 #[inline(always)]
427 pub fn as_slice(&self) -> &[T] {
428 unsafe { std::slice::from_raw_parts(self.ptr.as_ptr(), self.length) }
430 }
431
432 #[allow(clippy::inline_always)]
434 #[inline(always)]
435 pub fn as_bytes(&self) -> &[u8] {
436 unsafe {
438 std::slice::from_raw_parts(self.ptr.as_ptr().cast(), size_of_val(self.as_slice()))
439 }
440 }
441
442 pub fn iter(&self) -> Iter<'_, T> {
444 Iter {
445 inner: self.as_slice().iter(),
446 }
447 }
448
449 #[allow(clippy::inline_always)]
456 #[inline(always)]
457 pub fn slice(&self, range: impl RangeBounds<usize>) -> Self {
458 self.slice_with_alignment(range, self.alignment)
459 }
460
461 #[allow(clippy::inline_always)]
468 #[inline(always)]
469 pub fn slice_unaligned(&self, range: impl RangeBounds<usize>) -> Self {
470 self.slice_with_alignment(range, Alignment::of::<u8>())
471 }
472
473 pub fn slice_with_alignment(
481 &self,
482 range: impl RangeBounds<usize>,
483 alignment: Alignment,
484 ) -> Self {
485 let len = self.len();
486 let begin = match range.start_bound() {
487 Bound::Included(&n) => n,
488 Bound::Excluded(&n) => n.checked_add(1).vortex_expect("out of range"),
489 Bound::Unbounded => 0,
490 };
491 let end = match range.end_bound() {
492 Bound::Included(&n) => n.checked_add(1).vortex_expect("out of range"),
493 Bound::Excluded(&n) => n,
494 Bound::Unbounded => len,
495 };
496
497 if begin > end {
498 vortex_panic!(
499 "range start must not be greater than end: {:?} <= {:?}",
500 begin,
501 end
502 );
503 }
504 if end > len {
505 vortex_panic!("range end out of bounds: {:?} > {:?}", end, len);
506 }
507
508 if end == begin {
509 return Self::empty_aligned(alignment);
512 }
513
514 let begin_byte = begin * size_of::<T>();
515 if !alignment.is_offset_aligned(begin_byte) {
516 vortex_panic!(
517 "range start must be aligned to {alignment:?}, byte {}",
518 begin_byte
519 );
520 }
521 if !alignment.is_aligned_to(Alignment::of::<T>()) {
522 vortex_panic!("Slice alignment must at least align to type T")
523 }
524
525 Self {
526 ptr: unsafe { self.ptr.add(begin) },
528 length: end - begin,
529 alignment,
530 backing: self.backing.clone(),
531 }
532 }
533
534 #[allow(clippy::inline_always)]
543 #[inline(always)]
544 pub fn slice_ref(&self, subset: &[T]) -> Self {
545 self.slice_ref_with_alignment(subset, Alignment::of::<T>())
546 }
547
548 pub fn slice_ref_with_alignment(&self, subset: &[T], alignment: Alignment) -> Self {
558 if !alignment.is_aligned_to(Alignment::of::<T>()) {
559 vortex_panic!("slice_ref alignment must at least align to type T")
560 }
561
562 if !self.alignment.is_aligned_to(alignment) {
563 vortex_panic!("slice_ref subset alignment must at least align to the buffer alignment")
564 }
565
566 if !alignment.is_ptr_aligned(subset.as_ptr()) {
567 vortex_panic!("slice_ref subset must be aligned to {:?}", alignment);
568 }
569
570 let start = self.as_ptr().addr();
571 let end = start + size_of_val(self.as_slice());
572 let subset_start = subset.as_ptr().addr();
573 let subset_end = subset_start
574 .checked_add(size_of_val(subset))
575 .vortex_expect("slice_ref address overflow");
576 if subset_start < start || subset_end > end {
577 vortex_panic!("slice_ref subset must be contained in the buffer");
578 }
579
580 Self {
581 ptr: NonNull::new(subset.as_ptr().cast_mut()).vortex_expect("slice pointer is null"),
582 length: subset.len(),
583 alignment,
584 backing: self.backing.clone(),
585 }
586 }
587
588 pub fn into_bytes(self) -> Bytes {
590 if let Some(backing) = self.backing.as_ref()
591 && let BufferBacking::Bytes(bytes) = backing.as_ref()
592 {
593 let offset = self.ptr.cast::<u8>().addr().get() - bytes.as_ptr().addr();
594 let length = self.length * size_of::<T>();
595 if offset == 0 && length == bytes.len() && Arc::strong_count(backing) == 1 {
596 return match self.backing {
597 Some(backing) => match Arc::try_unwrap(backing) {
598 Ok(BufferBacking::Bytes(bytes)) => bytes,
599 _ => unreachable!(),
600 },
601 None => unreachable!(),
602 };
603 }
604 return bytes.slice(offset..offset + length);
605 }
606 match self.backing {
607 Some(backing) => Bytes::from_owner(BufferBytesOwner {
608 ptr: self.ptr.cast(),
609 length: self.length * size_of::<T>(),
610 backing,
611 }),
612 None => Bytes::new(),
613 }
614 }
615
616 pub fn into_byte_buffer(self) -> ByteBuffer {
618 ByteBuffer {
619 ptr: self.ptr.cast(),
620 length: self.length * size_of::<T>(),
621 alignment: self.alignment,
622 backing: self.backing,
623 }
624 }
625
626 pub fn try_into_mut(self) -> Result<BufferMut<T>, Self> {
628 let Self {
629 ptr,
630 length,
631 alignment,
632 backing,
633 } = self;
634 let Some(backing) = backing else {
635 return Ok(BufferMut::empty_aligned(alignment));
636 };
637 if !matches!(backing.as_ref(), BufferBacking::Owned(_)) {
638 return Err(Self {
639 ptr,
640 length,
641 alignment,
642 backing: Some(backing),
643 });
644 }
645 match Arc::try_unwrap(backing) {
646 Ok(BufferBacking::Owned(allocation)) => {
647 let offset = ptr.addr().get() - allocation.ptr().addr().get();
648 let capacity = if allocation.size() == 0 {
649 0
650 } else {
651 (allocation.size() - offset) / size_of::<T>()
652 };
653 Ok(BufferMut {
654 allocation,
655 ptr,
656 length,
657 capacity,
658 alignment,
659 _marker: Default::default(),
660 })
661 }
662 Ok(_) => unreachable!(),
663 Err(backing) => Err(Self {
664 ptr,
665 length,
666 alignment,
667 backing: Some(backing),
668 }),
669 }
670 }
671
672 pub fn into_mut(self) -> BufferMut<T> {
674 self.try_into_mut().unwrap_or_else(|buffer| {
675 let allocator = buffer.allocator().clone();
676 BufferMut::<T>::copy_from_aligned_in(&buffer, buffer.alignment, allocator)
677 })
678 }
679
680 pub fn is_aligned(&self, alignment: Alignment) -> bool {
682 alignment.is_ptr_aligned(self.as_ptr())
683 }
684
685 pub fn aligned(mut self, alignment: Alignment) -> Self {
687 if alignment.is_ptr_aligned(self.as_ptr()) {
688 self.alignment = alignment;
689 self
690 } else {
691 #[cfg(feature = "warn-copy")]
692 {
693 let bt = std::backtrace::Backtrace::capture();
694 tracing::warn!(
695 "Buffer is not aligned to requested alignment {alignment}, copying: {bt}"
696 )
697 }
698 let allocator = self.allocator().clone();
699 BufferMut::copy_from_aligned_in(self, alignment, allocator).freeze()
700 }
701 }
702
703 pub fn ensure_aligned(mut self, alignment: Alignment) -> Self {
705 if alignment.is_ptr_aligned(self.as_ptr()) {
706 self.alignment = alignment;
707 self
708 } else {
709 vortex_panic!("Buffer is not aligned to requested alignment {}", alignment)
710 }
711 }
712}
713
714impl<T> Buffer<T> {
715 pub unsafe fn transmute<U>(self) -> Buffer<U> {
727 assert_eq!(size_of::<T>(), size_of::<U>(), "Buffer type size mismatch");
728 assert_eq!(
729 align_of::<T>(),
730 align_of::<U>(),
731 "Buffer type alignment mismatch"
732 );
733
734 Buffer {
735 ptr: self.ptr.cast(),
736 length: self.length,
737 alignment: self.alignment,
738 backing: self.backing,
739 }
740 }
741}
742
743pub struct Iter<'a, T> {
747 inner: std::slice::Iter<'a, T>,
748}
749
750impl<'a, T> Iterator for Iter<'a, T> {
751 type Item = &'a T;
752
753 #[inline]
754 fn next(&mut self) -> Option<Self::Item> {
755 self.inner.next()
756 }
757
758 #[inline]
759 fn size_hint(&self) -> (usize, Option<usize>) {
760 self.inner.size_hint()
761 }
762
763 #[inline]
764 fn count(self) -> usize {
765 self.inner.count()
766 }
767
768 #[inline]
769 fn last(self) -> Option<Self::Item> {
770 self.inner.last()
771 }
772
773 #[inline]
774 fn nth(&mut self, n: usize) -> Option<Self::Item> {
775 self.inner.nth(n)
776 }
777}
778
779impl<T> ExactSizeIterator for Iter<'_, T> {
780 #[inline]
781 fn len(&self) -> usize {
782 self.inner.len()
783 }
784}
785
786impl<T: Debug> Debug for Buffer<T> {
787 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
788 f.debug_struct(&format!("Buffer<{}>", type_name::<T>()))
789 .field("length", &self.length)
790 .field("alignment", &self.alignment)
791 .field("as_slice", &TruncatedDebug(self.as_slice()))
792 .finish()
793 }
794}
795
796impl<T> Deref for Buffer<T> {
797 type Target = [T];
798
799 #[inline]
800 fn deref(&self) -> &Self::Target {
801 self.as_slice()
802 }
803}
804
805impl<T> AsRef<[T]> for Buffer<T> {
806 #[inline]
807 fn as_ref(&self) -> &[T] {
808 self.as_slice()
809 }
810}
811
812impl<T> FromIterator<T> for Buffer<T> {
813 #[inline]
814 fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self {
815 BufferMut::from_iter(iter).freeze()
816 }
817}
818
819impl<T> From<Vec<T>> for Buffer<T>
820where
821 T: Send + Sync + 'static,
822{
823 fn from(value: Vec<T>) -> Self {
824 const { assert!(size_of::<T>() != 0, "ZSTs are not supported") };
825 let length = value.len();
826 let alignment = Alignment::of::<T>();
827 if std::mem::needs_drop::<T>() {
828 Self {
830 ptr: NonNull::new(value.as_ptr().cast_mut())
831 .vortex_expect("a Vec always has a non-null pointer"),
832 length,
833 alignment,
834 backing: Some(Arc::new(BufferBacking::External {
835 _owner: Box::new(value),
836 })),
837 }
838 } else {
839 Self::from_allocation(Allocation::from_vec(value), 0, length, alignment)
840 }
841 }
842}
843
844impl From<Bytes> for ByteBuffer {
845 fn from(bytes: Bytes) -> Self {
846 Self::from_bytes(bytes, Alignment::of::<u8>())
847 }
848}
849
850impl Buf for ByteBuffer {
851 #[inline]
852 fn remaining(&self) -> usize {
853 self.len()
854 }
855
856 #[inline]
857 fn chunk(&self) -> &[u8] {
858 self.as_slice()
859 }
860
861 #[inline]
862 fn advance(&mut self, cnt: usize) {
863 if !self.alignment.is_offset_aligned(cnt) {
864 vortex_panic!(
865 "Cannot advance buffer by {} items, resulting alignment is not {}",
866 cnt,
867 self.alignment
868 );
869 }
870 assert!(cnt <= self.length, "cannot advance past the buffer length");
871 self.ptr = unsafe { self.ptr.add(cnt) };
873 self.length -= cnt;
874 }
875}
876
877struct BufferBytesOwner {
878 ptr: NonNull<u8>,
879 length: usize,
880 backing: Arc<BufferBacking>,
881}
882
883unsafe impl Send for BufferBytesOwner {}
885unsafe impl Sync for BufferBytesOwner {}
886
887impl AsRef<[u8]> for BufferBytesOwner {
888 fn as_ref(&self) -> &[u8] {
889 let _ = &self.backing;
890 unsafe { std::slice::from_raw_parts(self.ptr.as_ptr(), self.length) }
892 }
893}
894
895fn empty_ptr<T>() -> NonNull<T> {
896 let addr = 1usize << (usize::BITS - 1);
897 NonNull::new(std::ptr::without_provenance_mut(addr)).vortex_expect("empty pointer is non-null")
898}
899
900pub struct BufferIterator<T: Copy> {
902 _buffer: Buffer<T>,
904 ptr: *const T,
905 end: *const T,
906}
907
908unsafe impl<T: Copy + Send> Send for BufferIterator<T> {}
911unsafe impl<T: Copy + Sync> Sync for BufferIterator<T> {}
912
913impl<T: Copy> Iterator for BufferIterator<T> {
914 type Item = T;
915
916 #[inline]
917 fn next(&mut self) -> Option<Self::Item> {
918 if self.ptr == self.end {
919 None
920 } else {
921 let value = unsafe { self.ptr.read() };
923 self.ptr = unsafe { self.ptr.add(1) };
924 Some(value)
925 }
926 }
927
928 #[inline]
929 fn size_hint(&self) -> (usize, Option<usize>) {
930 let remaining = unsafe { self.end.offset_from(self.ptr) } as usize;
931 (remaining, Some(remaining))
932 }
933}
934
935impl<T: Copy> ExactSizeIterator for BufferIterator<T> {}
936
937impl<T: Copy> IntoIterator for Buffer<T> {
938 type Item = T;
939 type IntoIter = BufferIterator<T>;
940
941 #[inline]
942 fn into_iter(self) -> Self::IntoIter {
943 let ptr = self.as_slice().as_ptr();
944 let end = unsafe { ptr.add(self.len()) };
945 BufferIterator {
946 _buffer: self,
947 ptr,
948 end,
949 }
950 }
951}
952
953impl<T> From<BufferMut<T>> for Buffer<T> {
954 #[inline]
955 fn from(value: BufferMut<T>) -> Self {
956 value.freeze()
957 }
958}
959
960#[cfg(test)]
961mod test {
962 use std::mem::align_of;
963 use std::sync::Arc;
964 use std::sync::atomic::AtomicUsize;
965 use std::sync::atomic::Ordering;
966
967 use bytes::Buf;
968 use bytes::Bytes;
969
970 use crate::Alignment;
971 use crate::Buffer;
972 use crate::BufferBacking;
973 use crate::ByteBuffer;
974 use crate::buffer;
975
976 #[test]
977 fn align() {
978 let buf = buffer![0u8, 1, 2];
979 let aligned = buf.aligned(Alignment::new(32));
980 assert_eq!(aligned.alignment(), Alignment::new(32));
981 assert_eq!(aligned.as_slice(), &[0, 1, 2]);
982 }
983
984 #[test]
985 fn buffer_iterator_send_sync() {
986 fn assert_send_sync<T: Send + Sync>(_: &T) {}
987
988 let mut iter = buffer![0i32, 1, 2, 3].into_iter();
989 assert_send_sync(&iter);
990 iter.next();
991 let remaining: Vec<i32> = std::thread::spawn(move || iter.collect()).join().unwrap();
992 assert_eq!(remaining, vec![1, 2, 3]);
993 }
994
995 #[test]
996 fn slice() {
997 let buf = buffer![0, 1, 2, 3, 4];
998 assert_eq!(buf.slice(1..3).as_slice(), &[1, 2]);
999 assert_eq!(buf.slice(1..=3).as_slice(), &[1, 2, 3]);
1000 }
1001
1002 #[test]
1003 fn slice_unaligned() {
1004 let buf = buffer![0i32, 1, 2, 3, 4].into_byte_buffer();
1005 let sliced = buf.slice_unaligned(1..2);
1007 assert_eq!(sliced.len(), 1);
1009 assert_eq!(sliced.as_slice(), &[0]);
1012 }
1013
1014 #[test]
1015 #[should_panic]
1016 fn slice_bad_alignment() {
1017 let buf = buffer![0i32, 1, 2, 3, 4].into_byte_buffer();
1018 buf.slice(1..2);
1020 }
1021
1022 #[test]
1023 fn bytes_buf() {
1024 let mut buf = ByteBuffer::copy_from("helloworld".as_bytes());
1025 assert_eq!(buf.remaining(), 10);
1026 assert_eq!(buf.chunk(), b"helloworld");
1027
1028 buf.advance(5);
1029 assert_eq!(buf.remaining(), 5);
1030 assert_eq!(buf.as_slice(), b"world");
1031 assert_eq!(buf.chunk(), b"world");
1032 }
1033
1034 #[test]
1035 fn buffer_zeroed() {
1036 const LEN: usize = 17;
1037
1038 let buf = Buffer::<u32>::zeroed(LEN);
1039
1040 assert!(buf.is_aligned(Alignment::of::<u32>()));
1041 assert_eq!(buf.as_slice(), &[0; LEN]);
1042 }
1043
1044 #[test]
1045 fn buffer_zeroed_aligned() {
1046 const LEN: usize = 17;
1047 let alignment = Alignment::new(64);
1048
1049 let buf = Buffer::<u32>::zeroed_aligned(LEN, alignment);
1050
1051 assert!(buf.is_aligned(alignment));
1052 assert_eq!(buf.as_slice(), &[0; LEN]);
1053 }
1054
1055 #[test]
1056 fn copy_from_over_aligns_to_default() {
1057 let values = [1u32, 2, 3];
1058 let buf = Buffer::<u32>::copy_from(values);
1059
1060 assert_eq!(buf.alignment(), Alignment::of::<u32>());
1062 assert!(buf.is_aligned(Alignment::DEFAULT_ALIGNMENT));
1064 assert_eq!(buf.as_slice(), &values);
1065 }
1066
1067 #[test]
1068 fn zeroed_over_aligns_to_default() {
1069 const LEN: usize = 17;
1070
1071 let buf = Buffer::<u32>::zeroed(LEN);
1072
1073 assert_eq!(buf.alignment(), Alignment::of::<u32>());
1074 assert!(buf.is_aligned(Alignment::DEFAULT_ALIGNMENT));
1075 assert_eq!(buf.as_slice(), &[0; LEN]);
1076 }
1077
1078 #[test]
1079 fn from_vec() {
1080 let vec = vec![1, 2, 3, 4, 5];
1081 let buff = Buffer::from(vec.clone());
1082 assert!(buff.is_aligned(Alignment::of::<i32>()));
1083 assert_eq!(vec, buff.as_ref());
1084 }
1085
1086 #[test]
1087 fn from_vec_adopts_allocation() {
1088 let mut vec = Vec::with_capacity(16);
1089 vec.extend([1u32, 2, 3, 4, 5]);
1090 let ptr = vec.as_ptr();
1091 let capacity = vec.capacity();
1092
1093 let buffer = Buffer::from(vec);
1094 assert_eq!(buffer.as_ptr(), ptr);
1095
1096 let Ok(mut buffer) = buffer.try_into_mut() else {
1097 panic!("Vec-backed buffer should be uniquely owned")
1098 };
1099 assert_eq!(buffer.capacity(), capacity);
1100 assert_eq!(buffer.allocation.alignment(), align_of::<u32>());
1101
1102 buffer.extend(6..=32);
1103 assert_eq!(buffer.as_slice(), (1..=32).collect::<Vec<_>>());
1104 assert_eq!(buffer.allocation.alignment(), align_of::<u32>());
1105 }
1106
1107 #[test]
1108 fn byte_owner_preserves_slice_and_lifetime() {
1109 struct Owner {
1110 values: Vec<u8>,
1111 drops: Arc<AtomicUsize>,
1112 }
1113
1114 impl AsRef<[u8]> for Owner {
1115 fn as_ref(&self) -> &[u8] {
1116 &self.values[1..4]
1117 }
1118 }
1119
1120 impl Drop for Owner {
1121 fn drop(&mut self) {
1122 self.drops.fetch_add(1, Ordering::Relaxed);
1123 }
1124 }
1125
1126 let drops = Arc::new(AtomicUsize::new(0));
1127 let owner = Owner {
1128 values: vec![0, 1, 2, 3, 4],
1129 drops: Arc::clone(&drops),
1130 };
1131 let ptr = owner.as_ref().as_ptr();
1132 let buffer = ByteBuffer::from(Bytes::from_owner(owner));
1133 assert_eq!(buffer.as_ptr(), ptr);
1134 assert_eq!(buffer.as_slice(), [1, 2, 3]);
1135 let view = buffer.slice(1..);
1136 drop(buffer);
1137 assert_eq!(drops.load(Ordering::Relaxed), 0);
1138 assert_eq!(view.as_slice(), [2, 3]);
1139 drop(view);
1140 assert_eq!(drops.load(Ordering::Relaxed), 1);
1141 }
1142
1143 #[test]
1144 fn bytes_round_trip_reuses_owner() {
1145 let bytes = Bytes::from_static(&[1, 2, 3, 4]);
1146 let ptr = bytes.as_ptr();
1147
1148 let buffer = ByteBuffer::from(bytes);
1149 assert!(matches!(
1150 buffer.backing.as_deref(),
1151 Some(BufferBacking::Bytes(_))
1152 ));
1153 let bytes = buffer.into_bytes();
1154
1155 assert_eq!(bytes.as_ptr(), ptr);
1156 assert_eq!(bytes.as_ref(), &[1, 2, 3, 4]);
1157 }
1158
1159 #[test]
1160 fn external_try_into_mut_preserves_backing() {
1161 let buffer = ByteBuffer::from(Bytes::from_static(&[1, 2, 3, 4]));
1162 let Some(original_backing) = buffer.backing.as_ref() else {
1163 panic!("external buffer has no backing")
1164 };
1165 let backing = Arc::as_ptr(original_backing);
1166
1167 let Err(buffer) = buffer.try_into_mut() else {
1168 panic!("external buffer became mutable")
1169 };
1170
1171 let Some(new_backing) = buffer.backing.as_ref() else {
1172 panic!("external buffer has no backing")
1173 };
1174 assert_eq!(Arc::as_ptr(new_backing), backing);
1175 }
1176
1177 #[test]
1178 fn from_u8_vec_preserves_capacity() {
1179 let mut vec = Vec::with_capacity(16);
1180 vec.extend([1u8, 2, 3]);
1181
1182 let buffer = Buffer::from(vec);
1183 let Ok(buffer) = buffer.try_into_mut() else {
1184 panic!("Vec-backed buffer should be uniquely owned")
1185 };
1186 assert_eq!(buffer.capacity(), 16);
1187 }
1188
1189 #[test]
1190 fn sliced_buffer_into_mut_has_safe_capacity() {
1191 let mut original = crate::BufferMut::with_capacity(128);
1192 original.extend(0u32..100);
1193 let original = original.freeze();
1194 let sliced = original.slice(64..96);
1195 drop(original);
1196
1197 let Ok(mut sliced) = sliced.try_into_mut() else {
1198 panic!("uniquely owned slice should become mutable")
1199 };
1200 let ptr = sliced.as_ptr();
1201 let capacity = sliced.capacity();
1202 sliced.push_n(0, capacity - sliced.len());
1203 assert_eq!(sliced.len(), capacity);
1204 assert_eq!(sliced.as_ptr(), ptr);
1205 sliced.push(42);
1206 assert_eq!(&sliced[..32], (64u32..96).collect::<Vec<_>>());
1207 assert_eq!(&sliced[32..capacity], vec![0; capacity - 32]);
1208 assert_eq!(sliced[capacity], 42);
1209 }
1210
1211 #[test]
1212 fn from_vec_preserves_drop_glue() {
1213 struct DropValue(Arc<AtomicUsize>);
1214
1215 impl Drop for DropValue {
1216 fn drop(&mut self) {
1217 self.0.fetch_add(1, Ordering::Relaxed);
1218 }
1219 }
1220
1221 let drops = Arc::new(AtomicUsize::new(0));
1222 let values = (0..3)
1223 .map(|_| DropValue(Arc::clone(&drops)))
1224 .collect::<Vec<_>>();
1225 let buffer = Buffer::from(values);
1226
1227 assert_eq!(drops.load(Ordering::Relaxed), 0);
1228 drop(buffer);
1229 assert_eq!(drops.load(Ordering::Relaxed), 3);
1230 }
1231
1232 #[test]
1233 fn empty_aligned_max_alignment() {
1234 let buf = Buffer::<u8>::empty_aligned(Alignment::MAX);
1236 assert!(buf.is_empty());
1237 assert!(buf.is_aligned(Alignment::MAX));
1238 }
1239
1240 #[test]
1241 fn empty_has_no_backing() {
1242 assert!(Buffer::<u8>::empty().backing.is_none());
1243 }
1244
1245 #[test]
1246 fn empty_slice_preserves_alignment() {
1247 let buf = Buffer::<u64>::zeroed_aligned(8, Alignment::new(64));
1248 let sliced = buf.slice(0..0);
1249 assert!(sliced.is_empty());
1250 assert_eq!(sliced.alignment(), Alignment::new(64));
1251 assert!(sliced.is_aligned(Alignment::new(64)));
1252 }
1253
1254 #[test]
1255 fn empty_into_mut_preserves_alignment() {
1256 let buf = Buffer::<u8>::empty_aligned(Alignment::new(64));
1257 let buf_mut = buf.into_mut();
1258 assert_eq!(buf_mut.alignment(), Alignment::new(64));
1259 assert!(buf_mut.is_empty());
1260 }
1261
1262 #[test]
1263 fn test_slice_unaligned_end_pos() {
1264 let data = vec![0u8; 2];
1265 let aligned_buffer = Buffer::copy_from_aligned(&data, Alignment::new(8));
1267 aligned_buffer.slice(0..1);
1272 }
1273
1274 #[test]
1275 fn test_empty_equality() {
1276 let a = Buffer::<u16>::empty();
1277 let b = Buffer::<u16>::empty();
1278
1279 assert_eq!(a, b);
1280 }
1281}