1use arrow_array::RunArray;
5use arrow_array::types::RunEndIndexType;
6use vortex_array::ArrayRef;
7use vortex_array::IntoArray;
8use vortex_array::VortexSessionExecute;
9use vortex_array::arrays::PrimitiveArray;
10use vortex_array::arrays::primitive::PrimitiveArrayExt;
11use vortex_array::dtype::NativePType;
12use vortex_array::legacy_session;
13use vortex_array::validity::Validity;
14use vortex_buffer::Buffer;
15use vortex_error::VortexResult;
16use vortex_runend::RunEndData;
17use vortex_runend::ops::find_physical_index;
18use vortex_runend::ops::find_slice_end_index;
19
20use crate::FromArrowArray;
21
22impl<R: RunEndIndexType> FromArrowArray<&RunArray<R>> for RunEndData
23where
24 R::Native: NativePType,
25{
26 #[allow(clippy::disallowed_methods)]
27 fn from_arrow(array: &RunArray<R>, nullable: bool) -> VortexResult<Self> {
28 let offset = array.run_ends().offset();
29 let len = array.run_ends().len();
30 let ends_buf =
31 Buffer::<R::Native>::from_arrow_scalar_buffer(array.run_ends().inner().clone());
32 let ends = PrimitiveArray::new(ends_buf, Validity::NonNullable)
33 .reinterpret_cast(R::Native::PTYPE.to_unsigned());
34 let values = ArrayRef::from_arrow(array.values().as_ref(), nullable)?;
35
36 let ends_array = PrimitiveArray::from_buffer_handle(
37 ends.buffer_handle().clone(),
38 ends.ptype(),
39 ends.validity()?,
40 )
41 .into_array();
42 let mut ctx = legacy_session().create_execution_ctx();
43
44 let (ends_slice, values_slice) = if offset == 0 && len == array.run_ends().max_value() {
45 (ends_array, values)
46 } else {
47 let slice_begin = find_physical_index(&ends_array, offset, &mut ctx)?;
48 let slice_end = find_slice_end_index(&ends_array, offset + len, &mut ctx)?;
49
50 (
51 ends_array.slice(slice_begin..slice_end)?,
52 values.slice(slice_begin..slice_end)?,
53 )
54 };
55
56 RunEndData::validate_parts(&ends_slice, &values_slice, offset, len, &mut ctx)?;
58 Ok(unsafe { RunEndData::new_unchecked(offset) })
59 }
60}
61
62#[cfg(test)]
63mod tests {
64 use std::sync::Arc;
65 use std::sync::LazyLock;
66
67 use arrow_array::Array as _;
68 use arrow_array::Float64Array;
69 use arrow_array::Int32Array;
70 use arrow_array::Int64Array;
71 use arrow_array::RunArray;
72 use arrow_array::types::Int32Type;
73 use arrow_array::types::Int64Type;
74 use arrow_array::types::RunEndIndexType;
75 use arrow_schema::DataType;
76 use arrow_schema::Field;
77 use rstest::rstest;
78 use vortex_array::ArrayRef;
79 use vortex_array::IntoArray as _;
80 use vortex_array::VortexSessionExecute as _;
81 use vortex_array::arrays::PrimitiveArray;
82 use vortex_array::arrays::primitive::PrimitiveArrayExt;
83 use vortex_array::assert_arrays_eq;
84 use vortex_array::dtype::DType;
85 use vortex_array::dtype::NativePType;
86 use vortex_array::dtype::Nullability;
87 use vortex_array::dtype::PType;
88 use vortex_array::validity::Validity;
89 use vortex_buffer::Buffer;
90 use vortex_buffer::buffer;
91 use vortex_error::VortexResult;
92 use vortex_runend::RunEnd;
93 use vortex_runend::RunEndArray;
94 use vortex_runend::ops::find_physical_index;
95 use vortex_runend::ops::find_slice_end_index;
96 use vortex_session::VortexSession;
97
98 use crate::ArrowSessionExt;
99 use crate::FromArrowArray;
100
101 static SESSION: LazyLock<VortexSession> = LazyLock::new(|| {
102 let session = vortex_array::array_session();
103 vortex_runend::initialize(&session);
104 session
105 });
106
107 fn decode_run_array<R: RunEndIndexType>(
108 array: &RunArray<R>,
109 nullable: bool,
110 ) -> VortexResult<RunEndArray>
111 where
112 R::Native: NativePType,
113 {
114 let offset = array.run_ends().offset();
115 let len = array.run_ends().len();
116 let ends_buf =
117 Buffer::<R::Native>::from_arrow_scalar_buffer(array.run_ends().inner().clone());
118 let ends = PrimitiveArray::new(ends_buf, Validity::NonNullable)
119 .reinterpret_cast(R::Native::PTYPE.to_unsigned());
120 let values = ArrayRef::from_arrow(array.values().as_ref(), nullable)?;
121
122 let ends_array = PrimitiveArray::from_buffer_handle(
123 ends.buffer_handle().clone(),
124 ends.ptype(),
125 ends.validity()?,
126 )
127 .into_array();
128 let mut ctx = SESSION.create_execution_ctx();
129 let (ends_slice, values_slice) = if offset == 0 && len == array.run_ends().max_value() {
130 (ends_array, values)
131 } else {
132 let slice_begin = find_physical_index(&ends_array, offset, &mut ctx)?;
133 let slice_end = find_slice_end_index(&ends_array, offset + len, &mut ctx)?;
134
135 (
136 ends_array.slice(slice_begin..slice_end)?,
137 values.slice(slice_begin..slice_end)?,
138 )
139 };
140
141 RunEnd::try_new_offset_length(ends_slice, values_slice, offset, array.len(), &mut ctx)
142 }
143
144 #[test]
145 fn test_arrow_run_array_to_vortex() -> VortexResult<()> {
146 let run_ends = Int32Array::from(vec![3i32, 5, 8]);
150 let values = Int32Array::from(vec![10, 20, 30]);
151 let arrow_run_array = RunArray::<Int32Type>::try_new(&run_ends, &values)?;
152
153 let vortex_array = decode_run_array(&arrow_run_array, false)?;
155
156 assert_arrays_eq!(
157 vortex_array.into_array(),
158 buffer![10i32, 10, 10, 20, 20, 30, 30, 30].into_array(),
159 &mut SESSION.create_execution_ctx()
160 );
161 Ok(())
162 }
163
164 #[test]
165 fn test_arrow_run_array_with_nulls_to_vortex() -> VortexResult<()> {
166 let run_ends = Int32Array::from(vec![2i32, 4, 6]);
168 let values = Int32Array::from(vec![Some(100), None, Some(300)]);
169 let arrow_run_array = RunArray::<Int32Type>::try_new(&run_ends, &values)?;
170
171 let vortex_array = decode_run_array(&arrow_run_array, true)?;
173
174 assert_arrays_eq!(
175 vortex_array.into_array(),
176 PrimitiveArray::from_option_iter([
177 Some(100i32),
178 Some(100i32),
179 None,
180 None,
181 Some(300i32),
182 Some(300i32)
183 ]),
184 &mut SESSION.create_execution_ctx()
185 );
186 Ok(())
187 }
188
189 #[test]
190 fn test_arrow_run_array_with_different_types() -> VortexResult<()> {
191 let run_ends = Int64Array::from(vec![1i64, 3, 4]);
193 let values = Float64Array::from(vec![1.5, 2.5, 3.5]);
194 let arrow_run_array = RunArray::<Int64Type>::try_new(&run_ends, &values)?;
195
196 let vortex_array = decode_run_array(&arrow_run_array, false)?;
198
199 assert_arrays_eq!(
200 vortex_array,
201 buffer![1.5f64, 2.5, 2.5, 3.5].into_array(),
202 &mut SESSION.create_execution_ctx()
203 );
204 Ok(())
205 }
206
207 #[test]
208 fn test_sliced_arrow_run_array_to_vortex() -> VortexResult<()> {
209 let run_ends = Int32Array::from(vec![2i32, 5, 8, 10]);
213 let values = Int32Array::from(vec![100, 200, 300, 400]);
214 let arrow_run_array = RunArray::<Int32Type>::try_new(&run_ends, &values)?;
215
216 let sliced_array = arrow_run_array.slice(1, 6);
219
220 let vortex_array = decode_run_array(&sliced_array, false)?;
222 assert_arrays_eq!(
223 vortex_array,
224 buffer![100, 200, 200, 200, 300, 300].into_array(),
225 &mut SESSION.create_execution_ctx()
226 );
227 Ok(())
228 }
229
230 #[test]
231 fn test_sliced_arrow_run_array_with_nulls_to_vortex() -> VortexResult<()> {
232 let run_ends = Int64Array::from(vec![3i64, 6, 9, 12]);
236 let values = Int64Array::from(vec![Some(10), None, Some(30), Some(40)]);
237 let arrow_run_array = RunArray::<Int64Type>::try_new(&run_ends, &values)?;
238
239 let sliced_array = arrow_run_array.slice(4, 6);
243
244 let vortex_array = decode_run_array(&sliced_array, true)?;
246
247 assert_arrays_eq!(
248 vortex_array,
249 PrimitiveArray::from_option_iter([
250 None,
251 None,
252 Some(30i64),
253 Some(30),
254 Some(30),
255 Some(40),
256 ]),
257 &mut SESSION.create_execution_ctx()
258 );
259 Ok(())
260 }
261
262 #[test]
263 fn test_sliced_to_0_arrow_run_array_with_nulls_to_vortex() -> VortexResult<()> {
264 let run_ends = Int64Array::from(vec![3i64, 6, 9, 12]);
268 let values = Int64Array::from(vec![Some(10), None, Some(30), Some(40)]);
269 let arrow_run_array = RunArray::<Int64Type>::try_new(&run_ends, &values)?;
270
271 let sliced_array = arrow_run_array.slice(4, 0);
275
276 let vortex_array = decode_run_array(&sliced_array, true)?;
278
279 assert_eq!(vortex_array.len(), 0);
281 assert_eq!(
282 vortex_array.dtype(),
283 &DType::Primitive(PType::I64, Nullability::Nullable)
284 );
285 Ok(())
286 }
287
288 fn ree_type(ends: DataType, values_dtype: DataType) -> DataType {
289 DataType::RunEndEncoded(
290 Arc::new(Field::new("run_ends", ends, false)),
291 Arc::new(Field::new("values", values_dtype, true)),
292 )
293 }
294
295 fn execute(array: ArrayRef, dt: &DataType) -> VortexResult<arrow_array::ArrayRef> {
296 let field = Field::new("", dt.clone(), true);
297 SESSION
298 .arrow()
299 .execute_arrow(array, Some(&field), &mut SESSION.create_execution_ctx())
300 }
301
302 #[test]
303 fn test_roundtrip_arrow_to_vortex_to_arrow() -> VortexResult<()> {
304 let original = RunArray::<Int32Type>::try_new(
305 &Int32Array::from(vec![3i32, 5, 8]),
306 &Int32Array::from(vec![10, 20, 30]),
307 )?;
308 let vortex_array = decode_run_array(&original, false)?;
309 let target = ree_type(DataType::Int32, DataType::Int32);
310 let result = execute(vortex_array.into_array(), &target)?;
311
312 let expected = RunArray::<Int32Type>::try_new(
313 &Int32Array::from(vec![3, 5, 8]),
314 &Int32Array::from(vec![10, 20, 30]),
315 )?;
316 assert_eq!(result.as_ref(), &expected);
317 Ok(())
318 }
319
320 #[rstest]
323 #[case::nonzero_offset(
324 &[10i32, 10, 20, 20, 20, 30, 30],
325 1..5usize,
326 &[1i32, 4],
327 &[10i32, 20],
328 )]
329 #[case::zero_offset_excess_runs(
330 &[10i32, 10, 10, 20, 20, 30, 30, 30, 30, 30],
331 0..4usize,
332 &[3i32, 4],
333 &[10i32, 20],
334 )]
335 fn sliced_runend_to_arrow_ree(
336 #[case] input: &[i32],
337 #[case] slice_range: std::ops::Range<usize>,
338 #[case] expected_ends: &[i32],
339 #[case] expected_values: &[i32],
340 ) -> VortexResult<()> {
341 let mut ctx = SESSION.create_execution_ctx();
342 let array = RunEnd::encode(
343 PrimitiveArray::from_iter(input.iter().copied()).into_array(),
344 &mut ctx,
345 )?;
346 let sliced = array.into_array().slice(slice_range.clone())?;
347 let target = ree_type(DataType::Int32, DataType::Int32);
348 let result = execute(sliced, &target)?;
349
350 assert_eq!(result.len(), slice_range.len());
351 let expected = RunArray::<Int32Type>::try_new(
352 &Int32Array::from(expected_ends.to_vec()),
353 &Int32Array::from(expected_values.to_vec()),
354 )?;
355 assert_eq!(result.as_ref(), &expected);
356 Ok(())
357 }
358}