Skip to main content

parquet_variant_compute/
variant_to_arrow.rs

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