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