1#![allow(clippy::redundant_closure_call)]
2use std::fmt::{Debug, Formatter, Result, Write};
3
4use super::PrimitiveArray;
5use crate::array::Array;
6use crate::array::fmt::write_vec;
7use crate::datatypes::{IntervalUnit, TimeUnit};
8use crate::temporal_conversions;
9use crate::types::{NativeType, days_ms, i256, months_days_ns};
10
11macro_rules! dyn_primitive {
12 ($array:expr, $ty:ty, $expr:expr) => {{
13 let array = ($array as &dyn Array)
14 .as_any()
15 .downcast_ref::<PrimitiveArray<$ty>>()
16 .unwrap();
17 Box::new(move |f, index| write!(f, "{}", $expr(array.value(index))))
18 }};
19}
20
21pub fn get_write_value<'a, T: NativeType, F: Write>(
22 array: &'a PrimitiveArray<T>,
23) -> Box<dyn Fn(&mut F, usize) -> Result + 'a> {
24 use crate::datatypes::ArrowDataType::*;
25 match array.dtype().to_logical_type() {
26 Int8 => Box::new(|f, index| write!(f, "{}", array.value(index))),
27 Int16 => Box::new(|f, index| write!(f, "{}", array.value(index))),
28 Int32 => Box::new(|f, index| write!(f, "{}", array.value(index))),
29 Int64 => Box::new(|f, index| write!(f, "{}", array.value(index))),
30 Int128 => Box::new(|f, index| write!(f, "{}", array.value(index))),
31 UInt8 => Box::new(|f, index| write!(f, "{}", array.value(index))),
32 UInt16 => Box::new(|f, index| write!(f, "{}", array.value(index))),
33 UInt32 => Box::new(|f, index| write!(f, "{}", array.value(index))),
34 UInt64 => Box::new(|f, index| write!(f, "{}", array.value(index))),
35 UInt128 => Box::new(|f, index| write!(f, "{}", array.value(index))),
36 Float16 => unreachable!(),
37 Float32 => Box::new(|f, index| write!(f, "{}", array.value(index))),
38 Float64 => Box::new(|f, index| write!(f, "{}", array.value(index))),
39 Date32 => {
40 dyn_primitive!(array, i32, temporal_conversions::date32_to_date)
41 },
42 Date64 => {
43 dyn_primitive!(array, i64, temporal_conversions::date64_to_date)
44 },
45 Time32(TimeUnit::Second) => {
46 dyn_primitive!(array, i32, temporal_conversions::time32s_to_time)
47 },
48 Time32(TimeUnit::Millisecond) => {
49 dyn_primitive!(array, i32, temporal_conversions::time32ms_to_time)
50 },
51 Time32(_) => unreachable!(), Time64(TimeUnit::Microsecond) => {
53 dyn_primitive!(array, i64, temporal_conversions::time64us_to_time)
54 },
55 Time64(TimeUnit::Nanosecond) => {
56 dyn_primitive!(array, i64, temporal_conversions::time64ns_to_time)
57 },
58 Time64(_) => unreachable!(), Timestamp(time_unit, tz) => {
60 if let Some(tz) = tz {
61 let timezone = temporal_conversions::parse_offset(tz.as_str());
62 match timezone {
63 Ok(timezone) => {
64 dyn_primitive!(array, i64, |time| {
65 temporal_conversions::timestamp_to_datetime(time, *time_unit, &timezone)
66 })
67 },
68 #[cfg(feature = "chrono-tz")]
69 Err(_) => {
70 let timezone = temporal_conversions::parse_offset_tz(tz.as_str());
71 match timezone {
72 Ok(timezone) => dyn_primitive!(array, i64, |time| {
73 temporal_conversions::timestamp_to_datetime(
74 time, *time_unit, &timezone,
75 )
76 }),
77 Err(_) => {
78 let tz = tz.clone();
79 Box::new(move |f, index| {
80 write!(f, "{} ({})", array.value(index), tz)
81 })
82 },
83 }
84 },
85 #[cfg(not(feature = "chrono-tz"))]
86 _ => {
87 let tz = tz.clone();
88 Box::new(move |f, index| write!(f, "{} ({})", array.value(index), tz))
89 },
90 }
91 } else {
92 dyn_primitive!(array, i64, |time| {
93 temporal_conversions::timestamp_to_naive_datetime(time, *time_unit)
94 })
95 }
96 },
97 Interval(IntervalUnit::YearMonth) => {
98 dyn_primitive!(array, i32, |x| format!("{x}m"))
99 },
100 Interval(IntervalUnit::DayTime) => {
101 dyn_primitive!(array, days_ms, |x: days_ms| format!(
102 "{}d{}ms",
103 x.days(),
104 x.milliseconds()
105 ))
106 },
107 Interval(IntervalUnit::MonthDayNano) => {
108 dyn_primitive!(array, months_days_ns, |x: months_days_ns| format!(
109 "{}m{}d{}ns",
110 x.months(),
111 x.days(),
112 x.ns()
113 ))
114 },
115 Duration(TimeUnit::Second) => dyn_primitive!(array, i64, |x| format!("{x}s")),
116 Duration(TimeUnit::Millisecond) => dyn_primitive!(array, i64, |x| format!("{x}ms")),
117 Duration(TimeUnit::Microsecond) => dyn_primitive!(array, i64, |x| format!("{x}us")),
118 Duration(TimeUnit::Nanosecond) => dyn_primitive!(array, i64, |x| format!("{x}ns")),
119 Decimal(_, scale) => {
120 let scale = *scale as u32;
122 let factor = 10i128.pow(scale);
123 let display = move |x: i128| {
124 let base = x / factor;
125 let decimals = (x - base * factor).abs();
126 format!("{base}.{decimals}")
127 };
128 dyn_primitive!(array, i128, display)
129 },
130 Decimal32(_, scale) => {
131 let scale = *scale as u32;
132 let factor = 10i32.pow(scale);
133 let display = move |x: i32| {
134 let base = x / factor;
135 let decimals = (x - base * factor).abs();
136 format!("{base}.{decimals}")
137 };
138 dyn_primitive!(array, i32, display)
139 },
140 Decimal64(_, scale) => {
141 let scale = *scale as u32;
142 let factor = 10i64.pow(scale);
143 let display = move |x: i64| {
144 let base = x / factor;
145 let decimals = (x - base * factor).abs();
146 format!("{base}.{decimals}")
147 };
148 dyn_primitive!(array, i64, display)
149 },
150 Decimal256(_, scale) => {
151 let scale = *scale as u32;
152 let factor = (ethnum::I256::ONE * 10).pow(scale);
153 let display = move |x: i256| {
154 let base = x.0 / factor;
155 let decimals = (x.0 - base * factor).abs();
156 format!("{base}.{decimals}")
157 };
158 dyn_primitive!(array, i256, display)
159 },
160 _ => unreachable!(),
161 }
162}
163
164impl<T: NativeType> Debug for PrimitiveArray<T> {
165 fn fmt(&self, f: &mut Formatter<'_>) -> Result {
166 let writer = get_write_value(self);
167
168 write!(f, "{:?}", self.dtype())?;
169 write_vec(f, &*writer, self.validity(), self.len(), "None", false)
170 }
171}