Skip to main content

parquet_variant_compute/
variant_to_arrow.rs

1// SPDX-License-Identifier: Apache-2.0
2// SPDX-FileCopyrightText: See the NOTICE file distributed with this work for additional information regarding copyright ownership
3// SPDX-FileContributor: Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements
4
5use crate::shred_variant::{
6    NullValue, VariantToShreddedVariantRowBuilder,
7    make_variant_to_shredded_variant_arrow_row_builder,
8};
9use crate::type_conversion::{
10    PrimitiveFromVariant, ShredDecimalVariant, TimestampFromVariant, VariantCastMode,
11    shred_variant_to_unscaled_decimal, variant_cast_with_options, variant_to_boolean,
12    variant_to_unscaled_decimal,
13};
14use crate::variant_array::ShreddedVariantFieldArray;
15use crate::{VariantArray, VariantValueArrayBuilder};
16use arrow::array::{
17    ArrayRef, ArrowNativeTypeOp, BinaryBuilder, BinaryLikeArrayBuilder, BinaryViewBuilder,
18    BooleanBuilder, FixedSizeBinaryBuilder, FixedSizeListArray, GenericListArray,
19    GenericListViewArray, LargeBinaryBuilder, LargeStringBuilder, MapArray, NullArray,
20    NullBufferBuilder, OffsetSizeTrait, PrimitiveBuilder, StringBuilder, StringLikeArrayBuilder,
21    StringViewBuilder, StructArray, UnionArray,
22};
23use arrow::buffer::{OffsetBuffer, ScalarBuffer};
24use arrow::compute::{CastOptions, DecimalCast, cast_with_options};
25use arrow::datatypes::{self, DataType, DecimalType};
26use arrow::error::{ArrowError, Result};
27use arrow_schema::{FieldRef, Fields, TimeUnit, UnionFields, UnionMode};
28use parquet_variant::{Variant, VariantPath};
29use std::sync::Arc;
30
31/// Builder for converting variant values into strongly typed Arrow arrays.
32///
33/// Useful for variant_get kernels that need to extract specific paths from variant values, possibly
34/// with casting of leaf values to specific types.
35pub(crate) enum VariantToArrowRowBuilder<'a> {
36    Primitive(PrimitiveVariantToArrowRowBuilder<'a>),
37    Array(ArrayVariantToArrowRowBuilder<'a>),
38    Struct(StructVariantToArrowRowBuilder<'a>),
39    Union(UnionVariantToArrowRowBuilder<'a>),
40    Map(MapVariantToArrowRowBuilder<'a>),
41    Encoded(EncodedVariantToArrowRowBuilder<'a>),
42    BinaryVariant(VariantToBinaryVariantArrowRowBuilder),
43
44    // Path extraction wrapper - contains a boxed enum for any of the above
45    WithPath(VariantPathRowBuilder<'a>),
46}
47
48impl VariantToArrowRowBuilder<'_> {
49    pub fn append_null(&mut self) -> Result<()> {
50        use VariantToArrowRowBuilder::*;
51        match self {
52            Primitive(b) => b.append_null(),
53            Array(b) => b.append_null(),
54            Struct(b) => b.append_null(),
55            Union(b) => b.append_null(),
56            Map(b) => b.append_null(),
57            Encoded(b) => b.append_null(),
58            BinaryVariant(b) => b.append_null(),
59            WithPath(path_builder) => path_builder.append_null(),
60        }
61    }
62
63    pub fn append_value(&mut self, value: Variant<'_, '_>) -> Result<bool> {
64        use VariantToArrowRowBuilder::*;
65        match self {
66            Primitive(b) => b.append_value(&value),
67            Array(b) => b.append_value(&value),
68            Struct(b) => b.append_value(&value),
69            Union(b) => b.append_value(&value),
70            Map(b) => b.append_value(&value),
71            Encoded(b) => b.append_value(value),
72            BinaryVariant(b) => b.append_value(value),
73            WithPath(path_builder) => path_builder.append_value(value),
74        }
75    }
76
77    pub fn finish(self) -> Result<ArrayRef> {
78        use VariantToArrowRowBuilder::*;
79        match self {
80            Primitive(b) => b.finish(),
81            Array(b) => b.finish(),
82            Struct(b) => b.finish(),
83            Union(b) => b.finish(),
84            Map(b) => b.finish(),
85            Encoded(b) => b.finish(),
86            BinaryVariant(b) => b.finish(),
87            WithPath(path_builder) => path_builder.finish(),
88        }
89    }
90}
91
92fn make_typed_variant_to_arrow_row_builder<'a>(
93    data_type: &'a DataType,
94    cast_options: &'a CastOptions,
95    capacity: usize,
96    cast_mode: VariantCastMode,
97) -> Result<VariantToArrowRowBuilder<'a>> {
98    use VariantToArrowRowBuilder::*;
99
100    match data_type {
101        DataType::Struct(fields) => {
102            let builder = StructVariantToArrowRowBuilder::try_new(fields, cast_options, capacity)?;
103            Ok(Struct(builder))
104        }
105        data_type @ (DataType::List(_)
106        | DataType::LargeList(_)
107        | DataType::ListView(_)
108        | DataType::LargeListView(_)
109        | DataType::FixedSizeList(..)) => {
110            let builder =
111                ArrayVariantToArrowRowBuilder::try_new(data_type, cast_options, capacity, false)?;
112            Ok(Array(builder))
113        }
114        DataType::Union(union_fields, mode) => {
115            let builder = UnionVariantToArrowRowBuilder::try_new(
116                union_fields,
117                *mode,
118                cast_options,
119                capacity,
120            )?;
121            Ok(Union(builder))
122        }
123        DataType::Map(entries_field, ordered) => {
124            let builder = MapVariantToArrowRowBuilder::try_new(
125                entries_field,
126                *ordered,
127                cast_options,
128                capacity,
129                cast_mode,
130            )?;
131            Ok(Map(builder))
132        }
133        DataType::Dictionary(_, value_type) => {
134            let builder = EncodedVariantToArrowRowBuilder::try_new(
135                data_type,
136                value_type.as_ref(),
137                cast_options,
138                capacity,
139            )?;
140            Ok(Encoded(builder))
141        }
142        DataType::RunEndEncoded(_, value_field) => {
143            let builder = EncodedVariantToArrowRowBuilder::try_new(
144                data_type,
145                value_field.data_type(),
146                cast_options,
147                capacity,
148            )?;
149            Ok(Encoded(builder))
150        }
151        data_type => {
152            let builder = make_primitive_variant_to_arrow_row_builder(
153                data_type,
154                cast_options,
155                capacity,
156                cast_mode,
157            )?;
158            Ok(Primitive(builder))
159        }
160    }
161}
162
163pub(crate) fn make_variant_to_arrow_row_builder<'a>(
164    metadata: &ArrayRef,
165    path: VariantPath<'a>,
166    data_type: Option<&'a DataType>,
167    cast_options: &'a CastOptions,
168    capacity: usize,
169) -> Result<VariantToArrowRowBuilder<'a>> {
170    use VariantToArrowRowBuilder::*;
171
172    let mut builder = match data_type {
173        // If no data type was requested, build an unshredded VariantArray.
174        None => BinaryVariant(VariantToBinaryVariantArrowRowBuilder::new(
175            metadata.clone(),
176            capacity,
177        )),
178        Some(data_type) => make_typed_variant_to_arrow_row_builder(
179            data_type,
180            cast_options,
181            capacity,
182            VariantCastMode::Get,
183        )?,
184    };
185
186    // Wrap with path extraction if needed
187    if !path.is_empty() {
188        builder = WithPath(VariantPathRowBuilder {
189            builder: Box::new(builder),
190            path,
191        })
192    }
193
194    Ok(builder)
195}
196
197/// Builder for converting primitive variant values to Arrow arrays. It is used by both
198/// `VariantToArrowRowBuilder` (below) and `VariantToShreddedPrimitiveVariantRowBuilder` (in
199/// `shred_variant.rs`).
200pub(crate) enum PrimitiveVariantToArrowRowBuilder<'a> {
201    Null(VariantToNullArrowRowBuilder<'a>),
202    Boolean(VariantToBooleanArrowRowBuilder<'a>),
203    Int8(VariantToPrimitiveArrowRowBuilder<'a, datatypes::Int8Type>),
204    Int16(VariantToPrimitiveArrowRowBuilder<'a, datatypes::Int16Type>),
205    Int32(VariantToPrimitiveArrowRowBuilder<'a, datatypes::Int32Type>),
206    Int64(VariantToPrimitiveArrowRowBuilder<'a, datatypes::Int64Type>),
207    UInt8(VariantToPrimitiveArrowRowBuilder<'a, datatypes::UInt8Type>),
208    UInt16(VariantToPrimitiveArrowRowBuilder<'a, datatypes::UInt16Type>),
209    UInt32(VariantToPrimitiveArrowRowBuilder<'a, datatypes::UInt32Type>),
210    UInt64(VariantToPrimitiveArrowRowBuilder<'a, datatypes::UInt64Type>),
211    Float16(VariantToPrimitiveArrowRowBuilder<'a, datatypes::Float16Type>),
212    Float32(VariantToPrimitiveArrowRowBuilder<'a, datatypes::Float32Type>),
213    Float64(VariantToPrimitiveArrowRowBuilder<'a, datatypes::Float64Type>),
214    Decimal32(VariantToDecimalArrowRowBuilder<'a, datatypes::Decimal32Type>),
215    Decimal64(VariantToDecimalArrowRowBuilder<'a, datatypes::Decimal64Type>),
216    Decimal128(VariantToDecimalArrowRowBuilder<'a, datatypes::Decimal128Type>),
217    Decimal256(VariantToDecimalArrowRowBuilder<'a, datatypes::Decimal256Type>),
218    TimestampSecond(VariantToTimestampArrowRowBuilder<'a, datatypes::TimestampSecondType>),
219    TimestampSecondNtz(VariantToTimestampNtzArrowRowBuilder<'a, datatypes::TimestampSecondType>),
220    TimestampMilli(VariantToTimestampArrowRowBuilder<'a, datatypes::TimestampMillisecondType>),
221    TimestampMilliNtz(
222        VariantToTimestampNtzArrowRowBuilder<'a, datatypes::TimestampMillisecondType>,
223    ),
224    TimestampMicro(VariantToTimestampArrowRowBuilder<'a, datatypes::TimestampMicrosecondType>),
225    TimestampMicroNtz(
226        VariantToTimestampNtzArrowRowBuilder<'a, datatypes::TimestampMicrosecondType>,
227    ),
228    TimestampNano(VariantToTimestampArrowRowBuilder<'a, datatypes::TimestampNanosecondType>),
229    TimestampNanoNtz(VariantToTimestampNtzArrowRowBuilder<'a, datatypes::TimestampNanosecondType>),
230    Time32Second(VariantToPrimitiveArrowRowBuilder<'a, datatypes::Time32SecondType>),
231    Time32Milli(VariantToPrimitiveArrowRowBuilder<'a, datatypes::Time32MillisecondType>),
232    Time64Micro(VariantToPrimitiveArrowRowBuilder<'a, datatypes::Time64MicrosecondType>),
233    Time64Nano(VariantToPrimitiveArrowRowBuilder<'a, datatypes::Time64NanosecondType>),
234    Date32(VariantToPrimitiveArrowRowBuilder<'a, datatypes::Date32Type>),
235    Date64(VariantToPrimitiveArrowRowBuilder<'a, datatypes::Date64Type>),
236    Uuid(VariantToUuidArrowRowBuilder<'a>),
237    String(VariantToStringArrowBuilder<'a, StringBuilder>),
238    LargeString(VariantToStringArrowBuilder<'a, LargeStringBuilder>),
239    StringView(VariantToStringArrowBuilder<'a, StringViewBuilder>),
240    Binary(VariantToBinaryArrowRowBuilder<'a, BinaryBuilder>),
241    LargeBinary(VariantToBinaryArrowRowBuilder<'a, LargeBinaryBuilder>),
242    BinaryView(VariantToBinaryArrowRowBuilder<'a, BinaryViewBuilder>),
243}
244
245impl PrimitiveVariantToArrowRowBuilder<'_> {
246    pub fn append_null(&mut self) -> Result<()> {
247        use PrimitiveVariantToArrowRowBuilder::*;
248        match self {
249            Null(b) => b.append_null(),
250            Boolean(b) => b.append_null(),
251            Int8(b) => b.append_null(),
252            Int16(b) => b.append_null(),
253            Int32(b) => b.append_null(),
254            Int64(b) => b.append_null(),
255            UInt8(b) => b.append_null(),
256            UInt16(b) => b.append_null(),
257            UInt32(b) => b.append_null(),
258            UInt64(b) => b.append_null(),
259            Float16(b) => b.append_null(),
260            Float32(b) => b.append_null(),
261            Float64(b) => b.append_null(),
262            Decimal32(b) => b.append_null(),
263            Decimal64(b) => b.append_null(),
264            Decimal128(b) => b.append_null(),
265            Decimal256(b) => b.append_null(),
266            TimestampSecond(b) => b.append_null(),
267            TimestampSecondNtz(b) => b.append_null(),
268            TimestampMilli(b) => b.append_null(),
269            TimestampMilliNtz(b) => b.append_null(),
270            TimestampMicro(b) => b.append_null(),
271            TimestampMicroNtz(b) => b.append_null(),
272            TimestampNano(b) => b.append_null(),
273            TimestampNanoNtz(b) => b.append_null(),
274            Time32Second(b) => b.append_null(),
275            Time32Milli(b) => b.append_null(),
276            Time64Micro(b) => b.append_null(),
277            Time64Nano(b) => b.append_null(),
278            Date32(b) => b.append_null(),
279            Date64(b) => b.append_null(),
280            Uuid(b) => b.append_null(),
281            String(b) => b.append_null(),
282            LargeString(b) => b.append_null(),
283            StringView(b) => b.append_null(),
284            Binary(b) => b.append_null(),
285            LargeBinary(b) => b.append_null(),
286            BinaryView(b) => b.append_null(),
287        }
288    }
289
290    pub fn append_value(&mut self, value: &Variant<'_, '_>) -> Result<bool> {
291        use PrimitiveVariantToArrowRowBuilder::*;
292        match self {
293            Null(b) => b.append_value(value),
294            Boolean(b) => b.append_value(value),
295            Int8(b) => b.append_value(value),
296            Int16(b) => b.append_value(value),
297            Int32(b) => b.append_value(value),
298            Int64(b) => b.append_value(value),
299            UInt8(b) => b.append_value(value),
300            UInt16(b) => b.append_value(value),
301            UInt32(b) => b.append_value(value),
302            UInt64(b) => b.append_value(value),
303            Float16(b) => b.append_value(value),
304            Float32(b) => b.append_value(value),
305            Float64(b) => b.append_value(value),
306            Decimal32(b) => b.append_value(value),
307            Decimal64(b) => b.append_value(value),
308            Decimal128(b) => b.append_value(value),
309            Decimal256(b) => b.append_value(value),
310            TimestampSecond(b) => b.append_value(value),
311            TimestampSecondNtz(b) => b.append_value(value),
312            TimestampMilli(b) => b.append_value(value),
313            TimestampMilliNtz(b) => b.append_value(value),
314            TimestampMicro(b) => b.append_value(value),
315            TimestampMicroNtz(b) => b.append_value(value),
316            TimestampNano(b) => b.append_value(value),
317            TimestampNanoNtz(b) => b.append_value(value),
318            Time32Second(b) => b.append_value(value),
319            Time32Milli(b) => b.append_value(value),
320            Time64Micro(b) => b.append_value(value),
321            Time64Nano(b) => b.append_value(value),
322            Date32(b) => b.append_value(value),
323            Date64(b) => b.append_value(value),
324            Uuid(b) => b.append_value(value),
325            String(b) => b.append_value(value),
326            LargeString(b) => b.append_value(value),
327            StringView(b) => b.append_value(value),
328            Binary(b) => b.append_value(value),
329            LargeBinary(b) => b.append_value(value),
330            BinaryView(b) => b.append_value(value),
331        }
332    }
333
334    pub fn finish(self) -> Result<ArrayRef> {
335        use PrimitiveVariantToArrowRowBuilder::*;
336        match self {
337            Null(b) => b.finish(),
338            Boolean(b) => b.finish(),
339            Int8(b) => b.finish(),
340            Int16(b) => b.finish(),
341            Int32(b) => b.finish(),
342            Int64(b) => b.finish(),
343            UInt8(b) => b.finish(),
344            UInt16(b) => b.finish(),
345            UInt32(b) => b.finish(),
346            UInt64(b) => b.finish(),
347            Float16(b) => b.finish(),
348            Float32(b) => b.finish(),
349            Float64(b) => b.finish(),
350            Decimal32(b) => b.finish(),
351            Decimal64(b) => b.finish(),
352            Decimal128(b) => b.finish(),
353            Decimal256(b) => b.finish(),
354            TimestampSecond(b) => b.finish(),
355            TimestampSecondNtz(b) => b.finish(),
356            TimestampMilli(b) => b.finish(),
357            TimestampMilliNtz(b) => b.finish(),
358            TimestampMicro(b) => b.finish(),
359            TimestampMicroNtz(b) => b.finish(),
360            TimestampNano(b) => b.finish(),
361            TimestampNanoNtz(b) => b.finish(),
362            Time32Second(b) => b.finish(),
363            Time32Milli(b) => b.finish(),
364            Time64Micro(b) => b.finish(),
365            Time64Nano(b) => b.finish(),
366            Date32(b) => b.finish(),
367            Date64(b) => b.finish(),
368            Uuid(b) => b.finish(),
369            String(b) => b.finish(),
370            LargeString(b) => b.finish(),
371            StringView(b) => b.finish(),
372            Binary(b) => b.finish(),
373            LargeBinary(b) => b.finish(),
374            BinaryView(b) => b.finish(),
375        }
376    }
377}
378
379pub(crate) struct EncodedVariantToArrowRowBuilder<'a> {
380    data_type: &'a DataType,
381    cast_options: &'a CastOptions<'a>,
382    values_builder: Box<VariantToArrowRowBuilder<'a>>,
383}
384
385impl<'a> EncodedVariantToArrowRowBuilder<'a> {
386    fn try_new(
387        data_type: &'a DataType,
388        value_type: &'a DataType,
389        cast_options: &'a CastOptions,
390        capacity: usize,
391    ) -> Result<Self> {
392        let values_builder = Box::new(make_typed_variant_to_arrow_row_builder(
393            value_type,
394            cast_options,
395            capacity,
396            VariantCastMode::Get,
397        )?);
398        Ok(Self {
399            data_type,
400            cast_options,
401            values_builder,
402        })
403    }
404
405    fn append_null(&mut self) -> Result<()> {
406        self.values_builder.append_null()
407    }
408
409    fn append_value(&mut self, value: Variant<'_, '_>) -> Result<bool> {
410        self.values_builder.append_value(value)
411    }
412
413    fn finish(self) -> Result<ArrayRef> {
414        let values = self.values_builder.finish()?;
415        cast_with_options(values.as_ref(), self.data_type, self.cast_options)
416    }
417}
418
419/// Creates a row builder that converts primitive `Variant` values into the requested Arrow data type.
420pub(crate) fn make_primitive_variant_to_arrow_row_builder<'a>(
421    data_type: &'a DataType,
422    cast_options: &'a CastOptions,
423    capacity: usize,
424    cast_mode: VariantCastMode,
425) -> Result<PrimitiveVariantToArrowRowBuilder<'a>> {
426    use PrimitiveVariantToArrowRowBuilder::*;
427
428    let builder = match data_type {
429        DataType::Null => Null(VariantToNullArrowRowBuilder::new(cast_options, capacity)),
430        DataType::Boolean => Boolean(VariantToBooleanArrowRowBuilder::new(
431            cast_options,
432            capacity,
433            cast_mode,
434        )),
435        DataType::Int8 => Int8(VariantToPrimitiveArrowRowBuilder::new(
436            cast_options,
437            capacity,
438            cast_mode,
439        )),
440        DataType::Int16 => Int16(VariantToPrimitiveArrowRowBuilder::new(
441            cast_options,
442            capacity,
443            cast_mode,
444        )),
445        DataType::Int32 => Int32(VariantToPrimitiveArrowRowBuilder::new(
446            cast_options,
447            capacity,
448            cast_mode,
449        )),
450        DataType::Int64 => Int64(VariantToPrimitiveArrowRowBuilder::new(
451            cast_options,
452            capacity,
453            cast_mode,
454        )),
455        DataType::UInt8 => UInt8(VariantToPrimitiveArrowRowBuilder::new(
456            cast_options,
457            capacity,
458            cast_mode,
459        )),
460        DataType::UInt16 => UInt16(VariantToPrimitiveArrowRowBuilder::new(
461            cast_options,
462            capacity,
463            cast_mode,
464        )),
465        DataType::UInt32 => UInt32(VariantToPrimitiveArrowRowBuilder::new(
466            cast_options,
467            capacity,
468            cast_mode,
469        )),
470        DataType::UInt64 => UInt64(VariantToPrimitiveArrowRowBuilder::new(
471            cast_options,
472            capacity,
473            cast_mode,
474        )),
475        DataType::Float16 => Float16(VariantToPrimitiveArrowRowBuilder::new(
476            cast_options,
477            capacity,
478            cast_mode,
479        )),
480        DataType::Float32 => Float32(VariantToPrimitiveArrowRowBuilder::new(
481            cast_options,
482            capacity,
483            cast_mode,
484        )),
485        DataType::Float64 => Float64(VariantToPrimitiveArrowRowBuilder::new(
486            cast_options,
487            capacity,
488            cast_mode,
489        )),
490        DataType::Decimal32(precision, scale) => Decimal32(VariantToDecimalArrowRowBuilder::new(
491            cast_options,
492            capacity,
493            *precision,
494            *scale,
495            cast_mode,
496        )?),
497        DataType::Decimal64(precision, scale) => Decimal64(VariantToDecimalArrowRowBuilder::new(
498            cast_options,
499            capacity,
500            *precision,
501            *scale,
502            cast_mode,
503        )?),
504        DataType::Decimal128(precision, scale) => Decimal128(VariantToDecimalArrowRowBuilder::new(
505            cast_options,
506            capacity,
507            *precision,
508            *scale,
509            cast_mode,
510        )?),
511        DataType::Decimal256(precision, scale) => Decimal256(VariantToDecimalArrowRowBuilder::new(
512            cast_options,
513            capacity,
514            *precision,
515            *scale,
516            cast_mode,
517        )?),
518        DataType::Date32 => Date32(VariantToPrimitiveArrowRowBuilder::new(
519            cast_options,
520            capacity,
521            cast_mode,
522        )),
523        DataType::Date64 => Date64(VariantToPrimitiveArrowRowBuilder::new(
524            cast_options,
525            capacity,
526            cast_mode,
527        )),
528        DataType::Time32(TimeUnit::Second) => Time32Second(VariantToPrimitiveArrowRowBuilder::new(
529            cast_options,
530            capacity,
531            cast_mode,
532        )),
533        DataType::Time32(TimeUnit::Millisecond) => Time32Milli(
534            VariantToPrimitiveArrowRowBuilder::new(cast_options, capacity, cast_mode),
535        ),
536        DataType::Time32(t) => {
537            return Err(ArrowError::InvalidArgumentError(format!(
538                "The unit for Time32 must be second/millisecond, received {t:?}"
539            )));
540        }
541        DataType::Time64(TimeUnit::Microsecond) => Time64Micro(
542            VariantToPrimitiveArrowRowBuilder::new(cast_options, capacity, cast_mode),
543        ),
544        DataType::Time64(TimeUnit::Nanosecond) => Time64Nano(
545            VariantToPrimitiveArrowRowBuilder::new(cast_options, capacity, cast_mode),
546        ),
547        DataType::Time64(t) => {
548            return Err(ArrowError::InvalidArgumentError(format!(
549                "The unit for Time64 must be micro/nano seconds, received {t:?}"
550            )));
551        }
552        DataType::Timestamp(TimeUnit::Second, None) => TimestampSecondNtz(
553            VariantToTimestampNtzArrowRowBuilder::new(cast_options, capacity, cast_mode),
554        ),
555        DataType::Timestamp(TimeUnit::Second, tz) => TimestampSecond(
556            VariantToTimestampArrowRowBuilder::new(cast_options, capacity, cast_mode, tz.clone()),
557        ),
558        DataType::Timestamp(TimeUnit::Millisecond, None) => TimestampMilliNtz(
559            VariantToTimestampNtzArrowRowBuilder::new(cast_options, capacity, cast_mode),
560        ),
561        DataType::Timestamp(TimeUnit::Millisecond, tz) => TimestampMilli(
562            VariantToTimestampArrowRowBuilder::new(cast_options, capacity, cast_mode, tz.clone()),
563        ),
564        DataType::Timestamp(TimeUnit::Microsecond, None) => TimestampMicroNtz(
565            VariantToTimestampNtzArrowRowBuilder::new(cast_options, capacity, cast_mode),
566        ),
567        DataType::Timestamp(TimeUnit::Microsecond, tz) => TimestampMicro(
568            VariantToTimestampArrowRowBuilder::new(cast_options, capacity, cast_mode, tz.clone()),
569        ),
570        DataType::Timestamp(TimeUnit::Nanosecond, None) => TimestampNanoNtz(
571            VariantToTimestampNtzArrowRowBuilder::new(cast_options, capacity, cast_mode),
572        ),
573        DataType::Timestamp(TimeUnit::Nanosecond, tz) => TimestampNano(
574            VariantToTimestampArrowRowBuilder::new(cast_options, capacity, cast_mode, tz.clone()),
575        ),
576        DataType::Duration(_) | DataType::Interval(_) => {
577            return Err(ArrowError::InvalidArgumentError(
578                "Casting Variant to duration/interval types is not supported. \
579                    The Variant format does not define duration/interval types."
580                    .to_string(),
581            ));
582        }
583        DataType::Binary => Binary(VariantToBinaryArrowRowBuilder::new(cast_options, capacity)),
584        DataType::LargeBinary => {
585            LargeBinary(VariantToBinaryArrowRowBuilder::new(cast_options, capacity))
586        }
587        DataType::BinaryView => {
588            BinaryView(VariantToBinaryArrowRowBuilder::new(cast_options, capacity))
589        }
590        DataType::FixedSizeBinary(16) => {
591            Uuid(VariantToUuidArrowRowBuilder::new(cast_options, capacity))
592        }
593        DataType::FixedSizeBinary(_) => {
594            return Err(ArrowError::NotYetImplemented(format!(
595                "DataType {data_type:?} not yet implemented"
596            )));
597        }
598        DataType::Utf8 => String(VariantToStringArrowBuilder::new(cast_options, capacity)),
599        DataType::LargeUtf8 => {
600            LargeString(VariantToStringArrowBuilder::new(cast_options, capacity))
601        }
602        DataType::Utf8View => StringView(VariantToStringArrowBuilder::new(cast_options, capacity)),
603        DataType::List(_)
604        | DataType::LargeList(_)
605        | DataType::ListView(_)
606        | DataType::LargeListView(_)
607        | DataType::FixedSizeList(..)
608        | DataType::Struct(_)
609        | DataType::Map(..)
610        | DataType::Union(..)
611        | DataType::Dictionary(..)
612        | DataType::RunEndEncoded(..) => {
613            return Err(ArrowError::InvalidArgumentError(format!(
614                "Casting to {data_type:?} is not applicable for primitive Variant types"
615            )));
616        }
617    };
618    Ok(builder)
619}
620
621pub(crate) enum ArrayVariantToArrowRowBuilder<'a> {
622    List(VariantToListArrowRowBuilder<'a, i32, false>),
623    LargeList(VariantToListArrowRowBuilder<'a, i64, false>),
624    ListView(VariantToListArrowRowBuilder<'a, i32, true>),
625    LargeListView(VariantToListArrowRowBuilder<'a, i64, true>),
626    FixedSizeList(VariantToFixedSizeListArrowRowBuilder<'a>),
627}
628
629pub(crate) struct StructVariantToArrowRowBuilder<'a> {
630    fields: &'a Fields,
631    field_builders: Vec<VariantToArrowRowBuilder<'a>>,
632    nulls: NullBufferBuilder,
633    cast_options: &'a CastOptions<'a>,
634}
635
636impl<'a> StructVariantToArrowRowBuilder<'a> {
637    fn try_new(
638        fields: &'a Fields,
639        cast_options: &'a CastOptions<'a>,
640        capacity: usize,
641    ) -> Result<Self> {
642        let mut field_builders = Vec::with_capacity(fields.len());
643        for field in fields {
644            field_builders.push(make_typed_variant_to_arrow_row_builder(
645                field.data_type(),
646                cast_options,
647                capacity,
648                VariantCastMode::Get,
649            )?);
650        }
651        Ok(Self {
652            fields,
653            field_builders,
654            nulls: NullBufferBuilder::new(capacity),
655            cast_options,
656        })
657    }
658
659    fn append_null(&mut self) -> Result<()> {
660        for builder in &mut self.field_builders {
661            builder.append_null()?;
662        }
663        self.nulls.append_null();
664        Ok(())
665    }
666
667    fn append_value(&mut self, value: &Variant<'_, '_>) -> Result<bool> {
668        match variant_cast_with_options(value, self.cast_options, Variant::as_object) {
669            Ok(Some(obj)) => {
670                for (index, field) in self.fields.iter().enumerate() {
671                    match obj.get(field.name()) {
672                        Some(field_value) => {
673                            self.field_builders[index].append_value(field_value)?;
674                        }
675                        None => {
676                            self.field_builders[index].append_null()?;
677                        }
678                    }
679                }
680
681                self.nulls.append_non_null();
682                Ok(true)
683            }
684            Ok(None) => {
685                self.append_null()?;
686                Ok(false)
687            }
688            Err(_) => Err(ArrowError::CastError(format!(
689                "Failed to extract struct from variant {value:?}"
690            ))),
691        }
692    }
693
694    fn finish(mut self) -> Result<ArrayRef> {
695        let mut children = Vec::with_capacity(self.field_builders.len());
696        for builder in self.field_builders {
697            children.push(builder.finish()?);
698        }
699        Ok(Arc::new(StructArray::try_new(
700            self.fields.clone(),
701            children,
702            self.nulls.finish(),
703        )?))
704    }
705}
706
707/// Builder for converting variant values into a [`UnionArray`].
708///
709/// Each value is dispatched to the union field that most exactly represents its runtime type
710/// (see [`union_child_rank`]), with ties broken by declaration order. Unions have no top-level
711/// null buffer, so null rows -- and, in safe mode, values no field can represent -- become a
712/// null in the [`DataType::Null`] child if the union declares one, otherwise in the first child.
713pub(crate) struct UnionVariantToArrowRowBuilder<'a> {
714    fields: &'a UnionFields,
715    mode: UnionMode,
716    children: Vec<UnionChildBuilder<'a>>,
717    type_ids: Vec<i8>,
718    /// Dense mode only
719    offsets: Vec<i32>,
720    null_child: usize,
721    cast_options: &'a CastOptions<'a>,
722}
723
724struct UnionChildBuilder<'a> {
725    type_id: i8,
726    builder: VariantToArrowRowBuilder<'a>,
727    len: i32,
728}
729
730impl<'a> UnionVariantToArrowRowBuilder<'a> {
731    fn try_new(
732        fields: &'a UnionFields,
733        mode: UnionMode,
734        cast_options: &'a CastOptions<'a>,
735        capacity: usize,
736    ) -> Result<Self> {
737        // null rows need a child to land in
738        if fields.is_empty() {
739            return Err(ArrowError::InvalidArgumentError(
740                "Casting Variant to a union requires at least one union field".to_string(),
741            ));
742        }
743        let mut children = Vec::with_capacity(fields.len());
744        for (type_id, field) in fields.iter() {
745            // Match the other typed builders: nullability is schema metadata and does not
746            // override safe-cast behavior, which may append null for an unrepresentable value.
747            children.push(UnionChildBuilder {
748                type_id,
749                builder: make_typed_variant_to_arrow_row_builder(
750                    field.data_type(),
751                    cast_options,
752                    capacity,
753                    VariantCastMode::Get,
754                )?,
755                len: 0,
756            });
757        }
758        let null_child = fields
759            .iter()
760            .position(|(_, field)| field.data_type() == &DataType::Null)
761            .unwrap_or(0);
762        let offsets = match mode {
763            UnionMode::Dense => Vec::with_capacity(capacity),
764            UnionMode::Sparse => Vec::new(),
765        };
766        Ok(Self {
767            fields,
768            mode,
769            children,
770            type_ids: Vec::with_capacity(capacity),
771            offsets,
772            null_child,
773            cast_options,
774        })
775    }
776
777    fn append_null(&mut self) -> Result<()> {
778        self.append_to_child(self.null_child, None)?;
779        Ok(())
780    }
781
782    fn append_value(&mut self, value: &Variant<'_, '_>) -> Result<bool> {
783        // `Variant::Null` becomes null even in strict mode, like in the other builders
784        if matches!(value, Variant::Null) {
785            self.append_null()?;
786            return Ok(false);
787        }
788        match self.select_child(value) {
789            Some(index) => self.append_to_child(index, Some(value)),
790            None if self.cast_options.safe => {
791                self.append_null()?;
792                Ok(false)
793            }
794            None => Err(ArrowError::CastError(format!(
795                "Failed to cast variant {value:?} to union: no field can represent it"
796            ))),
797        }
798    }
799
800    fn select_child(&self, value: &Variant<'_, '_>) -> Option<usize> {
801        let mut best: Option<(u8, usize)> = None;
802        for (index, (_, field)) in self.fields.iter().enumerate() {
803            let Some(rank) = union_child_rank(value, field.data_type()) else {
804                continue;
805            };
806            if best.is_none_or(|(best_rank, _)| rank < best_rank) {
807                best = Some((rank, index));
808            }
809        }
810        best.map(|(_, index)| index)
811    }
812
813    fn append_to_child(&mut self, index: usize, value: Option<&Variant<'_, '_>>) -> Result<bool> {
814        self.type_ids.push(self.children[index].type_id);
815        match self.mode {
816            UnionMode::Dense => {
817                let child = &mut self.children[index];
818                self.offsets.push(child.len);
819                child.len = child.len.add_checked(1)?;
820                match value {
821                    Some(value) => child.builder.append_value(value.clone()),
822                    None => {
823                        child.builder.append_null()?;
824                        Ok(false)
825                    }
826                }
827            }
828            UnionMode::Sparse => {
829                let mut appended = false;
830                for (child_index, child) in self.children.iter_mut().enumerate() {
831                    match value {
832                        Some(value) if child_index == index => {
833                            appended = child.builder.append_value(value.clone())?;
834                        }
835                        _ => child.builder.append_null()?,
836                    }
837                }
838                Ok(appended)
839            }
840        }
841    }
842
843    fn finish(self) -> Result<ArrayRef> {
844        let mut type_ids = Vec::with_capacity(self.children.len());
845        let mut fields = Vec::with_capacity(self.children.len());
846        let mut arrays = Vec::with_capacity(self.children.len());
847        for (child, (_, field)) in self.children.into_iter().zip(self.fields.iter()) {
848            let array = child.builder.finish()?;
849            type_ids.push(child.type_id);
850            fields.push(
851                field
852                    .as_ref()
853                    .clone()
854                    .with_data_type(array.data_type().clone()),
855            );
856            arrays.push(array);
857        }
858        let fields = UnionFields::try_new(type_ids, fields)?;
859        let offsets = (self.mode == UnionMode::Dense).then(|| ScalarBuffer::from(self.offsets));
860        let array =
861            UnionArray::try_new(fields, ScalarBuffer::from(self.type_ids), offsets, arrays)?;
862        Ok(Arc::new(array))
863    }
864}
865
866/// Ranks how exactly a union child of type `data_type` can represent a variant value's runtime
867/// type: 0 is the value's natural Arrow type, higher ranks are lossless widenings, and `None`
868/// means the child cannot represent the value losslessly. Every pair admitted here must be
869/// convertible by the corresponding row builder.
870fn union_child_rank(value: &Variant<'_, '_>, data_type: &DataType) -> Option<u8> {
871    use DataType::*;
872    let rank = match (value, data_type) {
873        (_, Dictionary(_, value_type)) => return union_child_rank(value, value_type),
874        (_, RunEndEncoded(_, value_field)) => {
875            return union_child_rank(value, value_field.data_type());
876        }
877        (Variant::BooleanTrue | Variant::BooleanFalse, Boolean) => 0,
878        (Variant::Int8(_), Int8) => 0,
879        (Variant::Int8(_), Int16) => 1,
880        (Variant::Int8(_), Int32) => 2,
881        (Variant::Int8(_), Int64) => 3,
882        (Variant::Int16(_), Int16) => 0,
883        (Variant::Int16(_), Int32) => 1,
884        (Variant::Int16(_), Int64) => 2,
885        (Variant::Int32(_), Int32) => 0,
886        (Variant::Int32(_), Int64) => 1,
887        (Variant::Int64(_), Int64) => 0,
888        (Variant::Float(_), Float32) => 0,
889        (Variant::Float(_), Float64) => 1,
890        (Variant::Double(_), Float64) => 0,
891        (Variant::Decimal4(_), Decimal32(..)) if variant_fits_decimal(value, data_type) => 0,
892        (Variant::Decimal4(_), Decimal64(..)) if variant_fits_decimal(value, data_type) => 1,
893        (Variant::Decimal4(_), Decimal128(..)) if variant_fits_decimal(value, data_type) => 2,
894        (Variant::Decimal4(_), Decimal256(..)) if variant_fits_decimal(value, data_type) => 3,
895        (Variant::Decimal8(_), Decimal64(..)) if variant_fits_decimal(value, data_type) => 0,
896        (Variant::Decimal8(_), Decimal128(..)) if variant_fits_decimal(value, data_type) => 1,
897        (Variant::Decimal8(_), Decimal256(..)) if variant_fits_decimal(value, data_type) => 2,
898        (Variant::Decimal16(_), Decimal128(..)) if variant_fits_decimal(value, data_type) => 0,
899        (Variant::Decimal16(_), Decimal256(..)) if variant_fits_decimal(value, data_type) => 1,
900        (Variant::Date(_), Date32) => 0,
901        (Variant::Date(_), Date64) => 1,
902        (Variant::TimestampMicros(_), Timestamp(TimeUnit::Microsecond, Some(_))) => 0,
903        (Variant::TimestampMicros(_), Timestamp(TimeUnit::Nanosecond, Some(_))) => 1,
904        (Variant::TimestampNanos(_), Timestamp(TimeUnit::Nanosecond, Some(_))) => 0,
905        (Variant::TimestampNtzMicros(_), Timestamp(TimeUnit::Microsecond, None)) => 0,
906        (Variant::TimestampNtzMicros(_), Timestamp(TimeUnit::Nanosecond, None)) => 1,
907        (Variant::TimestampNtzNanos(_), Timestamp(TimeUnit::Nanosecond, None)) => 0,
908        (Variant::Time(_), Time64(TimeUnit::Microsecond)) => 0,
909        (Variant::Time(_), Time64(TimeUnit::Nanosecond)) => 1,
910        (Variant::String(_) | Variant::ShortString(_), Utf8 | LargeUtf8 | Utf8View) => 0,
911        (Variant::Binary(_), Binary | LargeBinary | BinaryView) => 0,
912        (Variant::Uuid(_), FixedSizeBinary(16)) => 0,
913        (Variant::Object(_), Struct(_)) => 0,
914        (Variant::Object(_), Map(..)) => 1,
915        (Variant::List(_), List(_)) => 0,
916        (Variant::List(list), FixedSizeList(_, size)) if list.len() == *size as usize => 0,
917        (Variant::List(_), LargeList(_)) => 1,
918        (Variant::List(_), ListView(_)) => 2,
919        (Variant::List(_), LargeListView(_)) => 3,
920        _ => return None,
921    };
922    Some(rank)
923}
924
925fn variant_fits_decimal(value: &Variant<'_, '_>, data_type: &DataType) -> bool {
926    match data_type {
927        DataType::Decimal32(precision, scale) => {
928            variant_to_unscaled_decimal::<datatypes::Decimal32Type>(value, *precision, *scale)
929                .is_some()
930        }
931        DataType::Decimal64(precision, scale) => {
932            variant_to_unscaled_decimal::<datatypes::Decimal64Type>(value, *precision, *scale)
933                .is_some()
934        }
935        DataType::Decimal128(precision, scale) => {
936            variant_to_unscaled_decimal::<datatypes::Decimal128Type>(value, *precision, *scale)
937                .is_some()
938        }
939        DataType::Decimal256(precision, scale) => {
940            variant_to_unscaled_decimal::<datatypes::Decimal256Type>(value, *precision, *scale)
941                .is_some()
942        }
943        _ => false,
944    }
945}
946
947/// Builder for converting variant objects into Arrow `MapArray`s.
948///
949/// Each variant object field becomes one map entry: the field name is the map key and the field
950/// value is converted to the requested value type. Variant objects store their fields in
951/// lexicographic key order, so maps with string keys come out sorted by key.
952pub(crate) struct MapVariantToArrowRowBuilder<'a> {
953    entries_field: &'a FieldRef,
954    key_field: &'a FieldRef,
955    value_field: &'a FieldRef,
956    ordered: bool,
957    key_builder: Box<VariantToArrowRowBuilder<'a>>,
958    value_builder: Box<VariantToArrowRowBuilder<'a>>,
959    offsets: Vec<i32>,
960    current_offset: i32,
961    nulls: NullBufferBuilder,
962    cast_options: &'a CastOptions<'a>,
963}
964
965impl<'a> MapVariantToArrowRowBuilder<'a> {
966    fn try_new(
967        entries_field: &'a FieldRef,
968        ordered: bool,
969        cast_options: &'a CastOptions,
970        capacity: usize,
971        cast_mode: VariantCastMode,
972    ) -> Result<Self> {
973        let DataType::Struct(entry_fields) = entries_field.data_type() else {
974            return Err(ArrowError::InvalidArgumentError(format!(
975                "Map entries must be Struct, got {:?}",
976                entries_field.data_type()
977            )));
978        };
979        let (key_field, value_field) = match entry_fields.as_ref() {
980            [key_field, value_field] => (key_field, value_field),
981            fields => {
982                return Err(ArrowError::InvalidArgumentError(format!(
983                    "Map entries must have exactly two fields (key, value), got {}",
984                    fields.len()
985                )));
986            }
987        };
988        let key_builder = Box::new(make_typed_variant_to_arrow_row_builder(
989            key_field.data_type(),
990            cast_options,
991            capacity,
992            cast_mode,
993        )?);
994        let value_builder = Box::new(make_typed_variant_to_arrow_row_builder(
995            value_field.data_type(),
996            cast_options,
997            capacity,
998            cast_mode,
999        )?);
1000        if capacity >= isize::MAX as usize {
1001            return Err(ArrowError::ComputeError(
1002                "Capacity exceeds isize::MAX when reserving map offsets".to_string(),
1003            ));
1004        }
1005        let mut offsets = Vec::with_capacity(capacity + 1);
1006        offsets.push(0);
1007        Ok(Self {
1008            entries_field,
1009            key_field,
1010            value_field,
1011            ordered,
1012            key_builder,
1013            value_builder,
1014            offsets,
1015            current_offset: 0,
1016            nulls: NullBufferBuilder::new(capacity),
1017            cast_options,
1018        })
1019    }
1020
1021    fn append_null(&mut self) -> Result<()> {
1022        self.offsets.push(self.current_offset);
1023        self.nulls.append_null();
1024        Ok(())
1025    }
1026
1027    fn append_value(&mut self, value: &Variant<'_, '_>) -> Result<bool> {
1028        match variant_cast_with_options(value, self.cast_options, Variant::as_object) {
1029            Ok(Some(obj)) => {
1030                for (key, field_value) in obj.iter() {
1031                    // Map keys cannot be null, so a failed key conversion is an error even when
1032                    // cast_options.safe is true.
1033                    if !self.key_builder.append_value(Variant::from(key))? {
1034                        return Err(ArrowError::CastError(format!(
1035                            "Failed to cast map key {key:?} to {:?}",
1036                            self.key_field.data_type()
1037                        )));
1038                    }
1039                    self.value_builder.append_value(field_value)?;
1040                    self.current_offset = self.current_offset.add_checked(1)?;
1041                }
1042                self.offsets.push(self.current_offset);
1043                self.nulls.append_non_null();
1044                Ok(true)
1045            }
1046            Ok(None) => {
1047                self.append_null()?;
1048                Ok(false)
1049            }
1050            Err(_) => Err(ArrowError::CastError(format!(
1051                "Failed to extract object from variant {value:?}"
1052            ))),
1053        }
1054    }
1055
1056    fn finish(mut self) -> Result<ArrayRef> {
1057        let keys = self.key_builder.finish()?;
1058        let values = self.value_builder.finish()?;
1059
1060        let entry_fields = Fields::from(vec![
1061            self.key_field
1062                .as_ref()
1063                .clone()
1064                .with_data_type(keys.data_type().clone()),
1065            self.value_field
1066                .as_ref()
1067                .clone()
1068                .with_data_type(values.data_type().clone()),
1069        ]);
1070        let entries = StructArray::try_new(entry_fields.clone(), vec![keys, values], None)?;
1071        let entries_field = Arc::new(
1072            self.entries_field
1073                .as_ref()
1074                .clone()
1075                .with_data_type(DataType::Struct(entry_fields)),
1076        );
1077        let map_array = MapArray::try_new(
1078            entries_field,
1079            OffsetBuffer::new(ScalarBuffer::from(self.offsets)),
1080            entries,
1081            self.nulls.finish(),
1082            self.ordered,
1083        )?;
1084        Ok(Arc::new(map_array))
1085    }
1086}
1087
1088impl<'a> ArrayVariantToArrowRowBuilder<'a> {
1089    /// Creates a new list builder for the given data type.
1090    ///
1091    /// # Arguments
1092    /// * `shredded` - If true, element builders produce shredded structs with `value`/`typed_value`
1093    ///   fields (for [`crate::shred_variant()`]). If false, element builders produce strongly typed
1094    ///   arrays directly (for [`crate::variant_get()`]).
1095    pub(crate) fn try_new(
1096        data_type: &'a DataType,
1097        cast_options: &'a CastOptions,
1098        capacity: usize,
1099        shredded: bool,
1100    ) -> Result<Self> {
1101        use ArrayVariantToArrowRowBuilder::*;
1102
1103        // Make List/ListView builders without repeating the constructor boilerplate.
1104        macro_rules! make_list_builder {
1105            ($variant:ident, $offset:ty, $is_view:expr, $field:ident) => {
1106                $variant(VariantToListArrowRowBuilder::<$offset, $is_view>::try_new(
1107                    $field.clone(),
1108                    $field.data_type(),
1109                    cast_options,
1110                    capacity,
1111                    shredded,
1112                )?)
1113            };
1114        }
1115
1116        let builder = match data_type {
1117            DataType::List(field) => make_list_builder!(List, i32, false, field),
1118            DataType::LargeList(field) => make_list_builder!(LargeList, i64, false, field),
1119            DataType::ListView(field) => make_list_builder!(ListView, i32, true, field),
1120            DataType::LargeListView(field) => make_list_builder!(LargeListView, i64, true, field),
1121            DataType::FixedSizeList(field, size) => {
1122                FixedSizeList(VariantToFixedSizeListArrowRowBuilder::try_new(
1123                    field.clone(),
1124                    field.data_type(),
1125                    *size,
1126                    cast_options,
1127                    capacity,
1128                    shredded,
1129                )?)
1130            }
1131            other => {
1132                return Err(ArrowError::InvalidArgumentError(format!(
1133                    "Casting to {other:?} is not applicable for array Variant types"
1134                )));
1135            }
1136        };
1137        Ok(builder)
1138    }
1139
1140    pub(crate) fn append_null(&mut self) -> Result<()> {
1141        match self {
1142            Self::List(builder) => builder.append_null(),
1143            Self::LargeList(builder) => builder.append_null(),
1144            Self::ListView(builder) => builder.append_null(),
1145            Self::LargeListView(builder) => builder.append_null(),
1146            Self::FixedSizeList(builder) => builder.append_null(),
1147        }
1148    }
1149
1150    pub(crate) fn append_value(&mut self, value: &Variant<'_, '_>) -> Result<bool> {
1151        match self {
1152            Self::List(builder) => builder.append_value(value),
1153            Self::LargeList(builder) => builder.append_value(value),
1154            Self::ListView(builder) => builder.append_value(value),
1155            Self::LargeListView(builder) => builder.append_value(value),
1156            Self::FixedSizeList(builder) => builder.append_value(value),
1157        }
1158    }
1159
1160    pub(crate) fn finish(self) -> Result<ArrayRef> {
1161        match self {
1162            Self::List(builder) => builder.finish(),
1163            Self::LargeList(builder) => builder.finish(),
1164            Self::ListView(builder) => builder.finish(),
1165            Self::LargeListView(builder) => builder.finish(),
1166            Self::FixedSizeList(builder) => builder.finish(),
1167        }
1168    }
1169}
1170
1171/// A thin wrapper whose only job is to extract a specific path from a variant value and pass the
1172/// result to a nested builder.
1173pub(crate) struct VariantPathRowBuilder<'a> {
1174    builder: Box<VariantToArrowRowBuilder<'a>>,
1175    path: VariantPath<'a>,
1176}
1177
1178impl VariantPathRowBuilder<'_> {
1179    fn append_null(&mut self) -> Result<()> {
1180        self.builder.append_null()
1181    }
1182
1183    fn append_value(&mut self, value: Variant<'_, '_>) -> Result<bool> {
1184        if let Some(v) = value.get_path(&self.path) {
1185            self.builder.append_value(v)
1186        } else {
1187            self.builder.append_null()?;
1188            Ok(false)
1189        }
1190    }
1191
1192    fn finish(self) -> Result<ArrayRef> {
1193        self.builder.finish()
1194    }
1195}
1196
1197macro_rules! define_variant_to_primitive_builder {
1198    (struct $name:ident<$lifetime:lifetime $(, $generic:ident: $bound:path )?>
1199    |$array_param:ident $(, $field:ident: $field_type:ty)?| -> $builder_name:ident $(< $array_type:ty >)? { $init_expr: expr },
1200    |$value: ident $(, $cast_mode: ident)?| $value_transform:expr,
1201    type_name: $type_name:expr) => {
1202        pub(crate) struct $name<$lifetime $(, $generic : $bound )?>
1203        {
1204            builder: $builder_name $(<$array_type>)?,
1205            $($cast_mode: VariantCastMode,)?
1206            cast_options: &$lifetime CastOptions<$lifetime>,
1207        }
1208
1209        impl<$lifetime $(, $generic: $bound+ )?> $name<$lifetime $(, $generic )?> {
1210            fn new(
1211                cast_options: &$lifetime CastOptions<$lifetime>,
1212                $array_param: usize,
1213                $($cast_mode: VariantCastMode,)?
1214                // add this so that $init_expr can use it
1215                $( $field: $field_type, )?
1216            ) -> Self {
1217                Self {
1218                    builder: $init_expr,
1219                    cast_options,
1220                    $($cast_mode)?
1221                }
1222            }
1223
1224            fn append_null(&mut self) -> Result<()> {
1225                self.builder.append_null();
1226                Ok(())
1227            }
1228
1229            fn append_value(&mut self, $value: &Variant<'_, '_>) -> Result<bool> {
1230                $(let $cast_mode: VariantCastMode = self.cast_mode;)?
1231                match variant_cast_with_options(
1232                    $value,
1233                    self.cast_options,
1234                    |$value| $value_transform,
1235                ) {
1236                    Ok(Some(v)) => {
1237                        self.builder.append_value(v);
1238                        Ok(true)
1239                    }
1240                    Ok(None) => {
1241                        self.builder.append_null();
1242                        Ok(false)
1243                    }
1244                    Err(_) => Err(ArrowError::CastError(format!(
1245                        "Failed to extract primitive of type {type_name} from variant {value:?} at path VariantPath([])",
1246                        type_name = $type_name,
1247                        value = $value
1248                    ))),
1249                }
1250            }
1251
1252            // Add this to silence unused mut warning from macro-generated code
1253            // This is mainly for `FakeNullBuilder`
1254            #[expect(clippy::allow_attributes)]
1255            #[allow(unused_mut)]
1256            fn finish(mut self) -> Result<ArrayRef> {
1257                // If the builder produces T: Array, the compiler infers `<Arc<T> as From<T>>::from`
1258                // (which then coerces to ArrayRef). If the builder produces ArrayRef directly, the
1259                // compiler infers `<ArrayRef as From<ArrayRef>>::from` (no-op, From blanket impl).
1260                Ok(Arc::from(self.builder.finish()))
1261            }
1262        }
1263    }
1264}
1265
1266define_variant_to_primitive_builder!(
1267    struct VariantToStringArrowBuilder<'a, B: StringLikeArrayBuilder>
1268    |capacity| -> B { B::with_capacity(capacity) },
1269    |value| value.as_string(),
1270    type_name: B::type_name()
1271);
1272
1273define_variant_to_primitive_builder!(
1274    struct VariantToBooleanArrowRowBuilder<'a>
1275    |capacity| -> BooleanBuilder { BooleanBuilder::with_capacity(capacity) },
1276    |value, cast_mode| variant_to_boolean(value, cast_mode),
1277    type_name: datatypes::BooleanType::DATA_TYPE
1278);
1279
1280define_variant_to_primitive_builder!(
1281    struct VariantToPrimitiveArrowRowBuilder<'a, T:PrimitiveFromVariant>
1282    |capacity| -> PrimitiveBuilder<T> { PrimitiveBuilder::<T>::with_capacity(capacity) },
1283    |value, cast_mode| T::from_variant(value, cast_mode),
1284    type_name: T::DATA_TYPE
1285);
1286
1287define_variant_to_primitive_builder!(
1288    struct VariantToTimestampNtzArrowRowBuilder<'a, T:TimestampFromVariant<true>>
1289    |capacity| -> PrimitiveBuilder<T> { PrimitiveBuilder::<T>::with_capacity(capacity) },
1290    |value, cast_mode| T::from_variant(value, cast_mode),
1291    type_name: T::DATA_TYPE
1292);
1293
1294define_variant_to_primitive_builder!(
1295    struct VariantToTimestampArrowRowBuilder<'a, T:TimestampFromVariant<false>>
1296    |capacity, tz: Option<Arc<str>> | -> PrimitiveBuilder<T> {
1297        PrimitiveBuilder::<T>::with_capacity(capacity).with_timezone_opt(tz)
1298    },
1299    |value, cast_mode| T::from_variant(value, cast_mode),
1300    type_name: T::DATA_TYPE
1301);
1302
1303define_variant_to_primitive_builder!(
1304    struct VariantToBinaryArrowRowBuilder<'a, B: BinaryLikeArrayBuilder>
1305    |capacity| -> B { B::with_capacity(capacity) },
1306    |value| value.as_u8_slice(),
1307    type_name: B::type_name()
1308);
1309
1310/// Builder for converting variant values to arrow Decimal values
1311pub(crate) struct VariantToDecimalArrowRowBuilder<'a, T>
1312where
1313    T: DecimalType,
1314    T::Native: DecimalCast,
1315{
1316    builder: PrimitiveBuilder<T>,
1317    cast_options: &'a CastOptions<'a>,
1318    precision: u8,
1319    scale: i8,
1320    cast_mode: VariantCastMode,
1321}
1322
1323impl<'a, T> VariantToDecimalArrowRowBuilder<'a, T>
1324where
1325    T: ShredDecimalVariant,
1326    T::Native: DecimalCast,
1327{
1328    fn new(
1329        cast_options: &'a CastOptions<'a>,
1330        capacity: usize,
1331        precision: u8,
1332        scale: i8,
1333        cast_mode: VariantCastMode,
1334    ) -> Result<Self> {
1335        let builder = PrimitiveBuilder::<T>::with_capacity(capacity)
1336            .with_precision_and_scale(precision, scale)?;
1337        Ok(Self {
1338            builder,
1339            cast_options,
1340            precision,
1341            scale,
1342            cast_mode,
1343        })
1344    }
1345
1346    fn append_null(&mut self) -> Result<()> {
1347        self.builder.append_null();
1348        Ok(())
1349    }
1350
1351    fn append_value(&mut self, value: &Variant<'_, '_>) -> Result<bool> {
1352        match variant_cast_with_options(value, self.cast_options, |value| match self.cast_mode {
1353            VariantCastMode::Shred => {
1354                shred_variant_to_unscaled_decimal::<T>(value, self.precision, self.scale)
1355            }
1356            VariantCastMode::Get => {
1357                variant_to_unscaled_decimal::<T>(value, self.precision, self.scale)
1358            }
1359        }) {
1360            Ok(Some(scaled)) => {
1361                self.builder.append_value(scaled);
1362                Ok(true)
1363            }
1364            Ok(None) => {
1365                self.builder.append_null();
1366                Ok(false)
1367            }
1368            Err(_) => Err(ArrowError::CastError(format!(
1369                "Failed to cast to {prefix}(precision={precision}, scale={scale}) from variant {value:?}",
1370                prefix = T::PREFIX,
1371                precision = self.precision,
1372                scale = self.scale
1373            ))),
1374        }
1375    }
1376
1377    fn finish(mut self) -> Result<ArrayRef> {
1378        Ok(Arc::new(self.builder.finish()))
1379    }
1380}
1381
1382/// Builder for converting variant values to FixedSizeBinary(16) for UUIDs
1383pub(crate) struct VariantToUuidArrowRowBuilder<'a> {
1384    builder: FixedSizeBinaryBuilder,
1385    cast_options: &'a CastOptions<'a>,
1386}
1387
1388impl<'a> VariantToUuidArrowRowBuilder<'a> {
1389    fn new(cast_options: &'a CastOptions<'a>, capacity: usize) -> Self {
1390        Self {
1391            builder: FixedSizeBinaryBuilder::with_capacity(capacity, 16),
1392            cast_options,
1393        }
1394    }
1395
1396    fn append_null(&mut self) -> Result<()> {
1397        self.builder.append_null();
1398        Ok(())
1399    }
1400
1401    fn append_value(&mut self, value: &Variant<'_, '_>) -> Result<bool> {
1402        match variant_cast_with_options(value, self.cast_options, Variant::as_uuid) {
1403            Ok(Some(uuid)) => {
1404                self.builder
1405                    .append_value(uuid.as_bytes())
1406                    .map_err(|e| ArrowError::ExternalError(Box::new(e)))?;
1407                Ok(true)
1408            }
1409            Ok(None) => {
1410                self.builder.append_null();
1411                Ok(false)
1412            }
1413            Err(_) => Err(ArrowError::CastError(format!(
1414                "Failed to extract UUID from variant {value:?}"
1415            ))),
1416        }
1417    }
1418
1419    fn finish(mut self) -> Result<ArrayRef> {
1420        Ok(Arc::new(self.builder.finish()))
1421    }
1422}
1423
1424/// Element builder for list variants, supporting both typed (for [`crate::variant_get()`])
1425/// and shredded (for [`crate::shred_variant()`]) output modes.
1426enum ListElementBuilder<'a> {
1427    /// Produces the target array type directly.
1428    Typed(Box<VariantToArrowRowBuilder<'a>>),
1429    /// Produces a shredded struct with `value` and `typed_value` fields.
1430    Shredded(Box<VariantToShreddedVariantRowBuilder<'a>>),
1431}
1432
1433impl ListElementBuilder<'_> {
1434    fn append_null(&mut self) -> Result<()> {
1435        match self {
1436            Self::Typed(b) => b.append_null(),
1437            Self::Shredded(b) => b.append_null(),
1438        }
1439    }
1440
1441    fn append_value(&mut self, value: Variant<'_, '_>) -> Result<bool> {
1442        match self {
1443            Self::Typed(b) => b.append_value(value),
1444            Self::Shredded(b) => b.append_value(value),
1445        }
1446    }
1447
1448    fn finish(self) -> Result<ArrayRef> {
1449        match self {
1450            Self::Typed(b) => b.finish(),
1451            Self::Shredded(b) => {
1452                let (value, typed_value, nulls) = b.finish()?;
1453                Ok(ArrayRef::from(ShreddedVariantFieldArray::from_parts(
1454                    Arc::new(value),
1455                    Some(typed_value),
1456                    nulls,
1457                )))
1458            }
1459        }
1460    }
1461}
1462
1463pub(crate) struct VariantToListArrowRowBuilder<'a, O, const IS_VIEW: bool>
1464where
1465    O: OffsetSizeTrait + ArrowNativeTypeOp,
1466{
1467    field: FieldRef,
1468    offsets: Vec<O>,
1469    element_builder: ListElementBuilder<'a>,
1470    nulls: NullBufferBuilder,
1471    current_offset: O,
1472    cast_options: &'a CastOptions<'a>,
1473}
1474
1475impl<'a, O, const IS_VIEW: bool> VariantToListArrowRowBuilder<'a, O, IS_VIEW>
1476where
1477    O: OffsetSizeTrait + ArrowNativeTypeOp,
1478{
1479    fn try_new(
1480        field: FieldRef,
1481        element_data_type: &'a DataType,
1482        cast_options: &'a CastOptions,
1483        capacity: usize,
1484        shredded: bool,
1485    ) -> Result<Self> {
1486        if capacity >= isize::MAX as usize {
1487            return Err(ArrowError::ComputeError(
1488                "Capacity exceeds isize::MAX when reserving list offsets".to_string(),
1489            ));
1490        }
1491        let mut offsets = Vec::with_capacity(capacity + 1);
1492        offsets.push(O::ZERO);
1493        let element_builder = if shredded {
1494            let builder = make_variant_to_shredded_variant_arrow_row_builder(
1495                element_data_type,
1496                cast_options,
1497                capacity,
1498                NullValue::ArrayElement,
1499                VariantCastMode::Shred,
1500            )?;
1501            ListElementBuilder::Shredded(Box::new(builder))
1502        } else {
1503            let builder = make_typed_variant_to_arrow_row_builder(
1504                element_data_type,
1505                cast_options,
1506                capacity,
1507                VariantCastMode::Get,
1508            )?;
1509            ListElementBuilder::Typed(Box::new(builder))
1510        };
1511
1512        Ok(Self {
1513            field,
1514            offsets,
1515            element_builder,
1516            nulls: NullBufferBuilder::new(capacity),
1517            current_offset: O::ZERO,
1518            cast_options,
1519        })
1520    }
1521
1522    fn append_null(&mut self) -> Result<()> {
1523        self.offsets.push(self.current_offset);
1524        self.nulls.append_null();
1525        Ok(())
1526    }
1527
1528    fn append_value(&mut self, value: &Variant<'_, '_>) -> Result<bool> {
1529        match variant_cast_with_options(value, self.cast_options, Variant::as_list) {
1530            Ok(Some(list)) => {
1531                for element in list.iter() {
1532                    self.element_builder.append_value(element)?;
1533                    self.current_offset = self.current_offset.add_checked(O::ONE)?;
1534                }
1535                self.offsets.push(self.current_offset);
1536                self.nulls.append_non_null();
1537                Ok(true)
1538            }
1539            Ok(None) => {
1540                self.append_null()?;
1541                Ok(false)
1542            }
1543            Err(_) => Err(ArrowError::CastError(format!(
1544                "Failed to extract list from variant {value:?}"
1545            ))),
1546        }
1547    }
1548
1549    fn finish(mut self) -> Result<ArrayRef> {
1550        let element_array: ArrayRef = self.element_builder.finish()?;
1551        let field = Arc::new(
1552            self.field
1553                .as_ref()
1554                .clone()
1555                .with_data_type(element_array.data_type().clone()),
1556        );
1557
1558        if IS_VIEW {
1559            // NOTE: `offsets` is never empty (constructor pushes an entry)
1560            let mut sizes = Vec::with_capacity(self.offsets.len() - 1);
1561            for i in 1..self.offsets.len() {
1562                sizes.push(self.offsets[i] - self.offsets[i - 1]);
1563            }
1564            self.offsets.pop();
1565            let list_view_array = GenericListViewArray::<O>::try_new(
1566                field,
1567                ScalarBuffer::from(self.offsets),
1568                ScalarBuffer::from(sizes),
1569                element_array,
1570                self.nulls.finish(),
1571            )?;
1572            Ok(Arc::new(list_view_array))
1573        } else {
1574            let list_array = GenericListArray::<O>::try_new(
1575                field,
1576                OffsetBuffer::<O>::new(ScalarBuffer::from(self.offsets)),
1577                element_array,
1578                self.nulls.finish(),
1579            )?;
1580            Ok(Arc::new(list_array))
1581        }
1582    }
1583}
1584
1585pub(crate) struct VariantToFixedSizeListArrowRowBuilder<'a> {
1586    field: FieldRef,
1587    list_size: i32,
1588    element_builder: ListElementBuilder<'a>,
1589    nulls: NullBufferBuilder,
1590    cast_options: &'a CastOptions<'a>,
1591    shredded: bool,
1592}
1593
1594impl<'a> VariantToFixedSizeListArrowRowBuilder<'a> {
1595    fn try_new(
1596        field: FieldRef,
1597        element_data_type: &'a DataType,
1598        list_size: i32,
1599        cast_options: &'a CastOptions,
1600        capacity: usize,
1601        shredded: bool,
1602    ) -> Result<Self> {
1603        let element_builder = if shredded {
1604            let builder = make_variant_to_shredded_variant_arrow_row_builder(
1605                element_data_type,
1606                cast_options,
1607                capacity,
1608                NullValue::ArrayElement,
1609                VariantCastMode::Shred,
1610            )?;
1611            ListElementBuilder::Shredded(Box::new(builder))
1612        } else {
1613            let builder = make_typed_variant_to_arrow_row_builder(
1614                element_data_type,
1615                cast_options,
1616                capacity,
1617                VariantCastMode::Get,
1618            )?;
1619            ListElementBuilder::Typed(Box::new(builder))
1620        };
1621        Ok(Self {
1622            field,
1623            list_size,
1624            element_builder,
1625            nulls: NullBufferBuilder::new(capacity),
1626            cast_options,
1627            shredded,
1628        })
1629    }
1630
1631    fn append_null(&mut self) -> Result<()> {
1632        for _ in 0..self.list_size {
1633            self.element_builder.append_null()?;
1634        }
1635        self.nulls.append_null();
1636        Ok(())
1637    }
1638
1639    fn append_value(&mut self, value: &Variant<'_, '_>) -> Result<bool> {
1640        match variant_cast_with_options(value, self.cast_options, Variant::as_list) {
1641            Ok(Some(list)) => {
1642                let len = list.len();
1643                if len != self.list_size as usize {
1644                    if self.cast_options.safe && !self.shredded {
1645                        self.append_null()?;
1646                        return Ok(false);
1647                    }
1648                    return Err(ArrowError::CastError(format!(
1649                        "Expected fixed size list of size {}, got size {}",
1650                        self.list_size, len
1651                    )));
1652                }
1653                for element in list.iter() {
1654                    self.element_builder.append_value(element)?;
1655                }
1656                self.nulls.append_non_null();
1657                Ok(true)
1658            }
1659            Ok(None) => {
1660                self.append_null()?;
1661                Ok(false)
1662            }
1663            Err(_) => Err(ArrowError::CastError(format!(
1664                "Failed to extract list from variant {value:?}"
1665            ))),
1666        }
1667    }
1668
1669    fn finish(mut self) -> Result<ArrayRef> {
1670        let element_array: ArrayRef = self.element_builder.finish()?;
1671        let field = Arc::new(
1672            self.field
1673                .as_ref()
1674                .clone()
1675                .with_data_type(element_array.data_type().clone()),
1676        );
1677        let fixed_size_list_array =
1678            FixedSizeListArray::try_new(field, self.list_size, element_array, self.nulls.finish())?;
1679        Ok(Arc::new(fixed_size_list_array))
1680    }
1681}
1682
1683/// Builder for creating VariantArray output (for path extraction without type conversion)
1684pub(crate) struct VariantToBinaryVariantArrowRowBuilder {
1685    metadata: ArrayRef,
1686    builder: VariantValueArrayBuilder,
1687    nulls: NullBufferBuilder,
1688}
1689
1690impl VariantToBinaryVariantArrowRowBuilder {
1691    fn new(metadata: ArrayRef, capacity: usize) -> Self {
1692        Self {
1693            metadata,
1694            builder: VariantValueArrayBuilder::new(capacity),
1695            nulls: NullBufferBuilder::new(capacity),
1696        }
1697    }
1698}
1699
1700impl VariantToBinaryVariantArrowRowBuilder {
1701    fn append_null(&mut self) -> Result<()> {
1702        self.builder.append_null();
1703        self.nulls.append_null();
1704        Ok(())
1705    }
1706
1707    fn append_value(&mut self, value: Variant<'_, '_>) -> Result<bool> {
1708        self.builder.append_value(value);
1709        self.nulls.append_non_null();
1710        Ok(true)
1711    }
1712
1713    fn finish(mut self) -> Result<ArrayRef> {
1714        // value-nulls are appended only alongside parent nulls, so the non-nullable
1715        // `value` annotation is always valid here
1716        let variant_array = VariantArray::from_parts_unshredded(
1717            self.metadata,
1718            Arc::new(self.builder.build()?),
1719            self.nulls.finish(),
1720        );
1721
1722        Ok(ArrayRef::from(variant_array))
1723    }
1724}
1725
1726#[derive(Default)]
1727struct FakeNullBuilder {
1728    item_count: usize,
1729}
1730
1731impl FakeNullBuilder {
1732    fn append_value(&mut self, (): ()) {
1733        self.item_count += 1;
1734    }
1735
1736    fn append_null(&mut self) {
1737        self.item_count += 1;
1738    }
1739
1740    fn finish(self) -> NullArray {
1741        NullArray::new(self.item_count)
1742    }
1743}
1744
1745define_variant_to_primitive_builder!(
1746    struct VariantToNullArrowRowBuilder<'a>
1747    |_capacity| -> FakeNullBuilder { FakeNullBuilder::default() },
1748    |value| value.as_null(),
1749    type_name: "Null"
1750);
1751
1752#[cfg(test)]
1753mod tests {
1754    use super::{
1755        make_primitive_variant_to_arrow_row_builder, make_typed_variant_to_arrow_row_builder,
1756    };
1757    use crate::type_conversion::VariantCastMode;
1758    use arrow::array::{
1759        Array, Decimal32Array, FixedSizeBinaryArray, Int32Array, ListArray, StructArray,
1760    };
1761    use arrow::compute::CastOptions;
1762    use arrow::datatypes::{DataType, Field, Fields, UnionFields, UnionMode};
1763    use arrow::error::ArrowError;
1764    use parquet_variant::{Variant, VariantDecimal4};
1765    use std::sync::Arc;
1766    use uuid::Uuid;
1767
1768    #[test]
1769    fn make_primitive_builder_rejects_non_primitive_types() {
1770        let cast_options = CastOptions::default();
1771        let item_field = Arc::new(Field::new("item", DataType::Int32, true));
1772        let struct_fields = Fields::from(vec![Field::new("child", DataType::Int32, true)]);
1773        let map_entries_field = Arc::new(Field::new(
1774            Field::MAP_ENTRIES_FIELD_DEFAULT_NAME,
1775            DataType::Struct(Fields::from(vec![
1776                Field::new(Field::MAP_KEY_FIELD_DEFAULT_NAME, DataType::Utf8, false),
1777                Field::new(Field::MAP_VALUE_FIELD_DEFAULT_NAME, DataType::Float64, true),
1778            ])),
1779            true,
1780        ));
1781        let union_fields =
1782            UnionFields::try_new(vec![1], vec![Field::new("child", DataType::Int32, true)])
1783                .unwrap();
1784        let run_ends_field = Arc::new(Field::new(
1785            Field::REE_RUN_ENDS_FIELD_DEFAULT_NAME,
1786            DataType::Int32,
1787            false,
1788        ));
1789        let ree_values_field = Arc::new(Field::new(
1790            Field::REE_VALUES_FIELD_DEFAULT_NAME,
1791            DataType::Utf8,
1792            true,
1793        ));
1794
1795        let non_primitive_types = vec![
1796            DataType::List(item_field.clone()),
1797            DataType::LargeList(item_field.clone()),
1798            DataType::ListView(item_field.clone()),
1799            DataType::LargeListView(item_field.clone()),
1800            DataType::FixedSizeList(item_field.clone(), 2),
1801            DataType::Struct(struct_fields.clone()),
1802            DataType::Map(map_entries_field.clone(), false),
1803            DataType::Union(union_fields.clone(), UnionMode::Dense),
1804            DataType::Dictionary(Box::new(DataType::Int32), Box::new(DataType::Utf8)),
1805            DataType::RunEndEncoded(run_ends_field.clone(), ree_values_field.clone()),
1806        ];
1807
1808        for data_type in non_primitive_types {
1809            let Err(err) = make_primitive_variant_to_arrow_row_builder(
1810                &data_type,
1811                &cast_options,
1812                1,
1813                VariantCastMode::Get,
1814            ) else {
1815                panic!("non-primitive type {data_type:?} should be rejected")
1816            };
1817
1818            match err {
1819                ArrowError::InvalidArgumentError(msg) => {
1820                    assert!(msg.contains(&format!("{data_type:?}")));
1821                }
1822                other => panic!("expected InvalidArgumentError, got {other:?}"),
1823            }
1824        }
1825    }
1826
1827    #[test]
1828    fn strict_cast_allows_variant_null_for_primitive_builder() {
1829        let cast_options = CastOptions {
1830            safe: false,
1831            ..Default::default()
1832        };
1833        let mut builder = make_primitive_variant_to_arrow_row_builder(
1834            &DataType::Int32,
1835            &cast_options,
1836            2,
1837            VariantCastMode::Get,
1838        )
1839        .unwrap();
1840
1841        assert!(!builder.append_value(&Variant::Null).unwrap());
1842        assert!(builder.append_value(&Variant::Int32(42)).unwrap());
1843
1844        let array = builder.finish().unwrap();
1845        let int_array = array.as_any().downcast_ref::<Int32Array>().unwrap();
1846        assert!(int_array.is_null(0));
1847        assert_eq!(int_array.value(1), 42);
1848    }
1849
1850    #[test]
1851    fn strict_cast_allows_variant_null_for_decimal_builder() {
1852        let cast_options = CastOptions {
1853            safe: false,
1854            ..Default::default()
1855        };
1856        let mut builder = make_primitive_variant_to_arrow_row_builder(
1857            &DataType::Decimal32(9, 2),
1858            &cast_options,
1859            2,
1860            VariantCastMode::Get,
1861        )
1862        .unwrap();
1863        let decimal_variant: Variant<'_, '_> = VariantDecimal4::try_new(1234, 2).unwrap().into();
1864
1865        assert!(!builder.append_value(&Variant::Null).unwrap());
1866        assert!(builder.append_value(&decimal_variant).unwrap());
1867
1868        let array = builder.finish().unwrap();
1869        let decimal_array = array.as_any().downcast_ref::<Decimal32Array>().unwrap();
1870        assert!(decimal_array.is_null(0));
1871        assert_eq!(decimal_array.value(1), 1234);
1872    }
1873
1874    #[test]
1875    fn strict_cast_allows_variant_null_for_uuid_builder() {
1876        let cast_options = CastOptions {
1877            safe: false,
1878            ..Default::default()
1879        };
1880        let mut builder = make_primitive_variant_to_arrow_row_builder(
1881            &DataType::FixedSizeBinary(16),
1882            &cast_options,
1883            2,
1884            VariantCastMode::Get,
1885        )
1886        .unwrap();
1887        let uuid = Uuid::nil();
1888
1889        assert!(!builder.append_value(&Variant::Null).unwrap());
1890        assert!(builder.append_value(&Variant::Uuid(uuid)).unwrap());
1891
1892        let array = builder.finish().unwrap();
1893        let uuid_array = array
1894            .as_any()
1895            .downcast_ref::<FixedSizeBinaryArray>()
1896            .unwrap();
1897        assert!(uuid_array.is_null(0));
1898        assert_eq!(uuid_array.value(1), uuid.as_bytes());
1899    }
1900
1901    #[test]
1902    fn strict_cast_allows_variant_null_for_list_and_struct_builders() {
1903        let cast_options = CastOptions {
1904            safe: false,
1905            ..Default::default()
1906        };
1907
1908        let list_type = DataType::List(Arc::new(Field::new("item", DataType::Int64, true)));
1909        let mut list_builder = make_typed_variant_to_arrow_row_builder(
1910            &list_type,
1911            &cast_options,
1912            1,
1913            VariantCastMode::Get,
1914        )
1915        .unwrap();
1916        assert!(!list_builder.append_value(Variant::Null).unwrap());
1917        let list_array = list_builder.finish().unwrap();
1918        let list_array = list_array.as_any().downcast_ref::<ListArray>().unwrap();
1919        assert!(list_array.is_null(0));
1920
1921        let struct_type =
1922            DataType::Struct(Fields::from(vec![Field::new("a", DataType::Int32, true)]));
1923        let mut struct_builder = make_typed_variant_to_arrow_row_builder(
1924            &struct_type,
1925            &cast_options,
1926            1,
1927            VariantCastMode::Get,
1928        )
1929        .unwrap();
1930        assert!(!struct_builder.append_value(Variant::Null).unwrap());
1931        let struct_array = struct_builder.finish().unwrap();
1932        let struct_array = struct_array.as_any().downcast_ref::<StructArray>().unwrap();
1933        assert!(struct_array.is_null(0));
1934    }
1935}