polars_arrow/array/primitive/
fmt.rs

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!(), // remaining are not valid
52        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!(), // remaining are not valid
59        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            // The number 999.99 has a precision of 5 and scale of 2
121            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}