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