1use arrow_buffer::ArrowNativeType;
5use arrow_buffer::OffsetBuffer;
6use vortex_error::vortex_panic;
7
8use crate::Alignment;
9use crate::Buffer;
10use crate::ByteBuffer;
11
12impl<T: ArrowNativeType> Buffer<T> {
13 pub fn into_arrow_scalar_buffer(self) -> arrow_buffer::ScalarBuffer<T> {
15 if self.is_empty() {
16 return Vec::new().into();
17 }
18 let buffer = self.into_byte_buffer().into_arrow_buffer();
19 arrow_buffer::ScalarBuffer::from(buffer)
20 }
21
22 pub fn from_arrow_scalar_buffer(arrow: arrow_buffer::ScalarBuffer<T>) -> Self {
29 let length = arrow.len();
30 let arrow = arrow.into_inner();
31
32 let alignment = Alignment::of::<T>();
33 if arrow.as_ptr().align_offset(alignment.as_usize()) != 0 {
34 vortex_panic!(
35 "Arrow buffer is not aligned to the requested alignment: {}",
36 alignment
37 );
38 }
39
40 debug_assert_eq!(length, arrow.len() / size_of::<T>());
41 Self::from_arrow_owner(arrow, length, alignment)
42 }
43
44 pub fn into_arrow_offset_buffer(self) -> OffsetBuffer<T> {
51 OffsetBuffer::new(self.into_arrow_scalar_buffer())
52 }
53
54 pub unsafe fn into_arrow_offset_buffer_unchecked(self) -> OffsetBuffer<T> {
64 unsafe { OffsetBuffer::new_unchecked(self.into_arrow_scalar_buffer()) }
66 }
67}
68
69impl ByteBuffer {
70 pub fn into_arrow_buffer(self) -> arrow_buffer::Buffer {
72 if let Some(crate::BufferBacking::Arrow(arrow)) = self.backing.as_deref() {
73 let offset = self.ptr.addr().get() - arrow.as_ptr().addr();
74 return arrow.slice_with_length(offset, self.length);
75 }
76 arrow_buffer::Buffer::from(self.into_bytes())
77 }
78
79 pub fn from_arrow_buffer(arrow: arrow_buffer::Buffer, alignment: Alignment) -> Self {
85 let length = arrow.len();
86
87 if arrow.as_ptr().align_offset(alignment.as_usize()) != 0 {
88 vortex_panic!(
89 "Arrow buffer is not aligned to the requested alignment: {}",
90 alignment
91 );
92 }
93
94 Self::from_arrow_owner(arrow, length, alignment)
95 }
96}
97
98#[cfg(test)]
99mod test {
100 use arrow_buffer::Buffer as ArrowBuffer;
101 use arrow_buffer::ScalarBuffer;
102
103 use crate::Alignment;
104 use crate::Buffer;
105 use crate::buffer;
106
107 #[test]
108 fn into_arrow_buffer() {
109 let buf = buffer![0u8, 1, 2];
110 let arrow: ArrowBuffer = buf.clone().into_arrow_buffer();
111 assert_eq!(arrow.as_ref(), buf.as_slice(), "Buffer values differ");
112 assert_eq!(arrow.as_ptr(), buf.as_ptr(), "Conversion not zero-copy")
113 }
114
115 #[test]
116 fn into_arrow_scalar_buffer() {
117 let buf = buffer![0i32, 1, 2];
118 let scalar: ScalarBuffer<i32> = buf.clone().into_arrow_scalar_buffer();
119 assert_eq!(scalar.as_ref(), buf.as_slice(), "Buffer values differ");
120 assert_eq!(scalar.as_ptr(), buf.as_ptr(), "Conversion not zero-copy")
121 }
122
123 #[test]
124 fn empty_into_arrow_scalar_buffer() {
125 let scalar = Buffer::<i64>::empty().into_arrow_scalar_buffer();
126
127 assert!(scalar.is_empty());
128 assert_eq!(scalar.as_ptr().align_offset(align_of::<i64>()), 0);
129 }
130
131 #[test]
132 fn from_arrow_buffer() {
133 let arrow = ArrowBuffer::from_vec(vec![0i32, 1, 2]);
134 let buf = Buffer::from_arrow_buffer(arrow.clone(), Alignment::of::<i32>());
135 assert_eq!(arrow.as_ref(), buf.as_slice(), "Buffer values differ");
136 assert_eq!(arrow.as_ptr(), buf.as_ptr(), "Conversion not zero-copy");
137
138 let round_trip = buf.into_arrow_buffer();
139 assert_eq!(round_trip.as_ptr(), arrow.as_ptr());
140 }
141
142 #[test]
143 fn into_arrow_offset_buffer() {
144 let buf = buffer![0i32, 2, 2, 5];
145 let offsets = buf.clone().into_arrow_offset_buffer();
146 assert_eq!(offsets.as_ref(), buf.as_slice(), "Buffer values differ");
147 assert_eq!(offsets.as_ptr(), buf.as_ptr(), "Conversion not zero-copy");
148 }
149
150 #[test]
151 fn into_arrow_offset_buffer_unchecked() {
152 let buf = buffer![0i32, 2, 2, 5];
153
154 let offsets = unsafe { buf.clone().into_arrow_offset_buffer_unchecked() };
156
157 assert_eq!(offsets.as_ref(), buf.as_slice(), "Buffer values differ");
158 assert_eq!(offsets.as_ptr(), buf.as_ptr(), "Conversion not zero-copy");
159 }
160
161 #[test]
162 fn into_arrow_offset_buffer_allows_nonzero_start() {
163 let offsets = buffer![3i64, 4, 9].into_arrow_offset_buffer();
165 assert_eq!(offsets.as_ref(), &[3, 4, 9]);
166 }
167
168 #[test]
169 #[should_panic(expected = "offsets must be monotonically increasing")]
170 fn into_arrow_offset_buffer_rejects_decreasing_offsets() {
171 drop(buffer![0i32, 5, 3].into_arrow_offset_buffer());
172 }
173
174 #[test]
175 #[should_panic(expected = "offsets must be greater than 0")]
176 fn into_arrow_offset_buffer_rejects_negative_offsets() {
177 drop(buffer![-1i32, 2].into_arrow_offset_buffer());
178 }
179
180 #[test]
181 #[should_panic(expected = "offsets cannot be empty")]
182 fn into_arrow_offset_buffer_rejects_empty() {
183 drop(Buffer::<i32>::empty().into_arrow_offset_buffer());
184 }
185}