Skip to main content

vortex_buffer/
buffer.rs

1// SPDX-License-Identifier: Apache-2.0
2// SPDX-FileCopyrightText: Copyright the Vortex contributors
3
4use 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/// An immutable buffer of items of `T`.
31///
32/// Zero-sized element types are rejected at compile time when constructing a buffer.
33///
34/// ```compile_fail
35/// use vortex_buffer::Buffer;
36/// let _ = Buffer::<()>::empty();
37/// ```
38///
39/// ```compile_fail
40/// use vortex_buffer::Buffer;
41/// let _ = Buffer::from(vec![(); 3]);
42/// ```
43///
44/// ```compile_fail
45/// use vortex_buffer::{Buffer, ByteBuffer};
46/// let _ = Buffer::<()>::from_byte_buffer(ByteBuffer::empty());
47/// ```
48///
49/// ```compile_fail
50/// use bytes::Bytes;
51/// use vortex_buffer::{Alignment, Buffer};
52/// let _ = Buffer::<()>::from_bytes_aligned(Bytes::new(), Alignment::none());
53/// ```
54#[derive(Clone)]
55pub struct Buffer<T> {
56    /// The first element in this view; may dangle for an empty buffer.
57    pub(crate) ptr: NonNull<T>,
58    /// The number of initialized `T` values visible from `ptr`.
59    pub(crate) length: usize,
60    /// The minimum alignment promised for `ptr` and preserved by aligned slices.
61    pub(crate) alignment: Alignment,
62    /// Shared ownership of the storage containing `ptr`, if any; `Buffer::empty` has no backing.
63    pub(crate) backing: Option<Arc<BufferBacking>>,
64}
65
66// SAFETY: Buffer is an immutable view over backing memory. Its pointer remains valid while the
67// backing is live, and sharing elements follows the same bounds as sharing a slice.
68unsafe impl<T: Send> Send for Buffer<T> {}
69// SAFETY: see the Send implementation above.
70unsafe 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        // SAFETY: BufferMut keeps offset within allocation, including for empty buffers.
121        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    /// Returns a new `Buffer<T>` copied from the provided `Vec<T>`, `&[T]`, etc.
165    ///
166    /// Due to our underlying usage of `bytes::Bytes`, we are unable to take zero-copy ownership
167    /// of the provided `Vec<T>` while maintaining the ability to convert it back into a mutable
168    /// buffer. We could fix this by forking `Bytes`, or in many other complex ways, but for now
169    /// callers should prefer to construct `Buffer<T>` from a `BufferMut<T>`.
170    pub fn copy_from(values: impl AsRef<[T]>) -> Self {
171        BufferMut::copy_from(values).freeze()
172    }
173
174    /// Returns a new `Buffer<T>` copied with the provided allocator.
175    pub fn copy_from_in(values: impl AsRef<[T]>, allocator: BufferAllocatorRef) -> Self {
176        BufferMut::copy_from_in(values, allocator).freeze()
177    }
178
179    /// Returns a new `Buffer<T>` copied from the provided slice and with the requested alignment.
180    ///
181    /// The allocation is over-aligned to [`Alignment::DEFAULT_ALIGNMENT`] when that is larger than
182    /// `alignment`. Use [`copy_from_preferred_aligned`] to control the over-alignment.
183    ///
184    /// [`copy_from_preferred_aligned`]: Self::copy_from_preferred_aligned
185    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    /// Returns a new `Buffer<T>` copied from the provided slice and with the requested alignment.
190    ///
191    /// The buffer reports `alignment`, but the underlying allocation is over-aligned to the larger
192    /// of `alignment` and `preferred_alignment`.
193    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    /// Create a new zeroed `Buffer` with the given value.
202    pub fn zeroed(len: usize) -> Self {
203        Self::zeroed_aligned(len, Alignment::of::<T>())
204    }
205
206    /// Create a new zeroed `Buffer` with the provided allocator.
207    pub fn zeroed_in(len: usize, allocator: BufferAllocatorRef) -> Self {
208        BufferMut::zeroed_in(len, allocator).freeze()
209    }
210
211    /// Create a new zeroed `Buffer` with the requested alignment.
212    ///
213    /// The allocation is over-aligned to [`Alignment::DEFAULT_ALIGNMENT`] when that is larger than
214    /// `alignment`. Use [`zeroed_preferred_aligned`] to control the over-alignment.
215    ///
216    /// [`zeroed_preferred_aligned`]: Self::zeroed_preferred_aligned
217    pub fn zeroed_aligned(len: usize, alignment: Alignment) -> Self {
218        Self::zeroed_preferred_aligned(len, alignment, Some(Alignment::DEFAULT_ALIGNMENT))
219    }
220
221    /// Create a new zeroed `Buffer` with the requested alignment.
222    ///
223    /// The buffer reports `alignment`, but the underlying allocation is over-aligned to the larger
224    /// of `alignment` and `preferred_alignment`.
225    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    /// Create a new empty `ByteBuffer` with the provided alignment.
234    pub fn empty() -> Self {
235        Self::empty_aligned(Alignment::of::<T>())
236    }
237
238    /// Create a new empty `ByteBuffer` with the provided alignment.
239    ///
240    /// This does not allocate. Empty buffers use an aligned dangling pointer.
241    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    /// Create a new full `ByteBuffer` with the given value.
259    pub fn full(item: T, len: usize) -> Self
260    where
261        T: Copy,
262    {
263        BufferMut::full(item, len).freeze()
264    }
265
266    /// Create a full `Buffer` with the given value and allocator.
267    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    /// Create a `Buffer<T>` zero-copy from a `ByteBuffer`.
275    ///
276    /// ## Panics
277    ///
278    /// Panics if the buffer is not aligned to the size of `T`, or the length is not a multiple of
279    /// the size of `T`.
280    pub fn from_byte_buffer(buffer: ByteBuffer) -> Self {
281        // TODO(ngates): should this preserve the current alignment of the buffer?
282        Self::from_byte_buffer_aligned(buffer, Alignment::of::<T>())
283    }
284
285    /// Create a `Buffer<T>` zero-copy from a `ByteBuffer`.
286    ///
287    /// ## Panics
288    ///
289    /// Panics if the buffer is not aligned to the given alignment, if the length is not a multiple
290    /// of the size of `T`, or if the given alignment is not aligned to that of `T`.
291    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    /// Create a `Buffer<T>` zero-copy from a `Bytes`.
319    ///
320    /// ## Panics
321    ///
322    /// Panics if the buffer is not aligned to the size of `T`, or the length is not a multiple of
323    /// the size of `T`.
324    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    /// Create a buffer with values from the TrustedLen iterator.
350    /// Should be preferred over `from_iter` when the iterator is known to be `TrustedLen`.
351    pub fn from_trusted_len_iter<I: TrustedLen<Item = T>>(iter: I) -> Self {
352        BufferMut::from_trusted_len_iter(iter).freeze()
353    }
354
355    /// Map each element of the buffer with a closure.
356    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                // Safety: just assigned to each value
375                unsafe { out_buf.set_len(len) }
376                out_buf
377            }
378        }
379    }
380
381    /// Clear the buffer, preserving existing capacity.
382    pub fn clear(&mut self) {
383        self.length = 0;
384    }
385
386    /// Returns the length of the buffer in elements of type T.
387    #[allow(clippy::inline_always)]
388    #[inline(always)]
389    pub fn len(&self) -> usize {
390        self.length
391    }
392
393    /// Returns whether the buffer is empty.
394    #[allow(clippy::inline_always)]
395    #[inline(always)]
396    pub fn is_empty(&self) -> bool {
397        self.length == 0
398    }
399
400    /// Returns the alignment of the buffer.
401    #[allow(clippy::inline_always)]
402    #[inline(always)]
403    pub fn alignment(&self) -> Alignment {
404        self.alignment
405    }
406
407    /// Returns the allocator to use for derived buffers.
408    ///
409    /// External buffers use the static allocator.
410    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    /// Returns a raw pointer to the buffer's data.
418    #[allow(clippy::inline_always)]
419    #[inline(always)]
420    pub fn as_ptr(&self) -> *const T {
421        self.ptr.as_ptr()
422    }
423
424    /// Returns a slice over the buffer of elements of type T.
425    #[allow(clippy::inline_always)]
426    #[inline(always)]
427    pub fn as_slice(&self) -> &[T] {
428        // SAFETY: ptr points into the live backing and construction checks its alignment.
429        unsafe { std::slice::from_raw_parts(self.ptr.as_ptr(), self.length) }
430    }
431
432    /// Return a view over the buffer as an opaque byte slice.
433    #[allow(clippy::inline_always)]
434    #[inline(always)]
435    pub fn as_bytes(&self) -> &[u8] {
436        // SAFETY: the element range is initialized and remains live through backing.
437        unsafe {
438            std::slice::from_raw_parts(self.ptr.as_ptr().cast(), size_of_val(self.as_slice()))
439        }
440    }
441
442    /// Returns an iterator over the buffer of elements of type T.
443    pub fn iter(&self) -> Iter<'_, T> {
444        Iter {
445            inner: self.as_slice().iter(),
446        }
447    }
448
449    /// Returns a slice of self for the provided range.
450    ///
451    /// # Panics
452    ///
453    /// Requires that `begin <= end` and `end <= self.len()`.
454    /// Also requires that both `begin` and `end` are aligned to the buffer's required alignment.
455    #[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    /// Returns a slice of self for the provided range, with no guarantees about the resulting
462    /// alignment.
463    ///
464    /// # Panics
465    ///
466    /// Requires that `begin <= end` and `end <= self.len()`.
467    #[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    /// Returns a slice of self for the provided range, ensuring the resulting slice has the
474    /// given alignment.
475    ///
476    /// # Panics
477    ///
478    /// Requires that `begin <= end` and `end <= self.len()`.
479    /// Also requires that both `begin` and `end` are aligned to the given alignment.
480    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            // We prefer to return a new empty buffer instead of sharing this one and creating a
510            // strong reference just to hold an empty slice.
511            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            // SAFETY: begin is in bounds and the alignment check applies to the new pointer.
527            ptr: unsafe { self.ptr.add(begin) },
528            length: end - begin,
529            alignment,
530            backing: self.backing.clone(),
531        }
532    }
533
534    /// Returns a slice of self that is equivalent to the given subset.
535    ///
536    /// When processing the buffer you will often end up with `&[T]` that is a subset
537    /// of the underlying buffer. This function turns the slice into a slice of the buffer
538    /// it has been taken from.
539    ///
540    /// # Panics:
541    /// Requires that the given sub slice is in fact contained within the Bytes buffer; otherwise this function will panic.
542    #[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    /// Returns a slice of self that is equivalent to the given subset.
549    ///
550    /// When processing the buffer you will often end up with `&[T]` that is a subset
551    /// of the underlying buffer. This function turns the slice into a slice of the buffer
552    /// it has been taken from.
553    ///
554    /// # Panics:
555    /// Requires that the given sub slice is in fact contained within the Bytes buffer; otherwise this function will panic.
556    /// Also requires that the given alignment aligns to the type of slice and is smaller or equal to the buffers alignment
557    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    /// Returns the underlying bytes without copying.
589    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    /// Return the ByteBuffer for this `Buffer<T>`.
617    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    /// Try to convert self into `BufferMut<T>` if there is only a single strong reference.
627    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    /// Convert self into `BufferMut<T>`, cloning the data if there are multiple strong references.
673    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    /// Returns whether a `Buffer<T>` is aligned to the given alignment.
681    pub fn is_aligned(&self, alignment: Alignment) -> bool {
682        alignment.is_ptr_aligned(self.as_ptr())
683    }
684
685    /// Return a `Buffer<T>` with the given alignment. Where possible, this will be zero-copy.
686    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    /// Return a `Buffer<T>` with the given alignment. Panics if the buffer is not aligned.
704    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    /// Transmute a `Buffer<T>` into a `Buffer<U>`.
716    ///
717    /// # Safety
718    ///
719    /// The caller must ensure that all possible bit representations of type `T` are valid when
720    /// interpreted as type `U`.
721    /// See [`std::mem::transmute`] for more details.
722    ///
723    /// # Panics
724    ///
725    /// Panics if the type `U` does not have the same size and alignment as `T`.
726    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
743/// An iterator over Buffer elements.
744///
745/// This is an analog to the `std::slice::Iter` type.
746pub 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            // Keep the typed owner so its elements are dropped.
829            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        // SAFETY: cnt is within the initialized byte range.
872        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
883// SAFETY: the owner exposes immutable initialized bytes and keeps their backing live.
884unsafe 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        // SAFETY: ptr and length came from a live Buffer.
891        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
900/// Owned iterator over a [`Buffer`].
901pub struct BufferIterator<T: Copy> {
902    // Keep the buffer alive for the duration of the iteration.
903    _buffer: Buffer<T>,
904    ptr: *const T,
905    end: *const T,
906}
907
908// SAFETY: `BufferIterator` is a `Buffer<T>` plus two cursors into it, so it can safely be
909// `Send`/`Sync` exactly when `Buffer<T>` is. Same bounds as `std::vec::IntoIter`.
910unsafe 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            // SAFETY: ptr is within the buffer and has not reached end.
922            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        // With a regular slice, this would panic. See [`slice_bad_alignment`].
1006        let sliced = buf.slice_unaligned(1..2);
1007        // Verify the slice has the expected length (1 byte from index 1 to 2).
1008        assert_eq!(sliced.len(), 1);
1009        // The original buffer has i32 values [0, 1, 2, 3, 4].
1010        // In little-endian bytes, 0i32 = [0, 0, 0, 0], so byte at index 1 is 0.
1011        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        // We should only be able to slice this buffer on 4-byte (i32) boundaries.
1019        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        // The buffer reports the scalar type's alignment, ...
1061        assert_eq!(buf.alignment(), Alignment::of::<u32>());
1062        // ... but the underlying allocation is over-aligned to DEFAULT_ALIGNMENT.
1063        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        // Empty buffers are backed by a static and must satisfy any valid alignment.
1235        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        // Overalign the u8 vector.
1266        let aligned_buffer = Buffer::copy_from_aligned(&data, Alignment::new(8));
1267        // Previously, `Buffer::slice` incorrectly asserted that the end position
1268        // must be aligned. That assertion has been removed such that the end
1269        // position can be arbitrary and only the beginning of the slice needs
1270        // to be aligned.
1271        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}