Skip to main content

vortex_array/arrow/
convert.rs

1// SPDX-License-Identifier: Apache-2.0
2// SPDX-FileCopyrightText: Copyright the Vortex contributors
3
4use std::sync::Arc;
5
6use arrow_array::AnyDictionaryArray;
7use arrow_array::Array as ArrowArray;
8use arrow_array::ArrowPrimitiveType;
9use arrow_array::BooleanArray as ArrowBooleanArray;
10use arrow_array::DictionaryArray;
11use arrow_array::FixedSizeListArray as ArrowFixedSizeListArray;
12use arrow_array::GenericByteArray;
13use arrow_array::GenericByteViewArray;
14use arrow_array::GenericListArray;
15use arrow_array::GenericListViewArray;
16use arrow_array::NullArray as ArrowNullArray;
17use arrow_array::OffsetSizeTrait;
18use arrow_array::PrimitiveArray as ArrowPrimitiveArray;
19use arrow_array::RecordBatch;
20use arrow_array::StructArray as ArrowStructArray;
21use arrow_array::cast::AsArray;
22use arrow_array::cast::as_null_array;
23use arrow_array::make_array;
24use arrow_array::types::ArrowDictionaryKeyType;
25use arrow_array::types::ByteArrayType;
26use arrow_array::types::ByteViewType;
27use arrow_array::types::Date32Type;
28use arrow_array::types::Date64Type;
29use arrow_array::types::Decimal32Type;
30use arrow_array::types::Decimal64Type;
31use arrow_array::types::Decimal128Type;
32use arrow_array::types::Decimal256Type;
33use arrow_array::types::Float16Type;
34use arrow_array::types::Float32Type;
35use arrow_array::types::Float64Type;
36use arrow_array::types::Int8Type;
37use arrow_array::types::Int16Type;
38use arrow_array::types::Int32Type;
39use arrow_array::types::Int64Type;
40use arrow_array::types::Time32MillisecondType;
41use arrow_array::types::Time32SecondType;
42use arrow_array::types::Time64MicrosecondType;
43use arrow_array::types::Time64NanosecondType;
44use arrow_array::types::TimestampMicrosecondType;
45use arrow_array::types::TimestampMillisecondType;
46use arrow_array::types::TimestampNanosecondType;
47use arrow_array::types::TimestampSecondType;
48use arrow_array::types::UInt8Type;
49use arrow_array::types::UInt16Type;
50use arrow_array::types::UInt32Type;
51use arrow_array::types::UInt64Type;
52use arrow_buffer::ArrowNativeType;
53use arrow_buffer::BooleanBuffer;
54use arrow_buffer::Buffer as ArrowBuffer;
55use arrow_buffer::ScalarBuffer;
56use arrow_buffer::buffer::NullBuffer;
57use arrow_buffer::buffer::OffsetBuffer;
58use arrow_schema::DataType;
59use arrow_schema::TimeUnit as ArrowTimeUnit;
60use itertools::Itertools;
61use vortex_buffer::Alignment;
62use vortex_buffer::BitBuffer;
63use vortex_buffer::Buffer;
64use vortex_buffer::ByteBuffer;
65use vortex_dtype::DType;
66use vortex_dtype::DecimalDType;
67use vortex_dtype::IntegerPType;
68use vortex_dtype::NativePType;
69use vortex_dtype::PType;
70use vortex_dtype::datetime::TimeUnit;
71use vortex_dtype::i256;
72use vortex_error::VortexExpect as _;
73use vortex_error::VortexResult;
74use vortex_error::vortex_bail;
75use vortex_error::vortex_panic;
76
77use crate::ArrayRef;
78use crate::IntoArray;
79use crate::arrays::BoolArray;
80use crate::arrays::DecimalArray;
81use crate::arrays::DictArray;
82use crate::arrays::FixedSizeListArray;
83use crate::arrays::ListArray;
84use crate::arrays::ListViewArray;
85use crate::arrays::NullArray;
86use crate::arrays::PrimitiveArray;
87use crate::arrays::StructArray;
88use crate::arrays::TemporalArray;
89use crate::arrays::VarBinArray;
90use crate::arrays::VarBinViewArray;
91use crate::arrow::FromArrowArray;
92use crate::validity::Validity;
93
94impl IntoArray for ArrowBuffer {
95    fn into_array(self) -> ArrayRef {
96        PrimitiveArray::from_byte_buffer(
97            ByteBuffer::from_arrow_buffer(self, Alignment::of::<u8>()),
98            PType::U8,
99            Validity::NonNullable,
100        )
101        .into_array()
102    }
103}
104
105impl IntoArray for BooleanBuffer {
106    fn into_array(self) -> ArrayRef {
107        BoolArray::new(self.into(), Validity::NonNullable).into_array()
108    }
109}
110
111impl<T> IntoArray for ScalarBuffer<T>
112where
113    T: ArrowNativeType + NativePType,
114{
115    fn into_array(self) -> ArrayRef {
116        PrimitiveArray::new(
117            Buffer::<T>::from_arrow_scalar_buffer(self),
118            Validity::NonNullable,
119        )
120        .into_array()
121    }
122}
123
124impl<O> IntoArray for OffsetBuffer<O>
125where
126    O: IntegerPType + OffsetSizeTrait,
127{
128    fn into_array(self) -> ArrayRef {
129        let primitive = PrimitiveArray::new(
130            Buffer::from_arrow_scalar_buffer(self.into_inner()),
131            Validity::NonNullable,
132        );
133
134        primitive.into_array()
135    }
136}
137
138macro_rules! impl_from_arrow_primitive {
139    ($T:path) => {
140        impl FromArrowArray<&ArrowPrimitiveArray<$T>> for ArrayRef {
141            fn from_arrow(value: &ArrowPrimitiveArray<$T>, nullable: bool) -> VortexResult<Self> {
142                let buffer = Buffer::from_arrow_scalar_buffer(value.values().clone());
143                let validity = nulls(value.nulls(), nullable);
144                Ok(PrimitiveArray::new(buffer, validity).into_array())
145            }
146        }
147    };
148}
149
150impl_from_arrow_primitive!(Int8Type);
151impl_from_arrow_primitive!(Int16Type);
152impl_from_arrow_primitive!(Int32Type);
153impl_from_arrow_primitive!(Int64Type);
154impl_from_arrow_primitive!(UInt8Type);
155impl_from_arrow_primitive!(UInt16Type);
156impl_from_arrow_primitive!(UInt32Type);
157impl_from_arrow_primitive!(UInt64Type);
158impl_from_arrow_primitive!(Float16Type);
159impl_from_arrow_primitive!(Float32Type);
160impl_from_arrow_primitive!(Float64Type);
161
162impl FromArrowArray<&ArrowPrimitiveArray<Decimal32Type>> for ArrayRef {
163    fn from_arrow(
164        array: &ArrowPrimitiveArray<Decimal32Type>,
165        nullable: bool,
166    ) -> VortexResult<Self> {
167        let decimal_type = DecimalDType::new(array.precision(), array.scale());
168        let buffer = Buffer::from_arrow_scalar_buffer(array.values().clone());
169        let validity = nulls(array.nulls(), nullable);
170        Ok(DecimalArray::new(buffer, decimal_type, validity).into_array())
171    }
172}
173
174impl FromArrowArray<&ArrowPrimitiveArray<Decimal64Type>> for ArrayRef {
175    fn from_arrow(
176        array: &ArrowPrimitiveArray<Decimal64Type>,
177        nullable: bool,
178    ) -> VortexResult<Self> {
179        let decimal_type = DecimalDType::new(array.precision(), array.scale());
180        let buffer = Buffer::from_arrow_scalar_buffer(array.values().clone());
181        let validity = nulls(array.nulls(), nullable);
182        Ok(DecimalArray::new(buffer, decimal_type, validity).into_array())
183    }
184}
185
186impl FromArrowArray<&ArrowPrimitiveArray<Decimal128Type>> for ArrayRef {
187    fn from_arrow(
188        array: &ArrowPrimitiveArray<Decimal128Type>,
189        nullable: bool,
190    ) -> VortexResult<Self> {
191        let decimal_type = DecimalDType::new(array.precision(), array.scale());
192        let buffer = Buffer::from_arrow_scalar_buffer(array.values().clone());
193        let validity = nulls(array.nulls(), nullable);
194        Ok(DecimalArray::new(buffer, decimal_type, validity).into_array())
195    }
196}
197
198impl FromArrowArray<&ArrowPrimitiveArray<Decimal256Type>> for ArrayRef {
199    fn from_arrow(
200        array: &ArrowPrimitiveArray<Decimal256Type>,
201        nullable: bool,
202    ) -> VortexResult<Self> {
203        let decimal_type = DecimalDType::new(array.precision(), array.scale());
204        let buffer = Buffer::from_arrow_scalar_buffer(array.values().clone());
205        // SAFETY: Our i256 implementation has the same bit-pattern representation of the
206        //  arrow_buffer::i256 type. It is safe to treat values held inside the buffer as values
207        //  of either type.
208        let buffer =
209            unsafe { std::mem::transmute::<Buffer<arrow_buffer::i256>, Buffer<i256>>(buffer) };
210        let validity = nulls(array.nulls(), nullable);
211        Ok(DecimalArray::new(buffer, decimal_type, validity).into_array())
212    }
213}
214
215macro_rules! impl_from_arrow_temporal {
216    ($T:path) => {
217        impl FromArrowArray<&ArrowPrimitiveArray<$T>> for ArrayRef {
218            fn from_arrow(
219                value: &ArrowPrimitiveArray<$T>,
220                nullable: bool,
221            ) -> vortex_error::VortexResult<Self> {
222                Ok(temporal_array(value, nullable))
223            }
224        }
225    };
226}
227
228// timestamp
229impl_from_arrow_temporal!(TimestampSecondType);
230impl_from_arrow_temporal!(TimestampMillisecondType);
231impl_from_arrow_temporal!(TimestampMicrosecondType);
232impl_from_arrow_temporal!(TimestampNanosecondType);
233
234// time
235impl_from_arrow_temporal!(Time32SecondType);
236impl_from_arrow_temporal!(Time32MillisecondType);
237impl_from_arrow_temporal!(Time64MicrosecondType);
238impl_from_arrow_temporal!(Time64NanosecondType);
239
240// date
241impl_from_arrow_temporal!(Date32Type);
242impl_from_arrow_temporal!(Date64Type);
243
244fn temporal_array<T: ArrowPrimitiveType>(value: &ArrowPrimitiveArray<T>, nullable: bool) -> ArrayRef
245where
246    T::Native: NativePType,
247{
248    let arr = PrimitiveArray::new(
249        Buffer::from_arrow_scalar_buffer(value.values().clone()),
250        nulls(value.nulls(), nullable),
251    )
252    .into_array();
253
254    match value.data_type() {
255        DataType::Timestamp(time_unit, tz) => {
256            TemporalArray::new_timestamp(arr, time_unit.into(), tz.clone()).into()
257        }
258        DataType::Time32(time_unit) => TemporalArray::new_time(arr, time_unit.into()).into(),
259        DataType::Time64(time_unit) => TemporalArray::new_time(arr, time_unit.into()).into(),
260        DataType::Date32 => TemporalArray::new_date(arr, TimeUnit::Days).into(),
261        DataType::Date64 => TemporalArray::new_date(arr, TimeUnit::Milliseconds).into(),
262        DataType::Duration(_) => unimplemented!(),
263        DataType::Interval(_) => unimplemented!(),
264        _ => vortex_panic!("Invalid temporal type: {}", value.data_type()),
265    }
266}
267
268impl<T: ByteArrayType> FromArrowArray<&GenericByteArray<T>> for ArrayRef
269where
270    <T as ByteArrayType>::Offset: IntegerPType,
271{
272    fn from_arrow(value: &GenericByteArray<T>, nullable: bool) -> VortexResult<Self> {
273        let dtype = match T::DATA_TYPE {
274            DataType::Binary | DataType::LargeBinary => DType::Binary(nullable.into()),
275            DataType::Utf8 | DataType::LargeUtf8 => DType::Utf8(nullable.into()),
276            dt => vortex_panic!("Invalid data type for ByteArray: {dt}"),
277        };
278        Ok(VarBinArray::try_new(
279            value.offsets().clone().into_array(),
280            ByteBuffer::from_arrow_buffer(value.values().clone(), Alignment::of::<u8>()),
281            dtype,
282            nulls(value.nulls(), nullable),
283        )?
284        .into_array())
285    }
286}
287
288impl<T: ByteViewType> FromArrowArray<&GenericByteViewArray<T>> for ArrayRef {
289    fn from_arrow(value: &GenericByteViewArray<T>, nullable: bool) -> VortexResult<Self> {
290        let dtype = match T::DATA_TYPE {
291            DataType::BinaryView => DType::Binary(nullable.into()),
292            DataType::Utf8View => DType::Utf8(nullable.into()),
293            dt => vortex_panic!("Invalid data type for ByteViewArray: {dt}"),
294        };
295
296        let views_buffer = Buffer::from_byte_buffer(
297            Buffer::from_arrow_scalar_buffer(value.views().clone()).into_byte_buffer(),
298        );
299
300        // SAFETY: arrow-rs ByteViewArray already checks the same invariants, we inherit those
301        //  guarantees by zero-copy constructing from one.
302        Ok(unsafe {
303            VarBinViewArray::new_unchecked(
304                views_buffer,
305                Arc::from(
306                    value
307                        .data_buffers()
308                        .iter()
309                        .map(|b| ByteBuffer::from_arrow_buffer(b.clone(), Alignment::of::<u8>()))
310                        .collect::<Vec<_>>(),
311                ),
312                dtype,
313                nulls(value.nulls(), nullable),
314            )
315            .into_array()
316        })
317    }
318}
319
320impl FromArrowArray<&ArrowBooleanArray> for ArrayRef {
321    fn from_arrow(value: &ArrowBooleanArray, nullable: bool) -> VortexResult<Self> {
322        Ok(BoolArray::new(
323            value.values().clone().into(),
324            nulls(value.nulls(), nullable),
325        )
326        .into_array())
327    }
328}
329
330/// Strip out the nulls from this array and return a new array without nulls.
331fn remove_nulls(data: arrow_data::ArrayData) -> arrow_data::ArrayData {
332    if data.null_count() == 0 {
333        // No nulls to remove, return the array as is
334        return data;
335    }
336
337    let children = match data.data_type() {
338        DataType::Struct(fields) => Some(
339            fields
340                .iter()
341                .zip(data.child_data().iter())
342                .map(|(field, child_data)| {
343                    if field.is_nullable() {
344                        child_data.clone()
345                    } else {
346                        remove_nulls(child_data.clone())
347                    }
348                })
349                .collect_vec(),
350        ),
351        DataType::List(f)
352        | DataType::LargeList(f)
353        | DataType::ListView(f)
354        | DataType::LargeListView(f)
355        | DataType::FixedSizeList(f, _)
356            if !f.is_nullable() =>
357        {
358            // All list types only have one child
359            assert_eq!(
360                data.child_data().len(),
361                1,
362                "List types should have one child"
363            );
364            Some(vec![remove_nulls(data.child_data()[0].clone())])
365        }
366        _ => None,
367    };
368
369    let mut builder = data.into_builder().nulls(None);
370    if let Some(children) = children {
371        builder = builder.child_data(children);
372    }
373    builder
374        .build()
375        .vortex_expect("reconstructing array without nulls")
376}
377
378impl FromArrowArray<&ArrowStructArray> for ArrayRef {
379    fn from_arrow(value: &ArrowStructArray, nullable: bool) -> VortexResult<Self> {
380        Ok(StructArray::try_new(
381            value.column_names().iter().copied().collect(),
382            value
383                .columns()
384                .iter()
385                .zip(value.fields())
386                .map(|(c, field)| {
387                    // Arrow pushes down nulls, even into non-nullable fields. So we strip them
388                    // out here because Vortex is a little more strict.
389                    if c.null_count() > 0 && !field.is_nullable() {
390                        let stripped = make_array(remove_nulls(c.into_data()));
391                        Self::from_arrow(stripped.as_ref(), false)
392                    } else {
393                        Self::from_arrow(c.as_ref(), field.is_nullable())
394                    }
395                })
396                .collect::<VortexResult<Vec<_>>>()?,
397            value.len(),
398            nulls(value.nulls(), nullable),
399        )?
400        .into_array())
401    }
402}
403
404impl<O: IntegerPType + OffsetSizeTrait> FromArrowArray<&GenericListArray<O>> for ArrayRef {
405    fn from_arrow(value: &GenericListArray<O>, nullable: bool) -> VortexResult<Self> {
406        // Extract the validity of the underlying element array.
407        let elements_are_nullable = match value.data_type() {
408            DataType::List(field) => field.is_nullable(),
409            DataType::LargeList(field) => field.is_nullable(),
410            dt => vortex_panic!("Invalid data type for ListArray: {dt}"),
411        };
412
413        let elements = Self::from_arrow(value.values().as_ref(), elements_are_nullable)?;
414
415        // `offsets` are always non-nullable.
416        let offsets = value.offsets().clone().into_array();
417        let nulls = nulls(value.nulls(), nullable);
418
419        Ok(ListArray::try_new(elements, offsets, nulls)?.into_array())
420    }
421}
422
423impl<O: OffsetSizeTrait + NativePType> FromArrowArray<&GenericListViewArray<O>> for ArrayRef {
424    fn from_arrow(array: &GenericListViewArray<O>, nullable: bool) -> VortexResult<Self> {
425        // Extract the validity of the underlying element array.
426        let elements_are_nullable = match array.data_type() {
427            DataType::ListView(field) => field.is_nullable(),
428            DataType::LargeListView(field) => field.is_nullable(),
429            dt => vortex_panic!("Invalid data type for ListViewArray: {dt}"),
430        };
431
432        let elements = Self::from_arrow(array.values().as_ref(), elements_are_nullable)?;
433
434        // `offsets` and `sizes` are always non-nullable.
435        let offsets = array.offsets().clone().into_array();
436        let sizes = array.sizes().clone().into_array();
437        let nulls = nulls(array.nulls(), nullable);
438
439        Ok(ListViewArray::try_new(elements, offsets, sizes, nulls)?.into_array())
440    }
441}
442
443impl FromArrowArray<&ArrowFixedSizeListArray> for ArrayRef {
444    fn from_arrow(array: &ArrowFixedSizeListArray, nullable: bool) -> VortexResult<Self> {
445        let DataType::FixedSizeList(field, list_size) = array.data_type() else {
446            vortex_panic!("Invalid data type for ListArray: {}", array.data_type());
447        };
448
449        Ok(FixedSizeListArray::try_new(
450            Self::from_arrow(array.values().as_ref(), field.is_nullable())?,
451            *list_size as u32,
452            nulls(array.nulls(), nullable),
453            array.len(),
454        )?
455        .into_array())
456    }
457}
458
459impl FromArrowArray<&ArrowNullArray> for ArrayRef {
460    fn from_arrow(value: &ArrowNullArray, nullable: bool) -> VortexResult<Self> {
461        assert!(nullable);
462        Ok(NullArray::new(value.len()).into_array())
463    }
464}
465
466impl<K: ArrowDictionaryKeyType> FromArrowArray<&DictionaryArray<K>> for DictArray {
467    fn from_arrow(array: &DictionaryArray<K>, nullable: bool) -> VortexResult<Self> {
468        let keys = AnyDictionaryArray::keys(array);
469        let keys = ArrayRef::from_arrow(keys, keys.is_nullable())?;
470        let values = ArrayRef::from_arrow(array.values().as_ref(), nullable)?;
471        // SAFETY: we assume that Arrow has checked the invariants on construction.
472        Ok(unsafe { DictArray::new_unchecked(keys, values) })
473    }
474}
475
476fn nulls(nulls: Option<&NullBuffer>, nullable: bool) -> Validity {
477    if nullable {
478        nulls
479            .map(|nulls| {
480                if nulls.null_count() == nulls.len() {
481                    Validity::AllInvalid
482                } else {
483                    Validity::from(BitBuffer::from(nulls.inner().clone()))
484                }
485            })
486            .unwrap_or_else(|| Validity::AllValid)
487    } else {
488        assert!(nulls.map(|x| x.null_count() == 0).unwrap_or(true));
489        Validity::NonNullable
490    }
491}
492
493impl FromArrowArray<&dyn ArrowArray> for ArrayRef {
494    fn from_arrow(array: &dyn ArrowArray, nullable: bool) -> VortexResult<Self> {
495        match array.data_type() {
496            DataType::Boolean => Self::from_arrow(array.as_boolean(), nullable),
497            DataType::UInt8 => Self::from_arrow(array.as_primitive::<UInt8Type>(), nullable),
498            DataType::UInt16 => Self::from_arrow(array.as_primitive::<UInt16Type>(), nullable),
499            DataType::UInt32 => Self::from_arrow(array.as_primitive::<UInt32Type>(), nullable),
500            DataType::UInt64 => Self::from_arrow(array.as_primitive::<UInt64Type>(), nullable),
501            DataType::Int8 => Self::from_arrow(array.as_primitive::<Int8Type>(), nullable),
502            DataType::Int16 => Self::from_arrow(array.as_primitive::<Int16Type>(), nullable),
503            DataType::Int32 => Self::from_arrow(array.as_primitive::<Int32Type>(), nullable),
504            DataType::Int64 => Self::from_arrow(array.as_primitive::<Int64Type>(), nullable),
505            DataType::Float16 => Self::from_arrow(array.as_primitive::<Float16Type>(), nullable),
506            DataType::Float32 => Self::from_arrow(array.as_primitive::<Float32Type>(), nullable),
507            DataType::Float64 => Self::from_arrow(array.as_primitive::<Float64Type>(), nullable),
508            DataType::Utf8 => Self::from_arrow(array.as_string::<i32>(), nullable),
509            DataType::LargeUtf8 => Self::from_arrow(array.as_string::<i64>(), nullable),
510            DataType::Binary => Self::from_arrow(array.as_binary::<i32>(), nullable),
511            DataType::LargeBinary => Self::from_arrow(array.as_binary::<i64>(), nullable),
512            DataType::BinaryView => Self::from_arrow(array.as_binary_view(), nullable),
513            DataType::Utf8View => Self::from_arrow(array.as_string_view(), nullable),
514            DataType::Struct(_) => Self::from_arrow(array.as_struct(), nullable),
515            DataType::List(_) => Self::from_arrow(array.as_list::<i32>(), nullable),
516            DataType::LargeList(_) => Self::from_arrow(array.as_list::<i64>(), nullable),
517            DataType::ListView(_) => Self::from_arrow(array.as_list_view::<i32>(), nullable),
518            DataType::LargeListView(_) => Self::from_arrow(array.as_list_view::<i64>(), nullable),
519            DataType::FixedSizeList(..) => Self::from_arrow(array.as_fixed_size_list(), nullable),
520            DataType::Null => Self::from_arrow(as_null_array(array), nullable),
521            DataType::Timestamp(u, _) => match u {
522                ArrowTimeUnit::Second => {
523                    Self::from_arrow(array.as_primitive::<TimestampSecondType>(), nullable)
524                }
525                ArrowTimeUnit::Millisecond => {
526                    Self::from_arrow(array.as_primitive::<TimestampMillisecondType>(), nullable)
527                }
528                ArrowTimeUnit::Microsecond => {
529                    Self::from_arrow(array.as_primitive::<TimestampMicrosecondType>(), nullable)
530                }
531                ArrowTimeUnit::Nanosecond => {
532                    Self::from_arrow(array.as_primitive::<TimestampNanosecondType>(), nullable)
533                }
534            },
535            DataType::Date32 => Self::from_arrow(array.as_primitive::<Date32Type>(), nullable),
536            DataType::Date64 => Self::from_arrow(array.as_primitive::<Date64Type>(), nullable),
537            DataType::Time32(u) => match u {
538                ArrowTimeUnit::Second => {
539                    Self::from_arrow(array.as_primitive::<Time32SecondType>(), nullable)
540                }
541                ArrowTimeUnit::Millisecond => {
542                    Self::from_arrow(array.as_primitive::<Time32MillisecondType>(), nullable)
543                }
544                ArrowTimeUnit::Microsecond | ArrowTimeUnit::Nanosecond => unreachable!(),
545            },
546            DataType::Time64(u) => match u {
547                ArrowTimeUnit::Microsecond => {
548                    Self::from_arrow(array.as_primitive::<Time64MicrosecondType>(), nullable)
549                }
550                ArrowTimeUnit::Nanosecond => {
551                    Self::from_arrow(array.as_primitive::<Time64NanosecondType>(), nullable)
552                }
553                ArrowTimeUnit::Second | ArrowTimeUnit::Millisecond => unreachable!(),
554            },
555            DataType::Decimal32(..) => {
556                Self::from_arrow(array.as_primitive::<Decimal32Type>(), nullable)
557            }
558            DataType::Decimal64(..) => {
559                Self::from_arrow(array.as_primitive::<Decimal64Type>(), nullable)
560            }
561            DataType::Decimal128(..) => {
562                Self::from_arrow(array.as_primitive::<Decimal128Type>(), nullable)
563            }
564            DataType::Decimal256(..) => {
565                Self::from_arrow(array.as_primitive::<Decimal256Type>(), nullable)
566            }
567            DataType::Dictionary(key_type, _) => match key_type.as_ref() {
568                DataType::Int8 => Ok(DictArray::from_arrow(
569                    array.as_dictionary::<Int8Type>(),
570                    nullable,
571                )?
572                .into_array()),
573                DataType::Int16 => Ok(DictArray::from_arrow(
574                    array.as_dictionary::<Int16Type>(),
575                    nullable,
576                )?
577                .into_array()),
578                DataType::Int32 => Ok(DictArray::from_arrow(
579                    array.as_dictionary::<Int32Type>(),
580                    nullable,
581                )?
582                .into_array()),
583                DataType::Int64 => Ok(DictArray::from_arrow(
584                    array.as_dictionary::<Int64Type>(),
585                    nullable,
586                )?
587                .into_array()),
588                DataType::UInt8 => Ok(DictArray::from_arrow(
589                    array.as_dictionary::<UInt8Type>(),
590                    nullable,
591                )?
592                .into_array()),
593                DataType::UInt16 => Ok(DictArray::from_arrow(
594                    array.as_dictionary::<UInt16Type>(),
595                    nullable,
596                )?
597                .into_array()),
598                DataType::UInt32 => Ok(DictArray::from_arrow(
599                    array.as_dictionary::<UInt32Type>(),
600                    nullable,
601                )?
602                .into_array()),
603                DataType::UInt64 => Ok(DictArray::from_arrow(
604                    array.as_dictionary::<UInt64Type>(),
605                    nullable,
606                )?
607                .into_array()),
608                key_dt => vortex_bail!("Unsupported dictionary key type: {key_dt}"),
609            },
610            dt => vortex_bail!("Array encoding not implemented for Arrow data type {dt}"),
611        }
612    }
613}
614
615impl FromArrowArray<RecordBatch> for ArrayRef {
616    fn from_arrow(array: RecordBatch, nullable: bool) -> VortexResult<Self> {
617        ArrayRef::from_arrow(&arrow_array::StructArray::from(array), nullable)
618    }
619}
620
621impl FromArrowArray<&RecordBatch> for ArrayRef {
622    fn from_arrow(array: &RecordBatch, nullable: bool) -> VortexResult<Self> {
623        Self::from_arrow(array.clone(), nullable)
624    }
625}
626
627#[cfg(test)]
628mod tests {
629    use std::sync::Arc;
630
631    use arrow_array::Array as ArrowArray;
632    use arrow_array::BinaryArray;
633    use arrow_array::BooleanArray;
634    use arrow_array::Date32Array;
635    use arrow_array::Date64Array;
636    use arrow_array::FixedSizeListArray as ArrowFixedSizeListArray;
637    use arrow_array::Float32Array;
638    use arrow_array::Float64Array;
639    use arrow_array::GenericListViewArray;
640    use arrow_array::Int8Array;
641    use arrow_array::Int16Array;
642    use arrow_array::Int32Array;
643    use arrow_array::Int64Array;
644    use arrow_array::LargeBinaryArray;
645    use arrow_array::LargeStringArray;
646    use arrow_array::NullArray;
647    use arrow_array::RecordBatch;
648    use arrow_array::StringArray;
649    use arrow_array::StructArray;
650    use arrow_array::Time32MillisecondArray;
651    use arrow_array::Time32SecondArray;
652    use arrow_array::Time64MicrosecondArray;
653    use arrow_array::Time64NanosecondArray;
654    use arrow_array::TimestampMicrosecondArray;
655    use arrow_array::TimestampMillisecondArray;
656    use arrow_array::TimestampNanosecondArray;
657    use arrow_array::TimestampSecondArray;
658    use arrow_array::UInt8Array;
659    use arrow_array::UInt16Array;
660    use arrow_array::UInt32Array;
661    use arrow_array::UInt64Array;
662    use arrow_array::builder::BinaryViewBuilder;
663    use arrow_array::builder::Decimal128Builder;
664    use arrow_array::builder::Decimal256Builder;
665    use arrow_array::builder::Int32Builder;
666    use arrow_array::builder::LargeListBuilder;
667    use arrow_array::builder::ListBuilder;
668    use arrow_array::builder::StringViewBuilder;
669    use arrow_array::new_null_array;
670    use arrow_array::types::ArrowPrimitiveType;
671    use arrow_array::types::Float16Type;
672    use arrow_buffer::BooleanBuffer;
673    use arrow_buffer::Buffer as ArrowBuffer;
674    use arrow_buffer::OffsetBuffer;
675    use arrow_buffer::ScalarBuffer;
676    use arrow_schema::DataType;
677    use arrow_schema::Field;
678    use arrow_schema::Fields;
679    use arrow_schema::Schema;
680    use vortex_dtype::DType;
681    use vortex_dtype::Nullability;
682    use vortex_dtype::PType;
683    use vortex_dtype::datetime::TimeUnit;
684    use vortex_dtype::datetime::Timestamp;
685
686    use crate::ArrayRef;
687    use crate::IntoArray;
688    use crate::arrays::DecimalVTable;
689    use crate::arrays::FixedSizeListVTable;
690    use crate::arrays::ListVTable;
691    use crate::arrays::ListViewVTable;
692    use crate::arrays::PrimitiveVTable;
693    use crate::arrays::StructVTable;
694    use crate::arrays::TemporalArray;
695    use crate::arrays::VarBinVTable;
696    use crate::arrays::VarBinViewVTable;
697    use crate::arrow::FromArrowArray as _;
698
699    // Test primitive array conversions
700    #[test]
701    fn test_int8_array_conversion() {
702        let arrow_array = Int8Array::from(vec![Some(1), None, Some(3), Some(4)]);
703        let vortex_array = ArrayRef::from_arrow(&arrow_array, true).unwrap();
704
705        let arrow_array_non_null = Int8Array::from(vec![1, 2, 3, 4]);
706        let vortex_array_non_null = ArrayRef::from_arrow(&arrow_array_non_null, false).unwrap();
707
708        assert_eq!(vortex_array.len(), 4);
709        assert_eq!(vortex_array_non_null.len(), 4);
710
711        // Verify metadata - should be PrimitiveArray with I8 ptype
712        let primitive_array = vortex_array.as_::<PrimitiveVTable>();
713        assert_eq!(primitive_array.ptype(), PType::I8);
714
715        let primitive_array_non_null = vortex_array_non_null.as_::<PrimitiveVTable>();
716        assert_eq!(primitive_array_non_null.ptype(), PType::I8);
717    }
718
719    #[test]
720    fn test_int16_array_conversion() {
721        let arrow_array = Int16Array::from(vec![Some(100), None, Some(300), Some(400)]);
722        let vortex_array = ArrayRef::from_arrow(&arrow_array, true).unwrap();
723
724        let arrow_array_non_null = Int16Array::from(vec![100, 200, 300, 400]);
725        let vortex_array_non_null = ArrayRef::from_arrow(&arrow_array_non_null, false).unwrap();
726
727        assert_eq!(vortex_array.len(), 4);
728        assert_eq!(vortex_array_non_null.len(), 4);
729
730        // Verify metadata - should be PrimitiveArray with I16 ptype
731        let primitive_array = vortex_array.as_::<PrimitiveVTable>();
732        assert_eq!(primitive_array.ptype(), PType::I16);
733
734        let primitive_array_non_null = vortex_array_non_null.as_::<PrimitiveVTable>();
735        assert_eq!(primitive_array_non_null.ptype(), PType::I16);
736    }
737
738    #[test]
739    fn test_int32_array_conversion() {
740        let arrow_array = Int32Array::from(vec![Some(1000), None, Some(3000), Some(4000)]);
741        let vortex_array = ArrayRef::from_arrow(&arrow_array, true).unwrap();
742
743        let arrow_array_non_null = Int32Array::from(vec![1000, 2000, 3000, 4000]);
744        let vortex_array_non_null = ArrayRef::from_arrow(&arrow_array_non_null, false).unwrap();
745
746        assert_eq!(vortex_array.len(), 4);
747        assert_eq!(vortex_array_non_null.len(), 4);
748
749        // Verify metadata - should be PrimitiveArray with I32 ptype
750        let primitive_array = vortex_array.as_::<PrimitiveVTable>();
751        assert_eq!(primitive_array.ptype(), PType::I32);
752
753        let primitive_array_non_null = vortex_array_non_null.as_::<PrimitiveVTable>();
754        assert_eq!(primitive_array_non_null.ptype(), PType::I32);
755    }
756
757    #[test]
758    fn test_int64_array_conversion() {
759        let arrow_array = Int64Array::from(vec![Some(10000), None, Some(30000), Some(40000)]);
760        let vortex_array = ArrayRef::from_arrow(&arrow_array, true).unwrap();
761
762        let arrow_array_non_null = Int64Array::from(vec![10000_i64, 20000, 30000, 40000]);
763        let vortex_array_non_null = ArrayRef::from_arrow(&arrow_array_non_null, false).unwrap();
764
765        assert_eq!(vortex_array.len(), 4);
766        assert_eq!(vortex_array_non_null.len(), 4);
767
768        // Verify metadata - should be PrimitiveArray with I64 ptype
769        let primitive_array = vortex_array.as_::<PrimitiveVTable>();
770        assert_eq!(primitive_array.ptype(), PType::I64);
771
772        let primitive_array_non_null = vortex_array_non_null.as_::<PrimitiveVTable>();
773        assert_eq!(primitive_array_non_null.ptype(), PType::I64);
774    }
775
776    #[test]
777    fn test_uint8_array_conversion() {
778        let arrow_array = UInt8Array::from(vec![Some(1), None, Some(3), Some(4)]);
779        let vortex_array = ArrayRef::from_arrow(&arrow_array, true).unwrap();
780
781        let arrow_array_non_null = UInt8Array::from(vec![1_u8, 2, 3, 4]);
782        let vortex_array_non_null = ArrayRef::from_arrow(&arrow_array_non_null, false).unwrap();
783
784        assert_eq!(vortex_array.len(), 4);
785        assert_eq!(vortex_array_non_null.len(), 4);
786
787        // Verify metadata - should be PrimitiveArray with U8 ptype
788        let primitive_array = vortex_array.as_::<PrimitiveVTable>();
789        assert_eq!(primitive_array.ptype(), PType::U8);
790
791        let primitive_array_non_null = vortex_array_non_null.as_::<PrimitiveVTable>();
792        assert_eq!(primitive_array_non_null.ptype(), PType::U8);
793    }
794
795    #[test]
796    fn test_uint16_array_conversion() {
797        let arrow_array = UInt16Array::from(vec![Some(100), None, Some(300), Some(400)]);
798        let vortex_array = ArrayRef::from_arrow(&arrow_array, true).unwrap();
799
800        let arrow_array_non_null = UInt16Array::from(vec![100_u16, 200, 300, 400]);
801        let vortex_array_non_null = ArrayRef::from_arrow(&arrow_array_non_null, false).unwrap();
802
803        assert_eq!(vortex_array.len(), 4);
804        assert_eq!(vortex_array_non_null.len(), 4);
805
806        // Verify metadata - should be PrimitiveArray with U16 ptype
807        let primitive_array = vortex_array.as_::<PrimitiveVTable>();
808        assert_eq!(primitive_array.ptype(), PType::U16);
809
810        let primitive_array_non_null = vortex_array_non_null.as_::<PrimitiveVTable>();
811        assert_eq!(primitive_array_non_null.ptype(), PType::U16);
812    }
813
814    #[test]
815    fn test_uint32_array_conversion() {
816        let arrow_array = UInt32Array::from(vec![Some(1000), None, Some(3000), Some(4000)]);
817        let vortex_array = ArrayRef::from_arrow(&arrow_array, true).unwrap();
818
819        let arrow_array_non_null = UInt32Array::from(vec![1000_u32, 2000, 3000, 4000]);
820        let vortex_array_non_null = ArrayRef::from_arrow(&arrow_array_non_null, false).unwrap();
821
822        assert_eq!(vortex_array.len(), 4);
823        assert_eq!(vortex_array_non_null.len(), 4);
824
825        // Verify metadata - should be PrimitiveArray with U32 ptype
826        let primitive_array = vortex_array.as_::<PrimitiveVTable>();
827        assert_eq!(primitive_array.ptype(), PType::U32);
828
829        let primitive_array_non_null = vortex_array_non_null.as_::<PrimitiveVTable>();
830        assert_eq!(primitive_array_non_null.ptype(), PType::U32);
831    }
832
833    #[test]
834    fn test_uint64_array_conversion() {
835        let arrow_array = UInt64Array::from(vec![Some(10000), None, Some(30000), Some(40000)]);
836        let vortex_array = ArrayRef::from_arrow(&arrow_array, true).unwrap();
837
838        let arrow_array_non_null = UInt64Array::from(vec![10000_u64, 20000, 30000, 40000]);
839        let vortex_array_non_null = ArrayRef::from_arrow(&arrow_array_non_null, false).unwrap();
840
841        assert_eq!(vortex_array.len(), 4);
842        assert_eq!(vortex_array_non_null.len(), 4);
843
844        // Verify metadata - should be PrimitiveArray with U64 ptype
845        let primitive_array = vortex_array.as_::<PrimitiveVTable>();
846        assert_eq!(primitive_array.ptype(), PType::U64);
847
848        let primitive_array_non_null = vortex_array_non_null.as_::<PrimitiveVTable>();
849        assert_eq!(primitive_array_non_null.ptype(), PType::U64);
850    }
851
852    #[test]
853    fn test_float16_array_conversion() {
854        let values = vec![
855            Some(<Float16Type as ArrowPrimitiveType>::Native::from_f32(1.5)),
856            None,
857            Some(<Float16Type as ArrowPrimitiveType>::Native::from_f32(3.5)),
858        ];
859        let arrow_array = arrow_array::PrimitiveArray::<Float16Type>::from(values);
860        let vortex_array = ArrayRef::from_arrow(&arrow_array, true).unwrap();
861
862        let non_null_values = vec![
863            <Float16Type as ArrowPrimitiveType>::Native::from_f32(1.5),
864            <Float16Type as ArrowPrimitiveType>::Native::from_f32(2.5),
865        ];
866        let arrow_array_non_null =
867            arrow_array::PrimitiveArray::<Float16Type>::from(non_null_values);
868        let vortex_array_non_null = ArrayRef::from_arrow(&arrow_array_non_null, false).unwrap();
869
870        assert_eq!(vortex_array.len(), 3);
871        assert_eq!(vortex_array_non_null.len(), 2);
872
873        // Verify metadata - should be PrimitiveArray with F16 ptype
874        let primitive_array = vortex_array.as_::<PrimitiveVTable>();
875        assert_eq!(primitive_array.ptype(), PType::F16);
876
877        let primitive_array_non_null = vortex_array_non_null.as_::<PrimitiveVTable>();
878        assert_eq!(primitive_array_non_null.ptype(), PType::F16);
879    }
880
881    #[test]
882    fn test_float32_array_conversion() {
883        let arrow_array = Float32Array::from(vec![Some(1.5), None, Some(3.5), Some(4.5)]);
884        let vortex_array = ArrayRef::from_arrow(&arrow_array, true).unwrap();
885
886        let arrow_array_non_null = Float32Array::from(vec![1.5_f32, 2.5, 3.5, 4.5]);
887        let vortex_array_non_null = ArrayRef::from_arrow(&arrow_array_non_null, false).unwrap();
888
889        assert_eq!(vortex_array.len(), 4);
890        assert_eq!(vortex_array_non_null.len(), 4);
891
892        // Verify metadata - should be PrimitiveArray with F32 ptype
893        let primitive_array = vortex_array.as_::<PrimitiveVTable>();
894        assert_eq!(primitive_array.ptype(), PType::F32);
895
896        let primitive_array_non_null = vortex_array_non_null.as_::<PrimitiveVTable>();
897        assert_eq!(primitive_array_non_null.ptype(), PType::F32);
898    }
899
900    #[test]
901    fn test_float64_array_conversion() {
902        let arrow_array = Float64Array::from(vec![Some(1.5), None, Some(3.5), Some(4.5)]);
903        let vortex_array = ArrayRef::from_arrow(&arrow_array, true).unwrap();
904
905        let arrow_array_non_null = Float64Array::from(vec![1.5_f64, 2.5, 3.5, 4.5]);
906        let vortex_array_non_null = ArrayRef::from_arrow(&arrow_array_non_null, false).unwrap();
907
908        assert_eq!(vortex_array.len(), 4);
909        assert_eq!(vortex_array_non_null.len(), 4);
910
911        // Verify metadata - should be PrimitiveArray with F64 ptype
912        let primitive_array = vortex_array.as_::<PrimitiveVTable>();
913        assert_eq!(primitive_array.ptype(), PType::F64);
914
915        let primitive_array_non_null = vortex_array_non_null.as_::<PrimitiveVTable>();
916        assert_eq!(primitive_array_non_null.ptype(), PType::F64);
917    }
918
919    // Test decimal array conversions
920    #[test]
921    fn test_decimal128_array_conversion() {
922        let mut builder = Decimal128Builder::with_capacity(4);
923        builder.append_value(12345);
924        builder.append_null();
925        builder.append_value(67890);
926        builder.append_value(11111);
927        let decimal_array = builder.finish().with_precision_and_scale(10, 2).unwrap();
928
929        let vortex_array = ArrayRef::from_arrow(&decimal_array, true).unwrap();
930        assert_eq!(vortex_array.len(), 4);
931
932        let mut builder_non_null = Decimal128Builder::with_capacity(3);
933        builder_non_null.append_value(12345);
934        builder_non_null.append_value(67890);
935        builder_non_null.append_value(11111);
936        let decimal_array_non_null = builder_non_null
937            .finish()
938            .with_precision_and_scale(10, 2)
939            .unwrap();
940
941        let vortex_array_non_null = ArrayRef::from_arrow(&decimal_array_non_null, false).unwrap();
942        assert_eq!(vortex_array_non_null.len(), 3);
943
944        // Verify metadata - should be DecimalArray with correct precision and scale
945        let decimal_vortex_array = vortex_array.as_::<DecimalVTable>();
946        assert_eq!(decimal_vortex_array.decimal_dtype().precision(), 10);
947        assert_eq!(decimal_vortex_array.decimal_dtype().scale(), 2);
948
949        let decimal_vortex_array_non_null = vortex_array_non_null.as_::<DecimalVTable>();
950        assert_eq!(
951            decimal_vortex_array_non_null.decimal_dtype().precision(),
952            10
953        );
954        assert_eq!(decimal_vortex_array_non_null.decimal_dtype().scale(), 2);
955    }
956
957    #[test]
958    fn test_decimal256_array_conversion() {
959        let mut builder = Decimal256Builder::with_capacity(4);
960        builder.append_value(arrow_buffer::i256::from_i128(12345));
961        builder.append_null();
962        builder.append_value(arrow_buffer::i256::from_i128(67890));
963        builder.append_value(arrow_buffer::i256::from_i128(11111));
964        let decimal_array = builder.finish().with_precision_and_scale(38, 10).unwrap();
965
966        let vortex_array = ArrayRef::from_arrow(&decimal_array, true).unwrap();
967        assert_eq!(vortex_array.len(), 4);
968
969        let mut builder_non_null = Decimal256Builder::with_capacity(3);
970        builder_non_null.append_value(arrow_buffer::i256::from_i128(12345));
971        builder_non_null.append_value(arrow_buffer::i256::from_i128(67890));
972        builder_non_null.append_value(arrow_buffer::i256::from_i128(11111));
973        let decimal_array_non_null = builder_non_null
974            .finish()
975            .with_precision_and_scale(38, 10)
976            .unwrap();
977
978        let vortex_array_non_null = ArrayRef::from_arrow(&decimal_array_non_null, false).unwrap();
979        assert_eq!(vortex_array_non_null.len(), 3);
980
981        // Verify metadata - should be DecimalArray with correct precision and scale
982        let decimal_vortex_array = vortex_array.as_::<DecimalVTable>();
983        assert_eq!(decimal_vortex_array.decimal_dtype().precision(), 38);
984        assert_eq!(decimal_vortex_array.decimal_dtype().scale(), 10);
985
986        let decimal_vortex_array_non_null = vortex_array_non_null.as_::<DecimalVTable>();
987        assert_eq!(
988            decimal_vortex_array_non_null.decimal_dtype().precision(),
989            38
990        );
991        assert_eq!(decimal_vortex_array_non_null.decimal_dtype().scale(), 10);
992    }
993
994    // Test temporal array conversions
995    #[test]
996    fn test_timestamp_second_array_conversion() {
997        let arrow_array =
998            TimestampSecondArray::from(vec![Some(1000), None, Some(3000), Some(4000)]);
999        let vortex_array = ArrayRef::from_arrow(&arrow_array, true).unwrap();
1000
1001        let arrow_array_non_null = TimestampSecondArray::from(vec![1000_i64, 2000, 3000, 4000]);
1002        let vortex_array_non_null = ArrayRef::from_arrow(&arrow_array_non_null, false).unwrap();
1003
1004        assert_eq!(vortex_array.len(), 4);
1005        assert_eq!(vortex_array_non_null.len(), 4);
1006
1007        // Verify metadata - should be TemporalArray with Second time unit
1008        let temporal_array = TemporalArray::try_from(vortex_array.clone()).unwrap();
1009        assert_eq!(
1010            temporal_array.temporal_metadata().time_unit(),
1011            TimeUnit::Seconds
1012        );
1013
1014        let temporal_array_non_null =
1015            TemporalArray::try_from(vortex_array_non_null.clone()).unwrap();
1016        assert_eq!(
1017            temporal_array_non_null.temporal_metadata().time_unit(),
1018            TimeUnit::Seconds
1019        );
1020    }
1021
1022    #[test]
1023    fn test_timestamp_millisecond_array_conversion() {
1024        let arrow_array =
1025            TimestampMillisecondArray::from(vec![Some(1000), None, Some(3000), Some(4000)]);
1026        let vortex_array = ArrayRef::from_arrow(&arrow_array, true).unwrap();
1027
1028        let arrow_array_non_null =
1029            TimestampMillisecondArray::from(vec![1000_i64, 2000, 3000, 4000]);
1030        let vortex_array_non_null = ArrayRef::from_arrow(&arrow_array_non_null, false).unwrap();
1031
1032        assert_eq!(vortex_array.len(), 4);
1033        assert_eq!(vortex_array_non_null.len(), 4);
1034    }
1035
1036    #[test]
1037    fn test_timestamp_microsecond_array_conversion() {
1038        let arrow_array =
1039            TimestampMicrosecondArray::from(vec![Some(1000), None, Some(3000), Some(4000)]);
1040        let vortex_array = ArrayRef::from_arrow(&arrow_array, true).unwrap();
1041
1042        let arrow_array_non_null =
1043            TimestampMicrosecondArray::from(vec![1000_i64, 2000, 3000, 4000]);
1044        let vortex_array_non_null = ArrayRef::from_arrow(&arrow_array_non_null, false).unwrap();
1045
1046        assert_eq!(vortex_array.len(), 4);
1047        assert_eq!(vortex_array_non_null.len(), 4);
1048    }
1049
1050    #[test]
1051    fn test_timestamp_timezone_microsecond_array_conversion() {
1052        let arrow_array =
1053            TimestampMicrosecondArray::from(vec![Some(1000), None, Some(3000), Some(4000)])
1054                .with_timezone("UTC");
1055        let vortex_array = ArrayRef::from_arrow(&arrow_array, true).unwrap();
1056
1057        let arrow_array_non_null =
1058            TimestampMicrosecondArray::from(vec![1000_i64, 2000, 3000, 4000]).with_timezone("UTC");
1059        let vortex_array_non_null = ArrayRef::from_arrow(&arrow_array_non_null, false).unwrap();
1060
1061        assert_eq!(vortex_array.len(), 4);
1062        assert_eq!(
1063            vortex_array.dtype(),
1064            &DType::Extension(
1065                Timestamp::new_with_tz(
1066                    TimeUnit::Microseconds,
1067                    Some("UTC".into()),
1068                    Nullability::Nullable
1069                )
1070                .erased()
1071            ),
1072        );
1073        assert_eq!(vortex_array_non_null.len(), 4);
1074        assert_eq!(
1075            vortex_array_non_null.dtype(),
1076            &DType::Extension(
1077                Timestamp::new_with_tz(
1078                    TimeUnit::Microseconds,
1079                    Some("UTC".into()),
1080                    Nullability::NonNullable
1081                )
1082                .erased()
1083            )
1084        );
1085    }
1086
1087    #[test]
1088    fn test_timestamp_nanosecond_array_conversion() {
1089        let arrow_array =
1090            TimestampNanosecondArray::from(vec![Some(1000), None, Some(3000), Some(4000)]);
1091        let vortex_array = ArrayRef::from_arrow(&arrow_array, true).unwrap();
1092
1093        let arrow_array_non_null = TimestampNanosecondArray::from(vec![1000_i64, 2000, 3000, 4000]);
1094        let vortex_array_non_null = ArrayRef::from_arrow(&arrow_array_non_null, false).unwrap();
1095
1096        assert_eq!(vortex_array.len(), 4);
1097        assert_eq!(vortex_array_non_null.len(), 4);
1098    }
1099
1100    #[test]
1101    fn test_time32_second_array_conversion() {
1102        let arrow_array = Time32SecondArray::from(vec![Some(1000), None, Some(3000), Some(4000)]);
1103        let vortex_array = ArrayRef::from_arrow(&arrow_array, true).unwrap();
1104
1105        let arrow_array_non_null = Time32SecondArray::from(vec![1000_i32, 2000, 3000, 4000]);
1106        let vortex_array_non_null = ArrayRef::from_arrow(&arrow_array_non_null, false).unwrap();
1107
1108        assert_eq!(vortex_array.len(), 4);
1109        assert_eq!(vortex_array_non_null.len(), 4);
1110
1111        // Verify metadata - should be TemporalArray with Second time unit
1112        let temporal_array = TemporalArray::try_from(vortex_array.clone()).unwrap();
1113        assert_eq!(
1114            temporal_array.temporal_metadata().time_unit(),
1115            TimeUnit::Seconds
1116        );
1117
1118        let temporal_array_non_null =
1119            TemporalArray::try_from(vortex_array_non_null.clone()).unwrap();
1120        assert_eq!(
1121            temporal_array_non_null.temporal_metadata().time_unit(),
1122            TimeUnit::Seconds
1123        );
1124    }
1125
1126    #[test]
1127    fn test_time32_millisecond_array_conversion() {
1128        let arrow_array =
1129            Time32MillisecondArray::from(vec![Some(1000), None, Some(3000), Some(4000)]);
1130        let vortex_array = ArrayRef::from_arrow(&arrow_array, true).unwrap();
1131
1132        let arrow_array_non_null = Time32MillisecondArray::from(vec![1000_i32, 2000, 3000, 4000]);
1133        let vortex_array_non_null = ArrayRef::from_arrow(&arrow_array_non_null, false).unwrap();
1134
1135        assert_eq!(vortex_array.len(), 4);
1136        assert_eq!(vortex_array_non_null.len(), 4);
1137    }
1138
1139    #[test]
1140    fn test_time64_microsecond_array_conversion() {
1141        let arrow_array =
1142            Time64MicrosecondArray::from(vec![Some(1000), None, Some(3000), Some(4000)]);
1143        let vortex_array = ArrayRef::from_arrow(&arrow_array, true).unwrap();
1144
1145        let arrow_array_non_null = Time64MicrosecondArray::from(vec![1000_i64, 2000, 3000, 4000]);
1146        let vortex_array_non_null = ArrayRef::from_arrow(&arrow_array_non_null, false).unwrap();
1147
1148        assert_eq!(vortex_array.len(), 4);
1149        assert_eq!(vortex_array_non_null.len(), 4);
1150    }
1151
1152    #[test]
1153    fn test_time64_nanosecond_array_conversion() {
1154        let arrow_array =
1155            Time64NanosecondArray::from(vec![Some(1000), None, Some(3000), Some(4000)]);
1156        let vortex_array = ArrayRef::from_arrow(&arrow_array, true).unwrap();
1157
1158        let arrow_array_non_null = Time64NanosecondArray::from(vec![1000_i64, 2000, 3000, 4000]);
1159        let vortex_array_non_null = ArrayRef::from_arrow(&arrow_array_non_null, false).unwrap();
1160
1161        assert_eq!(vortex_array.len(), 4);
1162        assert_eq!(vortex_array_non_null.len(), 4);
1163    }
1164
1165    #[test]
1166    fn test_date32_array_conversion() {
1167        let arrow_array = Date32Array::from(vec![Some(18000), None, Some(18002), Some(18003)]);
1168        let vortex_array = ArrayRef::from_arrow(&arrow_array, true).unwrap();
1169
1170        let arrow_array_non_null = Date32Array::from(vec![18000_i32, 18001, 18002, 18003]);
1171        let vortex_array_non_null = ArrayRef::from_arrow(&arrow_array_non_null, false).unwrap();
1172
1173        assert_eq!(vortex_array.len(), 4);
1174        assert_eq!(vortex_array_non_null.len(), 4);
1175    }
1176
1177    #[test]
1178    fn test_date64_array_conversion() {
1179        let arrow_array = Date64Array::from(vec![
1180            Some(1555200000000),
1181            None,
1182            Some(1555286400000),
1183            Some(1555372800000),
1184        ]);
1185        let vortex_array = ArrayRef::from_arrow(&arrow_array, true).unwrap();
1186
1187        let arrow_array_non_null = Date64Array::from(vec![
1188            1555200000000_i64,
1189            1555213600000,
1190            1555286400000,
1191            1555372800000,
1192        ]);
1193        let vortex_array_non_null = ArrayRef::from_arrow(&arrow_array_non_null, false).unwrap();
1194
1195        assert_eq!(vortex_array.len(), 4);
1196        assert_eq!(vortex_array_non_null.len(), 4);
1197    }
1198
1199    // Test string/binary array conversions
1200    #[test]
1201    fn test_utf8_array_conversion() {
1202        let arrow_array = StringArray::from(vec![Some("hello"), None, Some("world"), Some("test")]);
1203        let vortex_array = ArrayRef::from_arrow(&arrow_array, true).unwrap();
1204
1205        let arrow_array_non_null = StringArray::from(vec!["hello", "world", "test", "vortex"]);
1206        let vortex_array_non_null = ArrayRef::from_arrow(&arrow_array_non_null, false).unwrap();
1207
1208        assert_eq!(vortex_array.len(), 4);
1209        assert_eq!(vortex_array_non_null.len(), 4);
1210
1211        // Verify metadata - should be VarBinArray with Utf8 dtype
1212        let varbin_array = vortex_array.as_::<VarBinVTable>();
1213        assert_eq!(varbin_array.dtype(), &DType::Utf8(true.into()));
1214
1215        let varbin_array_non_null = vortex_array_non_null.as_::<VarBinVTable>();
1216        assert_eq!(varbin_array_non_null.dtype(), &DType::Utf8(false.into()));
1217    }
1218
1219    #[test]
1220    fn test_large_utf8_array_conversion() {
1221        let arrow_array =
1222            LargeStringArray::from(vec![Some("hello"), None, Some("world"), Some("test")]);
1223        let vortex_array = ArrayRef::from_arrow(&arrow_array, true).unwrap();
1224
1225        let arrow_array_non_null = LargeStringArray::from(vec!["hello", "world", "test", "vortex"]);
1226        let vortex_array_non_null = ArrayRef::from_arrow(&arrow_array_non_null, false).unwrap();
1227
1228        assert_eq!(vortex_array.len(), 4);
1229        assert_eq!(vortex_array_non_null.len(), 4);
1230    }
1231
1232    #[test]
1233    fn test_binary_array_conversion() {
1234        let arrow_array = BinaryArray::from(vec![
1235            Some("hello".as_bytes()),
1236            None,
1237            Some("world".as_bytes()),
1238            Some("test".as_bytes()),
1239        ]);
1240        let vortex_array = ArrayRef::from_arrow(&arrow_array, true).unwrap();
1241
1242        let arrow_array_non_null = BinaryArray::from(vec![
1243            "hello".as_bytes(),
1244            "world".as_bytes(),
1245            "test".as_bytes(),
1246            "vortex".as_bytes(),
1247        ]);
1248        let vortex_array_non_null = ArrayRef::from_arrow(&arrow_array_non_null, false).unwrap();
1249
1250        assert_eq!(vortex_array.len(), 4);
1251        assert_eq!(vortex_array_non_null.len(), 4);
1252    }
1253
1254    #[test]
1255    fn test_large_binary_array_conversion() {
1256        let arrow_array = LargeBinaryArray::from(vec![
1257            Some("hello".as_bytes()),
1258            None,
1259            Some("world".as_bytes()),
1260            Some("test".as_bytes()),
1261        ]);
1262        let vortex_array = ArrayRef::from_arrow(&arrow_array, true).unwrap();
1263
1264        let arrow_array_non_null = LargeBinaryArray::from(vec![
1265            "hello".as_bytes(),
1266            "world".as_bytes(),
1267            "test".as_bytes(),
1268            "vortex".as_bytes(),
1269        ]);
1270        let vortex_array_non_null = ArrayRef::from_arrow(&arrow_array_non_null, false).unwrap();
1271
1272        assert_eq!(vortex_array.len(), 4);
1273        assert_eq!(vortex_array_non_null.len(), 4);
1274    }
1275
1276    #[test]
1277    fn test_utf8_view_array_conversion() {
1278        let mut builder = StringViewBuilder::new();
1279        builder.append_value("hello");
1280        builder.append_null();
1281        builder.append_value("world");
1282        builder.append_value("test");
1283        let arrow_array = builder.finish();
1284        let vortex_array = ArrayRef::from_arrow(&arrow_array, true).unwrap();
1285
1286        let mut builder_non_null = StringViewBuilder::new();
1287        builder_non_null.append_value("hello");
1288        builder_non_null.append_value("world");
1289        builder_non_null.append_value("test");
1290        builder_non_null.append_value("vortex");
1291        let arrow_array_non_null = builder_non_null.finish();
1292        let vortex_array_non_null = ArrayRef::from_arrow(&arrow_array_non_null, false).unwrap();
1293
1294        assert_eq!(vortex_array.len(), 4);
1295        assert_eq!(vortex_array_non_null.len(), 4);
1296
1297        // Verify metadata - should be VarBinViewArray with correct buffer count and dtype
1298        let varbin_view_array = vortex_array.as_::<VarBinViewVTable>();
1299        assert_eq!(
1300            varbin_view_array.buffers().len(),
1301            arrow_array.data_buffers().len()
1302        );
1303        assert_eq!(varbin_view_array.dtype(), &DType::Utf8(true.into()));
1304
1305        let varbin_view_array_non_null = vortex_array_non_null.as_::<VarBinViewVTable>();
1306        assert_eq!(
1307            varbin_view_array_non_null.buffers().len(),
1308            arrow_array_non_null.data_buffers().len()
1309        );
1310        assert_eq!(
1311            varbin_view_array_non_null.dtype(),
1312            &DType::Utf8(false.into())
1313        );
1314    }
1315
1316    #[test]
1317    fn test_binary_view_array_conversion() {
1318        let mut builder = BinaryViewBuilder::new();
1319        builder.append_value(b"hello");
1320        builder.append_null();
1321        builder.append_value(b"world");
1322        builder.append_value(b"test");
1323        let arrow_array = builder.finish();
1324        let vortex_array = ArrayRef::from_arrow(&arrow_array, true).unwrap();
1325
1326        let mut builder_non_null = BinaryViewBuilder::new();
1327        builder_non_null.append_value(b"hello");
1328        builder_non_null.append_value(b"world");
1329        builder_non_null.append_value(b"test");
1330        builder_non_null.append_value(b"vortex");
1331        let arrow_array_non_null = builder_non_null.finish();
1332        let vortex_array_non_null = ArrayRef::from_arrow(&arrow_array_non_null, false).unwrap();
1333
1334        assert_eq!(vortex_array.len(), 4);
1335        assert_eq!(vortex_array_non_null.len(), 4);
1336
1337        // Verify metadata - should be VarBinViewArray with correct buffer count and dtype
1338        let varbin_view_array = vortex_array.as_::<VarBinViewVTable>();
1339        assert_eq!(
1340            varbin_view_array.buffers().len(),
1341            arrow_array.data_buffers().len()
1342        );
1343        assert_eq!(varbin_view_array.dtype(), &DType::Binary(true.into()));
1344
1345        let varbin_view_array_non_null = vortex_array_non_null.as_::<VarBinViewVTable>();
1346        assert_eq!(
1347            varbin_view_array_non_null.buffers().len(),
1348            arrow_array_non_null.data_buffers().len()
1349        );
1350        assert_eq!(
1351            varbin_view_array_non_null.dtype(),
1352            &DType::Binary(false.into())
1353        );
1354    }
1355
1356    // Test boolean array conversions
1357    #[test]
1358    fn test_boolean_array_conversion() {
1359        let arrow_array = BooleanArray::from(vec![Some(true), None, Some(false), Some(true)]);
1360        let vortex_array = ArrayRef::from_arrow(&arrow_array, true).unwrap();
1361
1362        let arrow_array_non_null = BooleanArray::from(vec![true, false, true, false]);
1363        let vortex_array_non_null = ArrayRef::from_arrow(&arrow_array_non_null, false).unwrap();
1364
1365        assert_eq!(vortex_array.len(), 4);
1366        assert_eq!(vortex_array_non_null.len(), 4);
1367    }
1368
1369    // Test struct array conversions
1370    #[test]
1371    fn test_struct_array_conversion() {
1372        let fields = vec![
1373            Field::new("field1", DataType::Int32, true),
1374            Field::new("field2", DataType::Utf8, false),
1375        ];
1376        let schema = Fields::from(fields);
1377
1378        let field1_data = Int32Array::from(vec![Some(1), None, Some(3)]);
1379        let field2_data = StringArray::from(vec!["a", "b", "c"]);
1380
1381        let arrow_array = StructArray::new(
1382            schema.clone(),
1383            vec![Arc::new(field1_data), Arc::new(field2_data)],
1384            None,
1385        );
1386
1387        let vortex_array = ArrayRef::from_arrow(&arrow_array, false).unwrap();
1388        assert_eq!(vortex_array.len(), 3);
1389
1390        // Verify metadata - should be StructArray with correct field names
1391        let struct_vortex_array = vortex_array.as_::<StructVTable>();
1392        assert_eq!(struct_vortex_array.names().len(), 2);
1393        assert_eq!(struct_vortex_array.names()[0], "field1");
1394        assert_eq!(struct_vortex_array.names()[1], "field2");
1395
1396        // Test nullable struct
1397        let nullable_array = StructArray::new(
1398            schema,
1399            vec![
1400                Arc::new(Int32Array::from(vec![Some(1), None, Some(3)])),
1401                Arc::new(StringArray::from(vec!["a", "b", "c"])),
1402            ],
1403            Some(arrow_buffer::NullBuffer::new(BooleanBuffer::from(vec![
1404                true, false, true,
1405            ]))),
1406        );
1407
1408        let vortex_nullable_array = ArrayRef::from_arrow(&nullable_array, true).unwrap();
1409        assert_eq!(vortex_nullable_array.len(), 3);
1410
1411        // Verify metadata for nullable struct
1412        let struct_vortex_nullable_array = vortex_nullable_array.as_::<StructVTable>();
1413        assert_eq!(struct_vortex_nullable_array.names().len(), 2);
1414        assert_eq!(struct_vortex_nullable_array.names()[0], "field1");
1415        assert_eq!(struct_vortex_nullable_array.names()[1], "field2");
1416    }
1417
1418    // Test list array conversions
1419    #[test]
1420    fn test_list_array_conversion() {
1421        let mut builder = ListBuilder::new(Int32Builder::new());
1422        builder.append_value([Some(1), None, Some(3)]);
1423        builder.append_null();
1424        builder.append_value([Some(4), Some(5)]);
1425        let arrow_array = builder.finish();
1426
1427        let vortex_array = ArrayRef::from_arrow(&arrow_array, true).unwrap();
1428        assert_eq!(vortex_array.len(), 3);
1429
1430        // Verify metadata - should be ListArray with correct offsets
1431        let list_vortex_array = vortex_array.as_::<ListVTable>();
1432        let offsets_array = list_vortex_array.offsets().as_::<PrimitiveVTable>();
1433        assert_eq!(offsets_array.len(), 4); // n+1 offsets for n lists
1434        assert_eq!(offsets_array.ptype(), PType::I32);
1435
1436        // Test non-nullable list
1437        let mut builder_non_null = ListBuilder::new(Int32Builder::new());
1438        builder_non_null.append_value([Some(1), None, Some(3)]);
1439        builder_non_null.append_value([Some(4), Some(5)]);
1440        let arrow_array_non_null = builder_non_null.finish();
1441
1442        let vortex_array_non_null = ArrayRef::from_arrow(&arrow_array_non_null, false).unwrap();
1443        assert_eq!(vortex_array_non_null.len(), 2);
1444
1445        // Verify metadata for non-nullable list
1446        let list_vortex_array_non_null = vortex_array_non_null.as_::<ListVTable>();
1447        let offsets_array_non_null = list_vortex_array_non_null
1448            .offsets()
1449            .as_::<PrimitiveVTable>();
1450        assert_eq!(offsets_array_non_null.len(), 3); // n+1 offsets for n lists
1451        assert_eq!(offsets_array_non_null.ptype(), PType::I32);
1452    }
1453
1454    #[test]
1455    fn test_large_list_array_conversion() {
1456        let mut builder = LargeListBuilder::new(Int32Builder::new());
1457        builder.append_value([Some(1), None, Some(3)]);
1458        builder.append_null();
1459        builder.append_value([Some(4), Some(5)]);
1460        let arrow_array = builder.finish();
1461
1462        let vortex_array = ArrayRef::from_arrow(&arrow_array, true).unwrap();
1463        assert_eq!(vortex_array.len(), 3);
1464
1465        // Verify metadata - should be ListArray with correct offsets (I64 for large lists)
1466        let list_vortex_array = vortex_array.as_::<ListVTable>();
1467        let offsets_array = list_vortex_array.offsets().as_::<PrimitiveVTable>();
1468        assert_eq!(offsets_array.len(), 4); // n+1 offsets for n lists
1469        assert_eq!(offsets_array.ptype(), PType::I64); // Large lists use I64 offsets
1470
1471        // Test non-nullable large list
1472        let mut builder_non_null = LargeListBuilder::new(Int32Builder::new());
1473        builder_non_null.append_value([Some(1), None, Some(3)]);
1474        builder_non_null.append_value([Some(4), Some(5)]);
1475        let arrow_array_non_null = builder_non_null.finish();
1476
1477        let vortex_array_non_null = ArrayRef::from_arrow(&arrow_array_non_null, false).unwrap();
1478        assert_eq!(vortex_array_non_null.len(), 2);
1479
1480        // Verify metadata for non-nullable large list
1481        let list_vortex_array_non_null = vortex_array_non_null.as_::<ListVTable>();
1482        let offsets_array_non_null = list_vortex_array_non_null
1483            .offsets()
1484            .as_::<PrimitiveVTable>();
1485        assert_eq!(offsets_array_non_null.len(), 3); // n+1 offsets for n lists
1486        assert_eq!(offsets_array_non_null.ptype(), PType::I64); // Large lists use I64 offsets
1487    }
1488
1489    #[test]
1490    fn test_fixed_size_list_array_conversion() {
1491        // Create elements for the fixed-size lists
1492        let values = Int32Array::from(vec![
1493            Some(1),
1494            Some(2),
1495            Some(3), // First list
1496            Some(4),
1497            None,
1498            Some(6), // Second list (with null element)
1499            Some(7),
1500            Some(8),
1501            Some(9), // Third list
1502            Some(10),
1503            Some(11),
1504            Some(12), // Fourth list
1505        ]);
1506
1507        // Create a FixedSizeListArray with list_size=3
1508        let field = Arc::new(Field::new("item", DataType::Int32, true));
1509        let arrow_array =
1510            ArrowFixedSizeListArray::try_new(field.clone(), 3, Arc::new(values), None).unwrap();
1511        let vortex_array = ArrayRef::from_arrow(&arrow_array, false).unwrap();
1512
1513        assert_eq!(vortex_array.len(), 4);
1514
1515        // Verify metadata - should be FixedSizeListArray with correct list size
1516        let fsl_vortex_array = vortex_array.as_::<FixedSizeListVTable>();
1517        assert_eq!(fsl_vortex_array.list_size(), 3);
1518        assert_eq!(fsl_vortex_array.elements().len(), 12); // 4 lists * 3 elements
1519
1520        // Test nullable fixed-size list
1521        let values_nullable = Int32Array::from(vec![
1522            Some(1),
1523            Some(2),
1524            Some(3), // First list
1525            Some(4),
1526            None,
1527            Some(6), // Second list (will be null)
1528            Some(7),
1529            Some(8),
1530            Some(9), // Third list
1531        ]);
1532
1533        // Create nulls buffer - second list is null
1534        let null_buffer =
1535            arrow_buffer::NullBuffer::new(BooleanBuffer::from(vec![true, false, true]));
1536
1537        let arrow_array_nullable = ArrowFixedSizeListArray::try_new(
1538            field,
1539            3,
1540            Arc::new(values_nullable),
1541            Some(null_buffer),
1542        )
1543        .unwrap();
1544        let vortex_array_nullable = ArrayRef::from_arrow(&arrow_array_nullable, true).unwrap();
1545
1546        assert_eq!(vortex_array_nullable.len(), 3);
1547
1548        // Verify metadata for nullable array
1549        let fsl_vortex_array_nullable = vortex_array_nullable.as_::<FixedSizeListVTable>();
1550        assert_eq!(fsl_vortex_array_nullable.list_size(), 3);
1551        assert_eq!(fsl_vortex_array_nullable.elements().len(), 9); // 3 lists * 3 elements
1552    }
1553
1554    #[test]
1555    fn test_list_view_array_conversion() {
1556        // Create values array for the lists
1557        let values = Int32Array::from(vec![
1558            Some(1),
1559            Some(2),
1560            Some(3), // First list [1, 2, 3]
1561            Some(4),
1562            Some(5), // Second list [4, 5]
1563            Some(6), // Third list [6]
1564            Some(7),
1565            Some(8),
1566            Some(9),
1567            Some(10), // Fourth list [7, 8, 9, 10]
1568        ]);
1569
1570        // Create offsets and sizes for ListView
1571        let offsets = ScalarBuffer::from(vec![0i32, 3, 5, 6]);
1572        let sizes = ScalarBuffer::from(vec![3i32, 2, 1, 4]);
1573
1574        let field = Arc::new(Field::new("item", DataType::Int32, true));
1575        let arrow_array = GenericListViewArray::try_new(
1576            field.clone(),
1577            offsets.clone(),
1578            sizes.clone(),
1579            Arc::new(values.clone()),
1580            None,
1581        )
1582        .unwrap();
1583
1584        let vortex_array = ArrayRef::from_arrow(&arrow_array, false).unwrap();
1585        assert_eq!(vortex_array.len(), 4);
1586
1587        // Verify metadata - should be ListViewArray with correct offsets and sizes
1588        let list_view_vortex_array = vortex_array.as_::<ListViewVTable>();
1589        let offsets_array = list_view_vortex_array.offsets().as_::<PrimitiveVTable>();
1590        let sizes_array = list_view_vortex_array.sizes().as_::<PrimitiveVTable>();
1591
1592        assert_eq!(offsets_array.len(), 4);
1593        assert_eq!(offsets_array.ptype(), PType::I32);
1594        assert_eq!(sizes_array.len(), 4);
1595        assert_eq!(sizes_array.ptype(), PType::I32);
1596
1597        // Test nullable ListView
1598        let null_buffer =
1599            arrow_buffer::NullBuffer::new(BooleanBuffer::from(vec![true, false, true, true]));
1600
1601        let arrow_array_nullable = GenericListViewArray::try_new(
1602            field.clone(),
1603            offsets,
1604            sizes,
1605            Arc::new(values.clone()),
1606            Some(null_buffer),
1607        )
1608        .unwrap();
1609
1610        let vortex_array_nullable = ArrayRef::from_arrow(&arrow_array_nullable, true).unwrap();
1611        assert_eq!(vortex_array_nullable.len(), 4);
1612
1613        // Test LargeListView (i64 offsets and sizes)
1614        let large_offsets = ScalarBuffer::from(vec![0i64, 3, 5, 6]);
1615        let large_sizes = ScalarBuffer::from(vec![3i64, 2, 1, 4]);
1616
1617        let large_arrow_array = GenericListViewArray::try_new(
1618            field,
1619            large_offsets,
1620            large_sizes,
1621            Arc::new(values),
1622            None,
1623        )
1624        .unwrap();
1625
1626        let large_vortex_array = ArrayRef::from_arrow(&large_arrow_array, false).unwrap();
1627        assert_eq!(large_vortex_array.len(), 4);
1628
1629        // Verify metadata for large ListView
1630        let large_list_view_vortex_array = large_vortex_array.as_::<ListViewVTable>();
1631        let large_offsets_array = large_list_view_vortex_array
1632            .offsets()
1633            .as_::<PrimitiveVTable>();
1634        let large_sizes_array = large_list_view_vortex_array
1635            .sizes()
1636            .as_::<PrimitiveVTable>();
1637
1638        assert_eq!(large_offsets_array.len(), 4);
1639        assert_eq!(large_offsets_array.ptype(), PType::I64); // Large ListView uses I64 offsets
1640        assert_eq!(large_sizes_array.len(), 4);
1641        assert_eq!(large_sizes_array.ptype(), PType::I64); // Large ListView uses I64 sizes
1642    }
1643
1644    // Test null array conversions
1645    #[test]
1646    fn test_null_array_conversion() {
1647        let arrow_array = NullArray::new(5);
1648        let vortex_array = ArrayRef::from_arrow(&arrow_array, true).unwrap();
1649        assert_eq!(vortex_array.len(), 5);
1650    }
1651
1652    // Test buffer conversions
1653    #[test]
1654    fn test_arrow_buffer_conversion() {
1655        let data = vec![1u8, 2, 3, 4, 5];
1656        let arrow_buffer = ArrowBuffer::from_vec(data);
1657        let vortex_array = arrow_buffer.into_array();
1658        assert_eq!(vortex_array.len(), 5);
1659    }
1660
1661    #[test]
1662    fn test_boolean_buffer_conversion() {
1663        let data = vec![true, false, true, false, true];
1664        let boolean_buffer = BooleanBuffer::from(data);
1665        let vortex_array = boolean_buffer.into_array();
1666        assert_eq!(vortex_array.len(), 5);
1667    }
1668
1669    #[test]
1670    fn test_scalar_buffer_conversion() {
1671        let data = vec![1i32, 2, 3, 4, 5];
1672        let scalar_buffer = ScalarBuffer::from(data);
1673        let vortex_array = scalar_buffer.into_array();
1674        assert_eq!(vortex_array.len(), 5);
1675    }
1676
1677    #[test]
1678    fn test_offset_buffer_conversion() {
1679        let data = vec![0i32, 2, 5, 8, 10];
1680        let offset_buffer = OffsetBuffer::new(ScalarBuffer::from(data));
1681        let vortex_array = offset_buffer.into_array();
1682        assert_eq!(vortex_array.len(), 5);
1683    }
1684
1685    // Test RecordBatch conversions
1686    #[test]
1687    fn test_record_batch_conversion() {
1688        let schema = Arc::new(Schema::new(vec![
1689            Field::new("field1", DataType::Int32, false),
1690            Field::new("field2", DataType::Utf8, false),
1691        ]));
1692
1693        let field1_data = Arc::new(Int32Array::from(vec![1, 2, 3, 4]));
1694        let field2_data = Arc::new(StringArray::from(vec!["a", "b", "c", "d"]));
1695
1696        let record_batch = RecordBatch::try_new(schema, vec![field1_data, field2_data]).unwrap();
1697
1698        let vortex_array = ArrayRef::from_arrow(record_batch, false).unwrap();
1699        assert_eq!(vortex_array.len(), 4);
1700
1701        // Test with reference
1702        let schema = Arc::new(Schema::new(vec![
1703            Field::new("field1", DataType::Int32, false),
1704            Field::new("field2", DataType::Utf8, false),
1705        ]));
1706
1707        let field1_data = Arc::new(Int32Array::from(vec![1, 2, 3, 4]));
1708        let field2_data = Arc::new(StringArray::from(vec!["a", "b", "c", "d"]));
1709
1710        let record_batch = RecordBatch::try_new(schema, vec![field1_data, field2_data]).unwrap();
1711
1712        let vortex_array = ArrayRef::from_arrow(&record_batch, false).unwrap();
1713        assert_eq!(vortex_array.len(), 4);
1714    }
1715
1716    // Test dynamic dispatch conversion
1717    #[test]
1718    fn test_dyn_array_conversion() {
1719        let int_array = Int32Array::from(vec![1, 2, 3, 4]);
1720        let dyn_array: &dyn ArrowArray = &int_array;
1721        let vortex_array = ArrayRef::from_arrow(dyn_array, false).unwrap();
1722        assert_eq!(vortex_array.len(), 4);
1723
1724        let string_array = StringArray::from(vec!["a", "b", "c"]);
1725        let dyn_array: &dyn ArrowArray = &string_array;
1726        let vortex_array = ArrayRef::from_arrow(dyn_array, false).unwrap();
1727        assert_eq!(vortex_array.len(), 3);
1728
1729        let bool_array = BooleanArray::from(vec![true, false, true]);
1730        let dyn_array: &dyn ArrowArray = &bool_array;
1731        let vortex_array = ArrayRef::from_arrow(dyn_array, false).unwrap();
1732        assert_eq!(vortex_array.len(), 3);
1733    }
1734
1735    // Existing tests
1736    #[test]
1737    pub fn nullable_may_contain_non_nullable() {
1738        let null_struct_array_with_non_nullable_field = new_null_array(
1739            &DataType::Struct(Fields::from(vec![Field::new(
1740                "non_nullable_inner",
1741                DataType::Int32,
1742                false,
1743            )])),
1744            1,
1745        );
1746        ArrayRef::from_arrow(null_struct_array_with_non_nullable_field.as_ref(), true).unwrap();
1747    }
1748
1749    #[test]
1750    pub fn nullable_may_contain_deeply_nested_non_nullable() {
1751        let null_struct_array_with_non_nullable_field = new_null_array(
1752            &DataType::Struct(Fields::from(vec![Field::new(
1753                "non_nullable_inner",
1754                DataType::Struct(Fields::from(vec![Field::new(
1755                    "non_nullable_deeper_inner",
1756                    DataType::Int32,
1757                    false,
1758                )])),
1759                false,
1760            )])),
1761            1,
1762        );
1763        ArrayRef::from_arrow(null_struct_array_with_non_nullable_field.as_ref(), true).unwrap();
1764    }
1765
1766    #[test]
1767    #[should_panic]
1768    pub fn cannot_handle_nullable_struct_containing_non_nullable_dictionary() {
1769        let null_struct_array_with_non_nullable_field = new_null_array(
1770            &DataType::Struct(Fields::from(vec![Field::new(
1771                "non_nullable_deeper_inner",
1772                DataType::Dictionary(Box::new(DataType::Int32), Box::new(DataType::Utf8)),
1773                false,
1774            )])),
1775            1,
1776        );
1777
1778        ArrayRef::from_arrow(null_struct_array_with_non_nullable_field.as_ref(), true).unwrap();
1779    }
1780}