1use arrow::array::ArrowNativeTypeOp;
8use arrow::compute::kernels::cast_utils::parse_decimal;
9use arrow::compute::{
10 CastOptions, DecimalCast, cast_num_to_bool, cast_single_string_to_boolean_default,
11 float_to_decimal_opt, num_cast, rescale_decimal, single_bool_to_numeric,
12 single_decimal_to_float_lossy,
13};
14use arrow::datatypes::{
15 self, ArrowPrimitiveType, ArrowTimestampType, Decimal32Type, Decimal64Type, Decimal128Type,
16 Decimal256Type, DecimalType,
17};
18use arrow::error::{ArrowError, Result};
19use chrono::{DateTime, NaiveDate, NaiveDateTime, NaiveTime, Timelike, Utc};
20use half::f16;
21use num_traits::NumCast;
22use parquet_variant::{Variant, VariantDecimal4, VariantDecimal8, VariantDecimal16};
23
24#[derive(Debug, Clone, Copy)]
26pub(crate) enum VariantCastMode {
27 Shred,
29 Get,
31}
32
33pub(crate) trait PrimitiveFromVariant: ArrowPrimitiveType {
35 fn from_variant(variant: &Variant<'_, '_>, cast_mode: VariantCastMode) -> Option<Self::Native>;
36}
37
38pub(crate) trait TimestampFromVariant<const NTZ: bool>: ArrowTimestampType {
42 fn from_variant(variant: &Variant<'_, '_>, cast_mode: VariantCastMode) -> Option<Self::Native>;
43}
44
45pub(crate) fn variant_cast_with_options<'a, 'm, 'v, T>(
51 variant: &'a Variant<'m, 'v>,
52 cast_options: &CastOptions<'_>,
53 cast: impl FnOnce(&'a Variant<'m, 'v>) -> Option<T>,
54) -> Result<Option<T>> {
55 if let Some(value) = cast(variant) {
56 Ok(Some(value))
57 } else if matches!(variant, Variant::Null) || cast_options.safe {
58 Ok(None)
59 } else {
60 Err(ArrowError::CastError(format!(
61 "Failed to cast variant value {variant:?}"
62 )))
63 }
64}
65
66macro_rules! impl_primitive_from_variant {
68 ($arrow_type:ty, $shred_fun:expr, $get_method:ident $(, $cast_fn:expr)?) => {
69 impl PrimitiveFromVariant for $arrow_type {
70 fn from_variant(variant: &Variant<'_, '_>, cast_mode: VariantCastMode) -> Option<Self::Native> {
71 let value = match cast_mode {
72 VariantCastMode::Shred => $shred_fun(variant),
73 VariantCastMode::Get => $get_method(variant),
74 };
75 $( let value = value.and_then($cast_fn); )?
76 value
77 }
78 }
79 };
80}
81
82macro_rules! impl_timestamp_from_variant {
83 ($timestamp_type:ty, $shred_fun:expr, $variant_method:expr, ntz=$ntz:ident, $cast_fn:expr $(,)?) => {
84 impl TimestampFromVariant<{ $ntz }> for $timestamp_type {
85 fn from_variant(
86 variant: &Variant<'_, '_>,
87 cast_mode: VariantCastMode,
88 ) -> Option<Self::Native> {
89 let value = match cast_mode {
90 VariantCastMode::Shred => ($shred_fun)(variant),
91 VariantCastMode::Get => $variant_method(variant),
92 };
93
94 value.and_then($cast_fn)
95 }
96 }
97 };
98}
99
100fn convert_to_timestamp_nano(value: &Variant) -> Option<DateTime<Utc>> {
101 match *value {
102 Variant::TimestampNanos(d) | Variant::TimestampMicros(d) => Some(d),
103 _ => None,
104 }
105}
106
107fn convert_to_timestamp_ntz_nano(value: &Variant) -> Option<NaiveDateTime> {
108 match *value {
109 Variant::TimestampNtzNanos(d) | Variant::TimestampNtzMicros(d) => Some(d),
110 _ => None,
111 }
112}
113
114enum NumericKind {
115 Integer,
116 Float,
117}
118
119trait DecimalCastTarget: NumCast + Default {
120 const KIND: NumericKind;
121}
122
123macro_rules! impl_decimal_cast_target {
124 ($raw_type: ident, $target_kind:expr) => {
125 impl DecimalCastTarget for $raw_type {
126 const KIND: NumericKind = $target_kind;
127 }
128 };
129}
130
131impl_decimal_cast_target!(i8, NumericKind::Integer);
132impl_decimal_cast_target!(i16, NumericKind::Integer);
133impl_decimal_cast_target!(i32, NumericKind::Integer);
134impl_decimal_cast_target!(i64, NumericKind::Integer);
135impl_decimal_cast_target!(u8, NumericKind::Integer);
136impl_decimal_cast_target!(u16, NumericKind::Integer);
137impl_decimal_cast_target!(u32, NumericKind::Integer);
138impl_decimal_cast_target!(u64, NumericKind::Integer);
139impl_decimal_cast_target!(f16, NumericKind::Float);
140impl_decimal_cast_target!(f32, NumericKind::Float);
141impl_decimal_cast_target!(f64, NumericKind::Float);
142
143fn as_num<T>(variant: &Variant) -> Option<T>
149where
150 T: DecimalCastTarget,
151{
152 match *variant {
153 Variant::BooleanFalse => single_bool_to_numeric(false),
154 Variant::BooleanTrue => single_bool_to_numeric(true),
155 Variant::Int8(i) => num_cast(i),
156 Variant::Int16(i) => num_cast(i),
157 Variant::Int32(i) => num_cast(i),
158 Variant::Int64(i) => num_cast(i),
159 Variant::Float(f) => num_cast(f),
160 Variant::Double(d) => num_cast(d),
161 Variant::Decimal4(d) => {
162 cast_decimal_to_num::<Decimal32Type, T, _>(d.integer(), d.scale(), |x| x as f64)
163 }
164 Variant::Decimal8(d) => {
165 cast_decimal_to_num::<Decimal64Type, T, _>(d.integer(), d.scale(), |x| x as f64)
166 }
167 Variant::Decimal16(d) => {
168 cast_decimal_to_num::<Decimal128Type, T, _>(d.integer(), d.scale(), |x| x as f64)
169 }
170 _ => None,
171 }
172}
173
174fn cast_decimal_to_num<D, T, F>(raw: D::Native, scale: u8, as_float: F) -> Option<T>
175where
176 D: DecimalType,
177 D::Native: NumCast + ArrowNativeTypeOp,
178 T: DecimalCastTarget,
179 F: Fn(D::Native) -> f64,
180{
181 let base: D::Native = NumCast::from(10)?;
182
183 let div = base.pow_checked(<u32 as From<u8>>::from(scale)).ok()?;
184 match T::KIND {
185 NumericKind::Integer => raw
186 .div_checked(div)
187 .ok()
188 .and_then(<T as NumCast>::from::<D::Native>),
189 NumericKind::Float => T::from(single_decimal_to_float_lossy::<D, _>(
190 &as_float,
191 raw,
192 <i32 as From<u8>>::from(scale),
193 )),
194 }
195}
196
197fn cast_naive_date(value: &Variant<'_, '_>) -> Option<NaiveDate> {
198 value.as_naive_date()
199}
200
201fn cast_time_utc(value: &Variant<'_, '_>) -> Option<NaiveTime> {
202 value.as_time_utc()
203}
204
205fn always_none<T>(_input: &Variant) -> Option<T> {
207 None
208}
209
210impl_primitive_from_variant!(datatypes::Int32Type, Variant::as_int32, as_num);
211impl_primitive_from_variant!(datatypes::Int16Type, Variant::as_int16, as_num);
212impl_primitive_from_variant!(datatypes::Int8Type, Variant::as_int8, as_num);
213impl_primitive_from_variant!(datatypes::Int64Type, Variant::as_int64, as_num);
214impl_primitive_from_variant!(datatypes::UInt8Type, always_none, as_num);
215impl_primitive_from_variant!(datatypes::UInt16Type, always_none, as_num);
216impl_primitive_from_variant!(datatypes::UInt32Type, always_none, as_num);
217impl_primitive_from_variant!(datatypes::UInt64Type, always_none, as_num);
218impl_primitive_from_variant!(datatypes::Float16Type, always_none, as_num);
219impl_primitive_from_variant!(datatypes::Float32Type, Variant::as_f32, as_num);
220impl_primitive_from_variant!(datatypes::Float64Type, Variant::as_f64, as_num);
221impl_primitive_from_variant!(
222 datatypes::Date32Type,
223 Variant::as_naive_date,
224 cast_naive_date,
225 |v| { Some(datatypes::Date32Type::from_naive_date(v)) }
226);
227impl_primitive_from_variant!(
228 datatypes::Date64Type,
229 Variant::as_naive_date,
230 cast_naive_date,
231 |v| { Some(datatypes::Date64Type::from_naive_date(v)) }
232);
233impl_primitive_from_variant!(
234 datatypes::Time32SecondType,
235 always_none, cast_time_utc,
237 |v| {
238 if v.nanosecond() != 0 {
240 None
241 } else {
242 Some(v.num_seconds_from_midnight() as i32)
243 }
244 }
245);
246impl_primitive_from_variant!(
247 datatypes::Time32MillisecondType,
248 always_none, cast_time_utc,
250 |v| {
251 if v.nanosecond() % 1_000_000 != 0 {
253 None
254 } else {
255 Some(
256 (v.num_seconds_from_midnight() * 1_000) as i32
257 + (v.nanosecond() / 1_000_000) as i32,
258 )
259 }
260 }
261);
262impl_primitive_from_variant!(
263 datatypes::Time64MicrosecondType,
264 Variant::as_time_utc,
265 cast_time_utc,
266 |v| { Some(v.num_seconds_from_midnight() as i64 * 1_000_000 + v.nanosecond() as i64 / 1_000) }
267);
268impl_primitive_from_variant!(
269 datatypes::Time64NanosecondType,
270 always_none, cast_time_utc,
272 |v| {
273 Some(v.num_seconds_from_midnight() as i64 * 1_000_000_000 + v.nanosecond() as i64)
275 }
276);
277impl_timestamp_from_variant!(
278 datatypes::TimestampSecondType,
279 always_none, convert_to_timestamp_ntz_nano,
281 ntz = true,
282 |timestamp| {
283 if timestamp.nanosecond() != 0 {
285 None
286 } else {
287 Self::from_naive_datetime(timestamp, None)
288 }
289 }
290);
291impl_timestamp_from_variant!(
292 datatypes::TimestampSecondType,
293 always_none, convert_to_timestamp_nano,
295 ntz = false,
296 |timestamp| {
297 if timestamp.nanosecond() != 0 {
299 None
300 } else {
301 Self::from_naive_datetime(timestamp.naive_utc(), None)
302 }
303 }
304);
305impl_timestamp_from_variant!(
306 datatypes::TimestampMillisecondType,
307 always_none, convert_to_timestamp_ntz_nano,
309 ntz = true,
310 |timestamp| {
311 if timestamp.nanosecond() % 1_000_000 != 0 {
313 None
314 } else {
315 Self::from_naive_datetime(timestamp, None)
316 }
317 }
318);
319impl_timestamp_from_variant!(
320 datatypes::TimestampMillisecondType,
321 always_none, convert_to_timestamp_nano,
323 ntz = false,
324 |timestamp| {
325 if timestamp.nanosecond() % 1_000_000 != 0 {
327 None
328 } else {
329 Self::from_naive_datetime(timestamp.naive_utc(), None)
330 }
331 }
332);
333impl_timestamp_from_variant!(
334 datatypes::TimestampMicrosecondType,
335 Variant::as_timestamp_ntz_micros,
336 Variant::as_timestamp_ntz_micros,
337 ntz = true,
338 |timestamp| Self::from_naive_datetime(timestamp, None),
339);
340impl_timestamp_from_variant!(
341 datatypes::TimestampMicrosecondType,
342 Variant::as_timestamp_micros,
343 Variant::as_timestamp_micros,
344 ntz = false,
345 |timestamp| Self::from_naive_datetime(timestamp.naive_utc(), None)
346);
347impl_timestamp_from_variant!(
348 datatypes::TimestampNanosecondType,
349 Variant::as_timestamp_ntz_nanos,
350 convert_to_timestamp_ntz_nano,
351 ntz = true,
352 |timestamp| Self::from_naive_datetime(timestamp, None)
353);
354impl_timestamp_from_variant!(
355 datatypes::TimestampNanosecondType,
356 Variant::as_timestamp_nanos,
357 convert_to_timestamp_nano,
358 ntz = false,
359 |timestamp| Self::from_naive_datetime(timestamp.naive_utc(), None)
360);
361
362pub(crate) fn variant_to_unscaled_decimal<O>(
375 variant: &Variant<'_, '_>,
376 precision: u8,
377 scale: i8,
378) -> Option<O::Native>
379where
380 O: DecimalType,
381 O::Native: DecimalCast,
382{
383 match variant {
384 Variant::Int8(i) => rescale_decimal::<Decimal32Type, O>(
385 *i as i32,
386 VariantDecimal4::MAX_PRECISION,
387 0,
388 precision,
389 scale,
390 ),
391 Variant::Int16(i) => rescale_decimal::<Decimal32Type, O>(
392 *i as i32,
393 VariantDecimal4::MAX_PRECISION,
394 0,
395 precision,
396 scale,
397 ),
398 Variant::Int32(i) => rescale_decimal::<Decimal32Type, O>(
399 *i,
400 VariantDecimal4::MAX_PRECISION,
401 0,
402 precision,
403 scale,
404 ),
405 Variant::Int64(i) => rescale_decimal::<Decimal64Type, O>(
406 *i,
407 VariantDecimal8::MAX_PRECISION,
408 0,
409 precision,
410 scale,
411 ),
412 Variant::Float(f) => {
413 float_to_decimal_opt::<O>(<f64 as From<f32>>::from(*f), precision, scale)
414 }
415 Variant::Double(f) => float_to_decimal_opt::<O>(*f, precision, scale),
416 Variant::String(v) => parse_decimal::<O>(v, precision, scale).ok(),
417 Variant::ShortString(v) => parse_decimal::<O>(v, precision, scale).ok(),
418 Variant::Decimal4(d) => rescale_decimal::<Decimal32Type, O>(
419 d.integer(),
420 VariantDecimal4::MAX_PRECISION,
421 d.scale() as i8,
422 precision,
423 scale,
424 ),
425 Variant::Decimal8(d) => rescale_decimal::<Decimal64Type, O>(
426 d.integer(),
427 VariantDecimal8::MAX_PRECISION,
428 d.scale() as i8,
429 precision,
430 scale,
431 ),
432 Variant::Decimal16(d) => rescale_decimal::<Decimal128Type, O>(
433 d.integer(),
434 VariantDecimal16::MAX_PRECISION,
435 d.scale() as i8,
436 precision,
437 scale,
438 ),
439 _ => None,
440 }
441}
442
443pub(crate) fn shred_variant_to_unscaled_decimal<O>(
449 variant: &Variant<'_, '_>,
450 precision: u8,
451 scale: i8,
452) -> Option<O::Native>
453where
454 O: ShredDecimalVariant,
455 O::Native: DecimalCast,
456{
457 match variant {
458 Variant::Int8(_)
459 | Variant::Int16(_)
460 | Variant::Int32(_)
461 | Variant::Int64(_)
462 | Variant::Decimal4(_)
463 | Variant::Decimal8(_)
464 | Variant::Decimal16(_) => O::shred_variant(variant, precision, scale),
465 _ => None,
466 }
467}
468pub(crate) trait ShredDecimalVariant: DecimalType {
469 fn shred_variant(value: &Variant<'_, '_>, precision: u8, scale: i8) -> Option<Self::Native>;
470}
471
472fn convert_to_unscaled_decimal<I, O>(
473 input: I::Native,
474 input_precision: u8,
475 input_scale: i8,
476 target_precision: u8,
477 target_scale: i8,
478) -> Option<O::Native>
479where
480 I: DecimalType,
481 O: DecimalType,
482 I::Native: DecimalCast,
483 O::Native: DecimalCast,
484{
485 let converted = rescale_decimal::<I, O>(
486 input,
487 input_precision,
488 input_scale,
489 target_precision,
490 target_scale,
491 )?;
492
493 let converted_back = rescale_decimal::<O, I>(
494 converted,
495 target_precision,
496 target_scale,
497 input_precision,
498 input_scale,
499 )?;
500 if converted_back == input {
501 return Some(converted);
502 }
503
504 None
505}
506
507impl ShredDecimalVariant for Decimal32Type {
508 fn shred_variant(value: &Variant<'_, '_>, precision: u8, scale: i8) -> Option<Self::Native> {
509 match *value {
510 Variant::Int8(i) => convert_to_unscaled_decimal::<Decimal32Type, Decimal32Type>(
511 i as i32,
512 VariantDecimal4::MAX_PRECISION,
513 0,
514 precision,
515 scale,
516 ),
517 Variant::Int16(i) => convert_to_unscaled_decimal::<Decimal32Type, Decimal32Type>(
518 i as i32,
519 VariantDecimal4::MAX_PRECISION,
520 0,
521 precision,
522 scale,
523 ),
524 Variant::Int32(i) => convert_to_unscaled_decimal::<Decimal32Type, Decimal32Type>(
525 i,
526 VariantDecimal4::MAX_PRECISION,
527 0,
528 precision,
529 scale,
530 ),
531 Variant::Int64(i) => {
532 let i32_value = <i64 as TryInto<i32>>::try_into(i).ok()?;
533 convert_to_unscaled_decimal::<Decimal32Type, Decimal32Type>(
534 i32_value,
535 VariantDecimal4::MAX_PRECISION,
536 0,
537 precision,
538 scale,
539 )
540 }
541 Variant::Decimal4(d) => convert_to_unscaled_decimal::<Decimal32Type, Decimal32Type>(
542 d.integer(),
543 VariantDecimal4::MAX_PRECISION,
544 d.scale() as i8,
545 precision,
546 scale,
547 ),
548 Variant::Decimal8(d) => convert_to_unscaled_decimal::<Decimal64Type, Decimal32Type>(
549 d.integer(),
550 VariantDecimal8::MAX_PRECISION,
551 d.scale() as i8,
552 precision,
553 scale,
554 ),
555 Variant::Decimal16(d) => convert_to_unscaled_decimal::<Decimal128Type, Decimal32Type>(
556 d.integer(),
557 VariantDecimal16::MAX_PRECISION,
558 d.scale() as i8,
559 precision,
560 scale,
561 ),
562 _ => None,
563 }
564 }
565}
566
567impl ShredDecimalVariant for Decimal64Type {
568 fn shred_variant(value: &Variant<'_, '_>, precision: u8, scale: i8) -> Option<Self::Native> {
569 match *value {
570 Variant::Int8(i) => convert_to_unscaled_decimal::<Decimal64Type, Decimal64Type>(
571 i as i64,
572 VariantDecimal8::MAX_PRECISION,
573 0,
574 precision,
575 scale,
576 ),
577 Variant::Int16(i) => convert_to_unscaled_decimal::<Decimal64Type, Decimal64Type>(
578 i as i64,
579 VariantDecimal8::MAX_PRECISION,
580 0,
581 precision,
582 scale,
583 ),
584 Variant::Int32(i) => convert_to_unscaled_decimal::<Decimal64Type, Decimal64Type>(
585 i as i64,
586 VariantDecimal8::MAX_PRECISION,
587 0,
588 precision,
589 scale,
590 ),
591 Variant::Int64(i) => convert_to_unscaled_decimal::<Decimal64Type, Decimal64Type>(
592 i,
593 VariantDecimal8::MAX_PRECISION,
594 0,
595 precision,
596 scale,
597 ),
598 Variant::Decimal4(d) => convert_to_unscaled_decimal::<Decimal32Type, Decimal64Type>(
599 d.integer(),
600 VariantDecimal4::MAX_PRECISION,
601 d.scale() as i8,
602 precision,
603 scale,
604 ),
605 Variant::Decimal8(d) => convert_to_unscaled_decimal::<Decimal64Type, Decimal64Type>(
606 d.integer(),
607 VariantDecimal8::MAX_PRECISION,
608 d.scale() as i8,
609 precision,
610 scale,
611 ),
612 Variant::Decimal16(d) => convert_to_unscaled_decimal::<Decimal128Type, Decimal64Type>(
613 d.integer(),
614 VariantDecimal16::MAX_PRECISION,
615 d.scale() as i8,
616 precision,
617 scale,
618 ),
619 _ => None,
620 }
621 }
622}
623
624impl ShredDecimalVariant for Decimal128Type {
625 fn shred_variant(value: &Variant<'_, '_>, precision: u8, scale: i8) -> Option<Self::Native> {
626 match *value {
627 Variant::Int8(i) => convert_to_unscaled_decimal::<Decimal128Type, Decimal128Type>(
628 i as i128,
629 VariantDecimal4::MAX_PRECISION,
630 0,
631 precision,
632 scale,
633 ),
634 Variant::Int16(i) => convert_to_unscaled_decimal::<Decimal128Type, Decimal128Type>(
635 i as i128,
636 VariantDecimal4::MAX_PRECISION,
637 0,
638 precision,
639 scale,
640 ),
641 Variant::Int32(i) => convert_to_unscaled_decimal::<Decimal128Type, Decimal128Type>(
642 i as i128,
643 VariantDecimal4::MAX_PRECISION,
644 0,
645 precision,
646 scale,
647 ),
648 Variant::Int64(i) => convert_to_unscaled_decimal::<Decimal128Type, Decimal128Type>(
649 i as i128,
650 VariantDecimal4::MAX_PRECISION,
651 0,
652 precision,
653 scale,
654 ),
655 Variant::Decimal4(d) => convert_to_unscaled_decimal::<Decimal32Type, Decimal128Type>(
656 d.integer(),
657 VariantDecimal4::MAX_PRECISION,
658 d.scale() as i8,
659 precision,
660 scale,
661 ),
662 Variant::Decimal8(d) => convert_to_unscaled_decimal::<Decimal64Type, Decimal128Type>(
663 d.integer(),
664 VariantDecimal8::MAX_PRECISION,
665 d.scale() as i8,
666 precision,
667 scale,
668 ),
669 Variant::Decimal16(d) => convert_to_unscaled_decimal::<Decimal128Type, Decimal128Type>(
670 d.integer(),
671 VariantDecimal16::MAX_PRECISION,
672 d.scale() as i8,
673 precision,
674 scale,
675 ),
676 _ => None,
677 }
678 }
679}
680
681impl ShredDecimalVariant for Decimal256Type {
682 fn shred_variant(_value: &Variant<'_, '_>, _precision: u8, _scale: i8) -> Option<Self::Native> {
683 None }
685}
686
687pub(crate) fn variant_to_boolean(
688 variant: &Variant<'_, '_>,
689 cast_mode: VariantCastMode,
690) -> Option<bool> {
691 if matches!(cast_mode, VariantCastMode::Shred) {
692 return variant.as_boolean();
693 }
694
695 match variant {
696 Variant::BooleanTrue => Some(true),
697 Variant::BooleanFalse => Some(false),
698 Variant::Int8(i) => Some(cast_num_to_bool(*i)),
699 Variant::Int16(i) => Some(cast_num_to_bool(*i)),
700 Variant::Int32(i) => Some(cast_num_to_bool(*i)),
701 Variant::Int64(i) => Some(cast_num_to_bool(*i)),
702 Variant::Float(f) => Some(cast_num_to_bool(*f)),
703 Variant::Double(d) => Some(cast_num_to_bool(*d)),
704 Variant::ShortString(s) => cast_single_string_to_boolean_default(s.as_str()),
705 Variant::String(s) => cast_single_string_to_boolean_default(s),
706 _ => None,
707 }
708}
709
710macro_rules! non_generic_conversion_single_value {
712 ($array:expr, $cast_fn:expr, $index:expr) => {{
713 let array = $array;
714 if array.is_null($index) {
715 Ok(Variant::Null)
716 } else {
717 let cast_value = $cast_fn(array.value($index));
718 Ok(Variant::from(cast_value))
719 }
720 }};
721}
722pub(crate) use non_generic_conversion_single_value;
723
724macro_rules! generic_conversion_single_value {
728 ($t:ty, $method:ident, $cast_fn:expr, $input:expr, $index:expr) => {{
729 $crate::type_conversion::non_generic_conversion_single_value!(
730 $input.$method::<$t>(),
731 $cast_fn,
732 $index
733 )
734 }};
735}
736pub(crate) use generic_conversion_single_value;
737
738macro_rules! generic_conversion_single_value_with_result {
739 ($t:ty, $method:ident, $cast_fn:expr, $input:expr, $index:expr) => {{
740 let arr = $input.$method::<$t>();
741 let v = arr.value($index);
742 match ($cast_fn)(v) {
743 Ok(var) => Ok(Variant::from(var)),
744 Err(e) => Err(ArrowError::CastError(format!(
745 "Cast failed at index {idx} (array type: {ty}): {e}",
746 idx = $index,
747 ty = <$t as ::arrow::datatypes::ArrowPrimitiveType>::DATA_TYPE
748 ))),
749 }
750 }};
751}
752
753pub(crate) use generic_conversion_single_value_with_result;
754
755macro_rules! primitive_conversion_single_value {
757 ($t:ty, $input:expr, $index:expr) => {{
758 $crate::type_conversion::generic_conversion_single_value!(
759 $t,
760 as_primitive,
761 |v| v,
762 $input,
763 $index
764 )
765 }};
766}
767pub(crate) use primitive_conversion_single_value;