## Coverage Report

#### Created: 2025-08-26 07:03

next uncovered line (L), next uncovered region (R), next uncovered branch (B)

    /Users/andrewlamb/Software/arrow-rs/arrow-cast/src/display.rs

    Line
    Count
    Source
    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
    18
    //! Functions for printing array values as human-readable strings.
    19
    //!
    20
    //! This is often used for debugging or logging purposes.
    21
    //!
    22
    //! See the [`pretty`] crate for additional functions for
    23
    //! record batch pretty printing.
    24
    //!
    25
    //! [`pretty`]: crate::pretty
    26
    use std::fmt::{Display, Formatter, Write};
    27
    use std::ops::Range;
    28
    29
    use arrow_array::cast::*;
    30
    use arrow_array::temporal_conversions::*;
    31
    use arrow_array::timezone::Tz;
    32
    use arrow_array::types::*;
    33
    use arrow_array::*;
    34
    use arrow_buffer::ArrowNativeType;
    35
    use arrow_schema::*;
    36
    use chrono::{NaiveDate, NaiveDateTime, SecondsFormat, TimeZone, Utc};
    37
    use lexical_core::FormattedSize;
    38
    39
    type TimeFormat<'a> = Option<&'a str>;
    40
    41
    /// Format for displaying durations
    42
    #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
    43
    #[non_exhaustive]
    44
    pub enum DurationFormat {
    45
        /// ISO 8601 - `P198DT72932.972880S`
    46
        ISO8601,
    47
        /// A human readable representation - `198 days 16 hours 34 mins 15.407810000 secs`
    48
        Pretty,
    49
    }
    50
    51
    /// Options for formatting arrays
    52
    ///
    53
    /// By default nulls are formatted as `""` and temporal types formatted
    54
    /// according to RFC3339
    55
    ///
    56
    #[derive(Debug, Clone, PartialEq, Eq, Hash)]
    57
    pub struct FormatOptions<'a> {
    58
        /// If set to `true` any formatting errors will be written to the output
    59
        /// instead of being converted into a [`std::fmt::Error`]
    60
        safe: bool,
    61
        /// Format string for nulls
    62
        null: &'a str,
    63
        /// Date format for date arrays
    64
        date_format: TimeFormat<'a>,
    65
        /// Format for DateTime arrays
    66
        datetime_format: TimeFormat<'a>,
    67
        /// Timestamp format for timestamp arrays
    68
        timestamp_format: TimeFormat<'a>,
    69
        /// Timestamp format for timestamp with timezone arrays
    70
        timestamp_tz_format: TimeFormat<'a>,
    71
        /// Time format for time arrays
    72
        time_format: TimeFormat<'a>,
    73
        /// Duration format
    74
        duration_format: DurationFormat,
    75
        /// Show types in visual representation batches
    76
        types_info: bool,
    77
    }
    78
    79
    impl Default for FormatOptions<'_> {
    80
    0
        fn default() -> Self {
    81
    0
            Self::new()
    82
    0
        }
    83
    }
    84
    85
    impl<'a> FormatOptions<'a> {
    86
        /// Creates a new set of format options
    87
    0
        pub const fn new() -> Self {
    88
    0
            Self {
    89
    0
                safe: true,
    90
    0
                null: "",
    91
    0
                date_format: None,
    92
    0
                datetime_format: None,
    93
    0
                timestamp_format: None,
    94
    0
                timestamp_tz_format: None,
    95
    0
                time_format: None,
    96
    0
                duration_format: DurationFormat::ISO8601,
    97
    0
                types_info: false,
    98
    0
            }
    99
    0
        }
    100
    101
        /// If set to `true` any formatting errors will be written to the output
    102
        /// instead of being converted into a [`std::fmt::Error`]
    103
    0
        pub const fn with_display_error(mut self, safe: bool) -> Self {
    104
    0
            self.safe = safe;
    105
    0
            self
    106
    0
        }
    107
    108
        /// Overrides the string used to represent a null
    109
        ///
    110
        /// Defaults to `""`
    111
    0
        pub const fn with_null(self, null: &'a str) -> Self {
    112
    0
            Self { null, ..self }
    113
    0
        }
    114
    115
        /// Overrides the format used for [`DataType::Date32`] columns
    116
    0
        pub const fn with_date_format(self, date_format: Option<&'a str>) -> Self {
    117
    0
            Self {
    118
    0
                date_format,
    119
    0
                ..self
    120
    0
            }
    121
    0
        }
    122
    123
        /// Overrides the format used for [`DataType::Date64`] columns
    124
    0
        pub const fn with_datetime_format(self, datetime_format: Option<&'a str>) -> Self {
    125
    0
            Self {
    126
    0
                datetime_format,
    127
    0
                ..self
    128
    0
            }
    129
    0
        }
    130
    131
        /// Overrides the format used for [`DataType::Timestamp`] columns without a timezone
    132
    0
        pub const fn with_timestamp_format(self, timestamp_format: Option<&'a str>) -> Self {
    133
    0
            Self {
    134
    0
                timestamp_format,
    135
    0
                ..self
    136
    0
            }
    137
    0
        }
    138
    139
        /// Overrides the format used for [`DataType::Timestamp`] columns with a timezone
    140
    0
        pub const fn with_timestamp_tz_format(self, timestamp_tz_format: Option<&'a str>) -> Self {
    141
    0
            Self {
    142
    0
                timestamp_tz_format,
    143
    0
                ..self
    144
    0
            }
    145
    0
        }
    146
    147
        /// Overrides the format used for [`DataType::Time32`] and [`DataType::Time64`] columns
    148
    0
        pub const fn with_time_format(self, time_format: Option<&'a str>) -> Self {
    149
    0
            Self {
    150
    0
                time_format,
    151
    0
                ..self
    152
    0
            }
    153
    0
        }
    154
    155
        /// Overrides the format used for duration columns
    156
        ///
    157
        /// Defaults to [`DurationFormat::ISO8601`]
    158
    0
        pub const fn with_duration_format(self, duration_format: DurationFormat) -> Self {
    159
    0
            Self {
    160
    0
                duration_format,
    161
    0
                ..self
    162
    0
            }
    163
    0
        }
    164
    165
        /// Overrides if types should be shown
    166
        ///
    167
        /// Defaults to [`false`]
    168
    0
        pub const fn with_types_info(self, types_info: bool) -> Self {
    169
    0
            Self { types_info, ..self }
    170
    0
        }
    171
    172
        /// Returns true if type info should be included in visual representation of batches
    173
    0
        pub const fn types_info(&self) -> bool {
    174
    0
            self.types_info
    175
    0
        }
    176
    }
    177
    178
    /// Implements [`Display`] for a specific array value
    179
    pub struct ValueFormatter<'a> {
    180
        idx: usize,
    181
        formatter: &'a ArrayFormatter<'a>,
    182
    }
    183
    184
    impl ValueFormatter<'_> {
    185
        /// Writes this value to the provided [`Write`]
    186
        ///
    187
        /// Note: this ignores [`FormatOptions::with_display_error`] and
    188
        /// will return an error on formatting issue
    189
    0
        pub fn write(&self, s: &mut dyn Write) -> Result<(), ArrowError> {
    190
    0
            match self.formatter.format.write(self.idx, s) {
    191
    0
                Ok(_) => Ok(()),
    192
    0
                Err(FormatError::Arrow(e)) => Err(e),
    193
    0
                Err(FormatError::Format(_)) => Err(ArrowError::CastError("Format error".to_string())),
    194
            }
    195
    0
        }
    196
    197
        /// Fallibly converts this to a string
    198
    0
        pub fn try_to_string(&self) -> Result<String, ArrowError> {
    199
    0
            let mut s = String::new();
    200
    0
            self.write(&mut s)?;
    201
    0
            Ok(s)
    202
    0
        }
    203
    }
    204
    205
    impl Display for ValueFormatter<'_> {
    206
    0
        fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
    207
    0
            match self.formatter.format.write(self.idx, f) {
    208
    0
                Ok(()) => Ok(()),
    209
    0
                Err(FormatError::Arrow(e)) if self.formatter.safe => {
    210
    0
                    write!(f, "ERROR: {e}")
    211
                }
    212
    0
                Err(_) => Err(std::fmt::Error),
    213
            }
    214
    0
        }
    215
    }
    216
    217
    /// A string formatter for an [`Array`]
    218
    ///
    219
    /// This can be used with [`std::write`] to write type-erased `dyn Array`
    220
    ///
    221
    /// ```
    222
    /// # use std::fmt::{Display, Formatter, Write};
    223
    /// # use arrow_array::{Array, ArrayRef, Int32Array};
    224
    /// # use arrow_cast::display::{ArrayFormatter, FormatOptions};
    225
    /// # use arrow_schema::ArrowError;
    226
    /// struct MyContainer {
    227
    ///     values: ArrayRef,
    228
    /// }
    229
    ///
    230
    /// impl Display for MyContainer {
    231
    ///     fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
    232
    ///         let options = FormatOptions::default();
    233
    ///         let formatter = ArrayFormatter::try_new(self.values.as_ref(), &options)
    234
    ///             .map_err(|_| std::fmt::Error)?;
    235
    ///
    236
    ///         let mut iter = 0..self.values.len();
    237
    ///         if let Some(idx) = iter.next() {
    238
    ///             write!(f, "{}", formatter.value(idx))?;
    239
    ///         }
    240
    ///         for idx in iter {
    241
    ///             write!(f, ", {}", formatter.value(idx))?;
    242
    ///         }
    243
    ///         Ok(())
    244
    ///     }
    245
    /// }
    246
    /// ```
    247
    ///
    248
    /// [`ValueFormatter::write`] can also be used to get a semantic error, instead of the
    249
    /// opaque [`std::fmt::Error`]
    250
    ///
    251
    /// ```
    252
    /// # use std::fmt::Write;
    253
    /// # use arrow_array::Array;
    254
    /// # use arrow_cast::display::{ArrayFormatter, FormatOptions};
    255
    /// # use arrow_schema::ArrowError;
    256
    /// fn format_array(
    257
    ///     f: &mut dyn Write,
    258
    ///     array: &dyn Array,
    259
    ///     options: &FormatOptions,
    260
    /// ) -> Result<(), ArrowError> {
    261
    ///     let formatter = ArrayFormatter::try_new(array, options)?;
    262
    ///     for i in 0..array.len() {
    263
    ///         formatter.value(i).write(f)?
    264
    ///     }
    265
    ///     Ok(())
    266
    /// }
    267
    /// ```
    268
    ///
    269
    pub struct ArrayFormatter<'a> {
    270
        format: Box<dyn DisplayIndex + 'a>,
    271
        safe: bool,
    272
    }
    273
    274
    impl<'a> ArrayFormatter<'a> {
    275
        /// Returns an [`ArrayFormatter`] that can be used to format `array`
    276
        ///
    277
        /// This returns an error if an array of the given data type cannot be formatted
    278
    0
        pub fn try_new(array: &'a dyn Array, options: &FormatOptions<'a>) -> Result<Self, ArrowError> {
    279
            Ok(Self {
    280
    0
                format: make_formatter(array, options)?,
    281
    0
                safe: options.safe,
    282
            })
    283
    0
        }
    284
    285
        /// Returns a [`ValueFormatter`] that implements [`Display`] for
    286
        /// the value of the array at `idx`
    287
    0
        pub fn value(&self, idx: usize) -> ValueFormatter<'_> {
    288
    0
            ValueFormatter {
    289
    0
                formatter: self,
    290
    0
                idx,
    291
    0
            }
    292
    0
        }
    293
    }
    294
    295
    0
    fn make_formatter<'a>(
    296
    0
        array: &'a dyn Array,
    297
    0
        options: &FormatOptions<'a>,
    298
    0
    ) -> Result<Box<dyn DisplayIndex + 'a>, ArrowError> {
    299
    0
        downcast_primitive_array! {
    300
    0
            array => array_format(array, options),
    301
    0
            DataType::Null => array_format(as_null_array(array), options),
    302
    0
            DataType::Boolean => array_format(as_boolean_array(array), options),
    303
    0
            DataType::Utf8 => array_format(array.as_string::<i32>(), options),
    304
    0
            DataType::LargeUtf8 => array_format(array.as_string::<i64>(), options),
    305
    0
            DataType::Utf8View => array_format(array.as_string_view(), options),
    306
    0
            DataType::Binary => array_format(array.as_binary::<i32>(), options),
    307
    0
            DataType::BinaryView => array_format(array.as_binary_view(), options),
    308
    0
            DataType::LargeBinary => array_format(array.as_binary::<i64>(), options),
    309
            DataType::FixedSizeBinary(_) => {
    310
    0
                let a = array.as_any().downcast_ref::<FixedSizeBinaryArray>().unwrap();
    311
    0
                array_format(a, options)
    312
            }
    313
    0
            DataType::Dictionary(_, _) => downcast_dictionary_array! {
    314
    0
                array => array_format(array, options),
    315
    0
                _ => unreachable!()
    316
            }
    317
    0
            DataType::List(_) => array_format(as_generic_list_array::<i32>(array), options),
    318
    0
            DataType::LargeList(_) => array_format(as_generic_list_array::<i64>(array), options),
    319
            DataType::FixedSizeList(_, _) => {
    320
    0
                let a = array.as_any().downcast_ref::<FixedSizeListArray>().unwrap();
    321
    0
                array_format(a, options)
    322
            }
    323
    0
            DataType::Struct(_) => array_format(as_struct_array(array), options),
    324
    0
            DataType::Map(_, _) => array_format(as_map_array(array), options),
    325
    0
            DataType::Union(_, _) => array_format(as_union_array(array), options),
    326
    0
            DataType::RunEndEncoded(_, _) => downcast_run_array! {
    327
    0
                array => array_format(array, options),
    328
    0
                _ => unreachable!()
    329
            },
    330
    0
            d => Err(ArrowError::NotYetImplemented(format!("formatting {d} is not yet supported"))),
    331
        }
    332
    0
    }
    333
    334
    /// Either an [`ArrowError`] or [`std::fmt::Error`]
    335
    enum FormatError {
    336
        Format(std::fmt::Error),
    337
        Arrow(ArrowError),
    338
    }
    339
    340
    type FormatResult = Result<(), FormatError>;
    341
    342
    impl From<std::fmt::Error> for FormatError {
    343
    0
        fn from(value: std::fmt::Error) -> Self {
    344
    0
            Self::Format(value)
    345
    0
        }
    346
    }
    347
    348
    impl From<ArrowError> for FormatError {
    349
    0
        fn from(value: ArrowError) -> Self {
    350
    0
            Self::Arrow(value)
    351
    0
        }
    352
    }
    353
    354
    /// [`Display`] but accepting an index
    355
    trait DisplayIndex {
    356
        fn write(&self, idx: usize, f: &mut dyn Write) -> FormatResult;
    357
    }
    358
    359
    /// [`DisplayIndex`] with additional state
    360
    trait DisplayIndexState<'a> {
    361
        type State;
    362
    363
        fn prepare(&self, options: &FormatOptions<'a>) -> Result<Self::State, ArrowError>;
    364
    365
        fn write(&self, state: &Self::State, idx: usize, f: &mut dyn Write) -> FormatResult;
    366
    }
    367
    368
    impl<'a, T: DisplayIndex> DisplayIndexState<'a> for T {
    369
        type State = ();
    370
    371
    0
        fn prepare(&self, _options: &FormatOptions<'a>) -> Result<Self::State, ArrowError> {
    372
    0
            Ok(())
    373
    0
        }
    374
    375
    0
        fn write(&self, _: &Self::State, idx: usize, f: &mut dyn Write) -> FormatResult {
    376
    0
            DisplayIndex::write(self, idx, f)
    377
    0
        }
    378
    }
    379
    380
    struct ArrayFormat<'a, F: DisplayIndexState<'a>> {
    381
        state: F::State,
    382
        array: F,
    383
        null: &'a str,
    384
    }
    385
    386
    0
    fn array_format<'a, F>(
    387
    0
        array: F,
    388
    0
        options: &FormatOptions<'a>,
    389
    0
    ) -> Result<Box<dyn DisplayIndex + 'a>, ArrowError>
    390
    0
    where
    391
    0
        F: DisplayIndexState<'a> + Array + 'a,
    392
    {
    393
    0
        let state = array.prepare(options)?;
    394
    0
        Ok(Box::new(ArrayFormat {
    395
    0
            state,
    396
    0
            array,
    397
    0
            null: options.null,
    398
    0
        }))
    399
    0
    }
    400
    401
    impl<'a, F: DisplayIndexState<'a> + Array> DisplayIndex for ArrayFormat<'a, F> {
    402
    0
        fn write(&self, idx: usize, f: &mut dyn Write) -> FormatResult {
    403
    0
            if self.array.is_null(idx) {
    404
    0
                if !self.null.is_empty() {
    405
    0
                    f.write_str(self.null)?
    406
    0
                }
    407
    0
                return Ok(());
    408
    0
            }
    409
    0
            DisplayIndexState::write(&self.array, &self.state, idx, f)
    410
    0
        }
    411
    }
    412
    413
    impl DisplayIndex for &BooleanArray {
    414
    0
        fn write(&self, idx: usize, f: &mut dyn Write) -> FormatResult {
    415
    0
            write!(f, "{}", self.value(idx))?;
    416
    0
            Ok(())
    417
    0
        }
    418
    }
    419
    420
    impl<'a> DisplayIndexState<'a> for &'a NullArray {
    421
        type State = &'a str;
    422
    423
    0
        fn prepare(&self, options: &FormatOptions<'a>) -> Result<Self::State, ArrowError> {
    424
    0
            Ok(options.null)
    425
    0
        }
    426
    427
    0
        fn write(&self, state: &Self::State, _idx: usize, f: &mut dyn Write) -> FormatResult {
    428
    0
            f.write_str(state)?;
    429
    0
            Ok(())
    430
    0
        }
    431
    }
    432
    433
    macro_rules! primitive_display {
    434
        ($($t:ty),+) => {
    435
            $(impl<'a> DisplayIndex for &'a PrimitiveArray<$t>
    436
            {
    437
    0
                fn write(&self, idx: usize, f: &mut dyn Write) -> FormatResult {
    438
    0
                    let value = self.value(idx);
    439
    0
                    let mut buffer = [0u8; <$t as ArrowPrimitiveType>::Native::FORMATTED_SIZE];
    440
    0
                    let b = lexical_core::write(value, &mut buffer);
    441
                    // Lexical core produces valid UTF-8
    442
    0
                    let s = unsafe { std::str::from_utf8_unchecked(b) };
    443
    0
                    f.write_str(s)?;
    444
    0
                    Ok(())
    445
    0
                }
    446
            })+
    447
        };
    448
    }
    449
    450
    macro_rules! primitive_display_float {
    451
        ($($t:ty),+) => {
    452
            $(impl<'a> DisplayIndex for &'a PrimitiveArray<$t>
    453
            {
    454
    0
                fn write(&self, idx: usize, f: &mut dyn Write) -> FormatResult {
    455
    0
                    let value = self.value(idx);
    456
    0
                    let mut buffer = ryu::Buffer::new();
    457
    0
                    f.write_str(buffer.format(value))?;
    458
    0
                    Ok(())
    459
    0
                }
    460
            })+
    461
        };
    462
    }
    463
    464
    primitive_display!(Int8Type, Int16Type, Int32Type, Int64Type);
    465
    primitive_display!(UInt8Type, UInt16Type, UInt32Type, UInt64Type);
    466
    primitive_display_float!(Float32Type, Float64Type);
    467
    468
    impl DisplayIndex for &PrimitiveArray<Float16Type> {
    469
    0
        fn write(&self, idx: usize, f: &mut dyn Write) -> FormatResult {
    470
    0
            write!(f, "{}", self.value(idx))?;
    471
    0
            Ok(())
    472
    0
        }
    473
    }
    474
    475
    macro_rules! decimal_display {
    476
        ($($t:ty),+) => {
    477
            $(impl<'a> DisplayIndexState<'a> for &'a PrimitiveArray<$t> {
    478
                type State = (u8, i8);
    479
    480
    0
                fn prepare(&self, _options: &FormatOptions<'a>) -> Result<Self::State, ArrowError> {
    481
    0
                    Ok((self.precision(), self.scale()))
    482
    0
                }
    483
    484
    0
                fn write(&self, s: &Self::State, idx: usize, f: &mut dyn Write) -> FormatResult {
    485
    0
                    write!(f, "{}", <$t>::format_decimal(self.values()[idx], s.0, s.1))?;
    486
    0
                    Ok(())
    487
    0
                }
    488
            })+
    489
        };
    490
    }
    491
    492
    decimal_display!(Decimal32Type, Decimal64Type, Decimal128Type, Decimal256Type);
    493
    494
    0
    fn write_timestamp(
    495
    0
        f: &mut dyn Write,
    496
    0
        naive: NaiveDateTime,
    497
    0
        timezone: Option<Tz>,
    498
    0
        format: Option<&str>,
    499
    0
    ) -> FormatResult {
    500
    0
        match timezone {
    501
    0
            Some(tz) => {
    502
    0
                let date = Utc.from_utc_datetime(&naive).with_timezone(&tz);
    503
    0
                match format {
    504
    0
                    Some(s) => write!(f, "{}", date.format(s))?,
    505
    0
                    None => write!(f, "{}", date.to_rfc3339_opts(SecondsFormat::AutoSi, true))?,
    506
                }
    507
            }
    508
    0
            None => match format {
    509
    0
                Some(s) => write!(f, "{}", naive.format(s))?,
    510
    0
                None => write!(f, "{naive:?}")?,
    511
            },
    512
        }
    513
    0
        Ok(())
    514
    0
    }
    515
    516
    macro_rules! timestamp_display {
    517
        ($($t:ty),+) => {
    518
            $(impl<'a> DisplayIndexState<'a> for &'a PrimitiveArray<$t> {
    519
                type State = (Option<Tz>, TimeFormat<'a>);
    520
    521
    0
                fn prepare(&self, options: &FormatOptions<'a>) -> Result<Self::State, ArrowError> {
    522
    0
                    match self.data_type() {
    523
    0
                        DataType::Timestamp(_, Some(tz)) => Ok((Some(tz.parse()?), options.timestamp_tz_format)),
    524
    0
                        DataType::Timestamp(_, None) => Ok((None, options.timestamp_format)),
    525
    0
                        _ => unreachable!(),
    526
                    }
    527
    0
                }
    528
    529
    0
                fn write(&self, s: &Self::State, idx: usize, f: &mut dyn Write) -> FormatResult {
    530
    0
                    let value = self.value(idx);
    531
    0
                    let naive = as_datetime::<$t>(value).ok_or_else(|| {
    532
    0
                        ArrowError::CastError(format!(
    533
    0
                            "Failed to convert {} to datetime for {}",
    534
    0
                            value,
    535
    0
                            self.data_type()
    536
    0
                        ))
    537
    0
                    })?;
    538
    539
    0
                    write_timestamp(f, naive, s.0, s.1.clone())
    540
    0
                }
    541
            })+
    542
        };
    543
    }
    544
    545
    timestamp_display!(
    546
        TimestampSecondType,
    547
        TimestampMillisecondType,
    548
        TimestampMicrosecondType,
    549
        TimestampNanosecondType
    550
    );
    551
    552
    macro_rules! temporal_display {
    553
        ($convert:ident, $format:ident, $t:ty) => {
    554
            impl<'a> DisplayIndexState<'a> for &'a PrimitiveArray<$t> {
    555
                type State = TimeFormat<'a>;
    556
    557
    0
                fn prepare(&self, options: &FormatOptions<'a>) -> Result<Self::State, ArrowError> {
    558
    0
                    Ok(options.$format)
    559
    0
                }
    560
    561
    0
                fn write(&self, fmt: &Self::State, idx: usize, f: &mut dyn Write) -> FormatResult {
    562
    0
                    let value = self.value(idx);
    563
    0
                    let naive = $convert(value as _).ok_or_else(|| {
    564
    0
                        ArrowError::CastError(format!(
    565
    0
                            "Failed to convert {} to temporal for {}",
    566
    0
                            value,
    567
    0
                            self.data_type()
    568
    0
                        ))
    569
    0
                    })?;
    570
    571
    0
                    match fmt {
    572
    0
                        Some(s) => write!(f, "{}", naive.format(s))?,
    573
    0
                        None => write!(f, "{naive:?}")?,
    574
                    }
    575
    0
                    Ok(())
    576
    0
                }
    577
            }
    578
        };
    579
    }
    580
    581
    #[inline]
    582
    0
    fn date32_to_date(value: i32) -> Option<NaiveDate> {
    583
    0
        Some(date32_to_datetime(value)?.date())
    584
    0
    }
    585
    586
    temporal_display!(date32_to_date, date_format, Date32Type);
    587
    temporal_display!(date64_to_datetime, datetime_format, Date64Type);
    588
    temporal_display!(time32s_to_time, time_format, Time32SecondType);
    589
    temporal_display!(time32ms_to_time, time_format, Time32MillisecondType);
    590
    temporal_display!(time64us_to_time, time_format, Time64MicrosecondType);
    591
    temporal_display!(time64ns_to_time, time_format, Time64NanosecondType);
    592
    593
    /// Derive [`DisplayIndexState`] for `PrimitiveArray<$t>`
    594
    ///
    595
    /// Arguments
    596
    /// * `$convert` - function to convert the value to an `Duration`
    597
    /// * `$t` - [`ArrowPrimitiveType`] of the array
    598
    /// * `$scale` - scale of the duration (passed to `duration_fmt`)
    599
    macro_rules! duration_display {
    600
        ($convert:ident, $t:ty, $scale:tt) => {
    601
            impl<'a> DisplayIndexState<'a> for &'a PrimitiveArray<$t> {
    602
                type State = DurationFormat;
    603
    604
    0
                fn prepare(&self, options: &FormatOptions<'a>) -> Result<Self::State, ArrowError> {
    605
    0
                    Ok(options.duration_format)
    606
    0
                }
    607
    608
    0
                fn write(&self, fmt: &Self::State, idx: usize, f: &mut dyn Write) -> FormatResult {
    609
    0
                    let v = self.value(idx);
    610
    0
                    match fmt {
    611
    0
                        DurationFormat::ISO8601 => write!(f, "{}", $convert(v))?,
    612
    0
                        DurationFormat::Pretty => duration_fmt!(f, v, $scale)?,
    613
                    }
    614
    0
                    Ok(())
    615
    0
                }
    616
            }
    617
        };
    618
    }
    619
    620
    /// Similar to [`duration_display`] but `$convert` returns an `Option`
    621
    macro_rules! duration_option_display {
    622
        ($convert:ident, $t:ty, $scale:tt) => {
    623
            impl<'a> DisplayIndexState<'a> for &'a PrimitiveArray<$t> {
    624
                type State = DurationFormat;
    625
    626
    0
                fn prepare(&self, options: &FormatOptions<'a>) -> Result<Self::State, ArrowError> {
    627
    0
                    Ok(options.duration_format)
    628
    0
                }
    629
    630
    0
                fn write(&self, fmt: &Self::State, idx: usize, f: &mut dyn Write) -> FormatResult {
    631
    0
                    let v = self.value(idx);
    632
    0
                    match fmt {
    633
    0
                        DurationFormat::ISO8601 => match $convert(v) {
    634
    0
                            Some(td) => write!(f, "{}", td)?,
    635
    0
                            None => write!(f, "<invalid>")?,
    636
                        },
    637
    0
                        DurationFormat::Pretty => match $convert(v) {
    638
    0
                            Some(_) => duration_fmt!(f, v, $scale)?,
    639
    0
                            None => write!(f, "<invalid>")?,
    640
                        },
    641
                    }
    642
    0
                    Ok(())
    643
    0
                }
    644
            }
    645
        };
    646
    }
    647
    648
    macro_rules! duration_fmt {
    649
        ($f:ident, $v:expr, 0) => {{
    650
            let secs = $v;
    651
            let mins = secs / 60;
    652
            let hours = mins / 60;
    653
            let days = hours / 24;
    654
    655
            let secs = secs - (mins * 60);
    656
            let mins = mins - (hours * 60);
    657
            let hours = hours - (days * 24);
    658
            write!($f, "{days} days {hours} hours {mins} mins {secs} secs")
    659
        }};
    660
        ($f:ident, $v:expr, $scale:tt) => {{
    661
            let subsec = $v;
    662
            let secs = subsec / 10_i64.pow($scale);
    663
            let mins = secs / 60;
    664
            let hours = mins / 60;
    665
            let days = hours / 24;
    666
    667
            let subsec = subsec - (secs * 10_i64.pow($scale));
    668
            let secs = secs - (mins * 60);
    669
            let mins = mins - (hours * 60);
    670
            let hours = hours - (days * 24);
    671
            match subsec.is_negative() {
    672
                true => {
    673
                    write!(
    674
                        $f,
    675
                        concat!("{} days {} hours {} mins -{}.{:0", $scale, "} secs"),
    676
                        days,
    677
                        hours,
    678
                        mins,
    679
                        secs.abs(),
    680
                        subsec.abs()
    681
                    )
    682
                }
    683
                false => {
    684
                    write!(
    685
                        $f,
    686
                        concat!("{} days {} hours {} mins {}.{:0", $scale, "} secs"),
    687
                        days, hours, mins, secs, subsec
    688
                    )
    689
                }
    690
            }
    691
        }};
    692
    }
    693
    694
    duration_option_display!(try_duration_s_to_duration, DurationSecondType, 0);
    695
    duration_option_display!(try_duration_ms_to_duration, DurationMillisecondType, 3);
    696
    duration_display!(duration_us_to_duration, DurationMicrosecondType, 6);
    697
    duration_display!(duration_ns_to_duration, DurationNanosecondType, 9);
    698
    699
    impl DisplayIndex for &PrimitiveArray<IntervalYearMonthType> {
    700
    0
        fn write(&self, idx: usize, f: &mut dyn Write) -> FormatResult {
    701
    0
            let interval = self.value(idx) as f64;
    702
    0
            let years = (interval / 12_f64).floor();
    703
    0
            let month = interval - (years * 12_f64);
    704
    705
    0
            write!(f, "{years} years {month} mons",)?;
    706
    0
            Ok(())
    707
    0
        }
    708
    }
    709
    710
    impl DisplayIndex for &PrimitiveArray<IntervalDayTimeType> {
    711
    0
        fn write(&self, idx: usize, f: &mut dyn Write) -> FormatResult {
    712
    0
            let value = self.value(idx);
    713
    0
            let mut prefix = "";
    714
    715
    0
            if value.days != 0 {
    716
    0
                write!(f, "{prefix}{} days", value.days)?;
    717
    0
                prefix = " ";
    718
    0
            }
    719
    720
    0
            if value.milliseconds != 0 {
    721
    0
                let millis_fmt = MillisecondsFormatter {
    722
    0
                    milliseconds: value.milliseconds,
    723
    0
                    prefix,
    724
    0
                };
    725
    726
    0
                f.write_fmt(format_args!("{millis_fmt}"))?;
    727
    0
            }
    728
    729
    0
            Ok(())
    730
    0
        }
    731
    }
    732
    733
    impl DisplayIndex for &PrimitiveArray<IntervalMonthDayNanoType> {
    734
    0
        fn write(&self, idx: usize, f: &mut dyn Write) -> FormatResult {
    735
    0
            let value = self.value(idx);
    736
    0
            let mut prefix = "";
    737
    738
    0
            if value.months != 0 {
    739
    0
                write!(f, "{prefix}{} mons", value.months)?;
    740
    0
                prefix = " ";
    741
    0
            }
    742
    743
    0
            if value.days != 0 {
    744
    0
                write!(f, "{prefix}{} days", value.days)?;
    745
    0
                prefix = " ";
    746
    0
            }
    747
    748
    0
            if value.nanoseconds != 0 {
    749
    0
                let nano_fmt = NanosecondsFormatter {
    750
    0
                    nanoseconds: value.nanoseconds,
    751
    0
                    prefix,
    752
    0
                };
    753
    0
                f.write_fmt(format_args!("{nano_fmt}"))?;
    754
    0
            }
    755
    756
    0
            Ok(())
    757
    0
        }
    758
    }
    759
    760
    struct NanosecondsFormatter<'a> {
    761
        nanoseconds: i64,
    762
        prefix: &'a str,
    763
    }
    764
    765
    impl Display for NanosecondsFormatter<'_> {
    766
    0
        fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
    767
    0
            let mut prefix = self.prefix;
    768
    769
    0
            let secs = self.nanoseconds / 1_000_000_000;
    770
    0
            let mins = secs / 60;
    771
    0
            let hours = mins / 60;
    772
    773
    0
            let secs = secs - (mins * 60);
    774
    0
            let mins = mins - (hours * 60);
    775
    776
    0
            let nanoseconds = self.nanoseconds % 1_000_000_000;
    777
    778
    0
            if hours != 0 {
    779
    0
                write!(f, "{prefix}{hours} hours")?;
    780
    0
                prefix = " ";
    781
    0
            }
    782
    783
    0
            if mins != 0 {
    784
    0
                write!(f, "{prefix}{mins} mins")?;
    785
    0
                prefix = " ";
    786
    0
            }
    787
    788
    0
            if secs != 0 || nanoseconds != 0 {
    789
    0
                let secs_sign = if secs < 0 || nanoseconds < 0 { "-" } else { "" };
    790
    0
                write!(
    791
    0
                    f,
    792
    0
                    "{prefix}{}{}.{:09} secs",
    793
                    secs_sign,
    794
    0
                    secs.abs(),
    795
    0
                    nanoseconds.abs()
    796
    0
                )?;
    797
    0
            }
    798
    799
    0
            Ok(())
    800
    0
        }
    801
    }
    802
    803
    struct MillisecondsFormatter<'a> {
    804
        milliseconds: i32,
    805
        prefix: &'a str,
    806
    }
    807
    808
    impl Display for MillisecondsFormatter<'_> {
    809
    0
        fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
    810
    0
            let mut prefix = self.prefix;
    811
    812
    0
            let secs = self.milliseconds / 1_000;
    813
    0
            let mins = secs / 60;
    814
    0
            let hours = mins / 60;
    815
    816
    0
            let secs = secs - (mins * 60);
    817
    0
            let mins = mins - (hours * 60);
    818
    819
    0
            let milliseconds = self.milliseconds % 1_000;
    820
    821
    0
            if hours != 0 {
    822
    0
                write!(f, "{prefix}{hours} hours")?;
    823
    0
                prefix = " ";
    824
    0
            }
    825
    826
    0
            if mins != 0 {
    827
    0
                write!(f, "{prefix}{mins} mins")?;
    828
    0
                prefix = " ";
    829
    0
            }
    830
    831
    0
            if secs != 0 || milliseconds != 0 {
    832
    0
                let secs_sign = if secs < 0 || milliseconds < 0 {
    833
    0
                    "-"
    834
                } else {
    835
    0
                    ""
    836
                };
    837
    838
    0
                write!(
    839
    0
                    f,
    840
    0
                    "{prefix}{}{}.{:03} secs",
    841
                    secs_sign,
    842
    0
                    secs.abs(),
    843
    0
                    milliseconds.abs()
    844
    0
                )?;
    845
    0
            }
    846
    847
    0
            Ok(())
    848
    0
        }
    849
    }
    850
    851
    impl<O: OffsetSizeTrait> DisplayIndex for &GenericStringArray<O> {
    852
    0
        fn write(&self, idx: usize, f: &mut dyn Write) -> FormatResult {
    853
    0
            write!(f, "{}", self.value(idx))?;
    854
    0
            Ok(())
    855
    0
        }
    856
    }
    857
    858
    impl DisplayIndex for &StringViewArray {
    859
    0
        fn write(&self, idx: usize, f: &mut dyn Write) -> FormatResult {
    860
    0
            write!(f, "{}", self.value(idx))?;
    861
    0
            Ok(())
    862
    0
        }
    863
    }
    864
    865
    impl<O: OffsetSizeTrait> DisplayIndex for &GenericBinaryArray<O> {
    866
    0
        fn write(&self, idx: usize, f: &mut dyn Write) -> FormatResult {
    867
    0
            let v = self.value(idx);
    868
    0
            for byte in v {
    869
    0
                write!(f, "{byte:02x}")?;
    870
            }
    871
    0
            Ok(())
    872
    0
        }
    873
    }
    874
    875
    impl DisplayIndex for &BinaryViewArray {
    876
    0
        fn write(&self, idx: usize, f: &mut dyn Write) -> FormatResult {
    877
    0
            let v = self.value(idx);
    878
    0
            for byte in v {
    879
    0
                write!(f, "{byte:02x}")?;
    880
            }
    881
    0
            Ok(())
    882
    0
        }
    883
    }
    884
    885
    impl DisplayIndex for &FixedSizeBinaryArray {
    886
    0
        fn write(&self, idx: usize, f: &mut dyn Write) -> FormatResult {
    887
    0
            let v = self.value(idx);
    888
    0
            for byte in v {
    889
    0
                write!(f, "{byte:02x}")?;
    890
            }
    891
    0
            Ok(())
    892
    0
        }
    893
    }
    894
    895
    impl<'a, K: ArrowDictionaryKeyType> DisplayIndexState<'a> for &'a DictionaryArray<K> {
    896
        type State = Box<dyn DisplayIndex + 'a>;
    897
    898
    0
        fn prepare(&self, options: &FormatOptions<'a>) -> Result<Self::State, ArrowError> {
    899
    0
            make_formatter(self.values().as_ref(), options)
    900
    0
        }
    901
    902
    0
        fn write(&self, s: &Self::State, idx: usize, f: &mut dyn Write) -> FormatResult {
    903
    0
            let value_idx = self.keys().values()[idx].as_usize();
    904
    0
            s.as_ref().write(value_idx, f)
    905
    0
        }
    906
    }
    907
    908
    impl<'a, K: RunEndIndexType> DisplayIndexState<'a> for &'a RunArray<K> {
    909
        type State = Box<dyn DisplayIndex + 'a>;
    910
    911
    0
        fn prepare(&self, options: &FormatOptions<'a>) -> Result<Self::State, ArrowError> {
    912
    0
            make_formatter(self.values().as_ref(), options)
    913
    0
        }
    914
    915
    0
        fn write(&self, s: &Self::State, idx: usize, f: &mut dyn Write) -> FormatResult {
    916
    0
            let value_idx = self.get_physical_index(idx);
    917
    0
            s.as_ref().write(value_idx, f)
    918
    0
        }
    919
    }
    920
    921
    0
    fn write_list(
    922
    0
        f: &mut dyn Write,
    923
    0
        mut range: Range<usize>,
    924
    0
        values: &dyn DisplayIndex,
    925
    0
    ) -> FormatResult {
    926
    0
        f.write_char('[')?;
    927
    0
        if let Some(idx) = range.next() {
    928
    0
            values.write(idx, f)?;
    929
    0
        }
    930
    0
        for idx in range {
    931
    0
            write!(f, ", ")?;
    932
    0
            values.write(idx, f)?;
    933
        }
    934
    0
        f.write_char(']')?;
    935
    0
        Ok(())
    936
    0
    }
    937
    938
    impl<'a, O: OffsetSizeTrait> DisplayIndexState<'a> for &'a GenericListArray<O> {
    939
        type State = Box<dyn DisplayIndex + 'a>;
    940
    941
    0
        fn prepare(&self, options: &FormatOptions<'a>) -> Result<Self::State, ArrowError> {
    942
    0
            make_formatter(self.values().as_ref(), options)
    943
    0
        }
    944
    945
    0
        fn write(&self, s: &Self::State, idx: usize, f: &mut dyn Write) -> FormatResult {
    946
    0
            let offsets = self.value_offsets();
    947
    0
            let end = offsets[idx + 1].as_usize();
    948
    0
            let start = offsets[idx].as_usize();
    949
    0
            write_list(f, start..end, s.as_ref())
    950
    0
        }
    951
    }
    952
    953
    impl<'a> DisplayIndexState<'a> for &'a FixedSizeListArray {
    954
        type State = (usize, Box<dyn DisplayIndex + 'a>);
    955
    956
    0
        fn prepare(&self, options: &FormatOptions<'a>) -> Result<Self::State, ArrowError> {
    957
    0
            let values = make_formatter(self.values().as_ref(), options)?;
    958
    0
            let length = self.value_length();
    959
    0
            Ok((length as usize, values))
    960
    0
        }
    961
    962
    0
        fn write(&self, s: &Self::State, idx: usize, f: &mut dyn Write) -> FormatResult {
    963
    0
            let start = idx * s.0;
    964
    0
            let end = start + s.0;
    965
    0
            write_list(f, start..end, s.1.as_ref())
    966
    0
        }
    967
    }
    968
    969
    /// Pairs a boxed [`DisplayIndex`] with its field name
    970
    type FieldDisplay<'a> = (&'a str, Box<dyn DisplayIndex + 'a>);
    971
    972
    impl<'a> DisplayIndexState<'a> for &'a StructArray {
    973
        type State = Vec<FieldDisplay<'a>>;
    974
    975
    0
        fn prepare(&self, options: &FormatOptions<'a>) -> Result<Self::State, ArrowError> {
    976
    0
            let fields = match (*self).data_type() {
    977
    0
                DataType::Struct(f) => f,
    978
    0
                _ => unreachable!(),
    979
            };
    980
    981
    0
            self.columns()
    982
    0
                .iter()
    983
    0
                .zip(fields)
    984
    0
                .map(|(a, f)| {
    985
    0
                    let format = make_formatter(a.as_ref(), options)?;
    986
    0
                    Ok((f.name().as_str(), format))
    987
    0
                })
    988
    0
                .collect()
    989
    0
        }
    990
    991
    0
        fn write(&self, s: &Self::State, idx: usize, f: &mut dyn Write) -> FormatResult {
    992
    0
            let mut iter = s.iter();
    993
    0
            f.write_char('{')?;
    994
    0
            if let Some((name, display)) = iter.next() {
    995
    0
                write!(f, "{name}: ")?;
    996
    0
                display.as_ref().write(idx, f)?;
    997
    0
            }
    998
    0
            for (name, display) in iter {
    999
    0
                write!(f, ", {name}: ")?;
    1000
    0
                display.as_ref().write(idx, f)?;
    1001
            }
    1002
    0
            f.write_char('}')?;
    1003
    0
            Ok(())
    1004
    0
        }
    1005
    }
    1006
    1007
    impl<'a> DisplayIndexState<'a> for &'a MapArray {
    1008
        type State = (Box<dyn DisplayIndex + 'a>, Box<dyn DisplayIndex + 'a>);
    1009
    1010
    0
        fn prepare(&self, options: &FormatOptions<'a>) -> Result<Self::State, ArrowError> {
    1011
    0
            let keys = make_formatter(self.keys().as_ref(), options)?;
    1012
    0
            let values = make_formatter(self.values().as_ref(), options)?;
    1013
    0
            Ok((keys, values))
    1014
    0
        }
    1015
    1016
    0
        fn write(&self, s: &Self::State, idx: usize, f: &mut dyn Write) -> FormatResult {
    1017
    0
            let offsets = self.value_offsets();
    1018
    0
            let end = offsets[idx + 1].as_usize();
    1019
    0
            let start = offsets[idx].as_usize();
    1020
    0
            let mut iter = start..end;
    1021
    1022
    0
            f.write_char('{')?;
    1023
    0
            if let Some(idx) = iter.next() {
    1024
    0
                s.0.write(idx, f)?;
    1025
    0
                write!(f, ": ")?;
    1026
    0
                s.1.write(idx, f)?;
    1027
    0
            }
    1028
    1029
    0
            for idx in iter {
    1030
    0
                write!(f, ", ")?;
    1031
    0
                s.0.write(idx, f)?;
    1032
    0
                write!(f, ": ")?;
    1033
    0
                s.1.write(idx, f)?;
    1034
            }
    1035
    1036
    0
            f.write_char('}')?;
    1037
    0
            Ok(())
    1038
    0
        }
    1039
    }
    1040
    1041
    impl<'a> DisplayIndexState<'a> for &'a UnionArray {
    1042
        type State = (
    1043
            Vec<Option<(&'a str, Box<dyn DisplayIndex + 'a>)>>,
    1044
            UnionMode,
    1045
        );
    1046
    1047
    0
        fn prepare(&self, options: &FormatOptions<'a>) -> Result<Self::State, ArrowError> {
    1048
    0
            let (fields, mode) = match (*self).data_type() {
    1049
    0
                DataType::Union(fields, mode) => (fields, mode),
    1050
    0
                _ => unreachable!(),
    1051
            };
    1052
    1053
    0
            let max_id = fields.iter().map(|(id, _)| id).max().unwrap_or_default() as usize;
    1054
    0
            let mut out: Vec<Option<FieldDisplay>> = (0..max_id + 1).map(|_| None).collect();
    1055
    0
            for (i, field) in fields.iter() {
    1056
    0
                let formatter = make_formatter(self.child(i).as_ref(), options)?;
    1057
    0
                out[i as usize] = Some((field.name().as_str(), formatter))
    1058
            }
    1059
    0
            Ok((out, *mode))
    1060
    0
        }
    1061
    1062
    0
        fn write(&self, s: &Self::State, idx: usize, f: &mut dyn Write) -> FormatResult {
    1063
    0
            let id = self.type_id(idx);
    1064
    0
            let idx = match s.1 {
    1065
    0
                UnionMode::Dense => self.value_offset(idx),
    1066
    0
                UnionMode::Sparse => idx,
    1067
            };
    1068
    0
            let (name, field) = s.0[id as usize].as_ref().unwrap();
    1069
    1070
    0
            write!(f, "{{{name}=")?;
    1071
    0
            field.write(idx, f)?;
    1072
    0
            f.write_char('}')?;
    1073
    0
            Ok(())
    1074
    0
        }
    1075
    }
    1076
    1077
    /// Get the value at the given row in an array as a String.
    1078
    ///
    1079
    /// Note this function is quite inefficient and is unlikely to be
    1080
    /// suitable for converting large arrays or record batches.
    1081
    ///
    1082
    /// Please see [`ArrayFormatter`] for a more performant interface
    1083
    0
    pub fn array_value_to_string(column: &dyn Array, row: usize) -> Result<String, ArrowError> {
    1084
    0
        let options = FormatOptions::default().with_display_error(true);
    1085
    0
        let formatter = ArrayFormatter::try_new(column, &options)?;
    1086
    0
        Ok(formatter.value(row).to_string())
    1087
    0
    }
    1088
    1089
    /// Converts numeric type to a `String`
    1090
    pub fn lexical_to_string<N: lexical_core::ToLexical>(n: N) -> String {
    1091
        let mut buf = Vec::<u8>::with_capacity(N::FORMATTED_SIZE_DECIMAL);
    1092
        unsafe {
    1093
            // JUSTIFICATION
    1094
            //  Benefit
    1095
            //      Allows using the faster serializer lexical core and convert to string
    1096
            //  Soundness
    1097
            //      Length of buf is set as written length afterwards. lexical_core
    1098
            //      creates a valid string, so doesn't need to be checked.
    1099
            let slice = std::slice::from_raw_parts_mut(buf.as_mut_ptr(), buf.capacity());
    1100
            let len = lexical_core::write(n, slice).len();
    1101
            buf.set_len(len);
    1102
            String::from_utf8_unchecked(buf)
    1103
        }
    1104
    }
    1105
    1106
    #[cfg(test)]
    1107
    mod tests {
    1108
        use super::*;
    1109
        use arrow_array::builder::StringRunBuilder;
    1110
    1111
        /// Test to verify options can be constant. See #4580
    1112
        const TEST_CONST_OPTIONS: FormatOptions<'static> = FormatOptions::new()
    1113
            .with_date_format(Some("foo"))
    1114
            .with_timestamp_format(Some("404"));
    1115
    1116
        #[test]
    1117
        fn test_const_options() {
    1118
            assert_eq!(TEST_CONST_OPTIONS.date_format, Some("foo"));
    1119
        }
    1120
    1121
        #[test]
    1122
        fn test_map_array_to_string() {
    1123
            let keys = vec!["a", "b", "c", "d", "e", "f", "g", "h"];
    1124
            let values_data = UInt32Array::from(vec![0u32, 10, 20, 30, 40, 50, 60, 70]);
    1125
    1126
            // Construct a buffer for value offsets, for the nested array:
    1127
            //  [[a, b, c], [d, e, f], [g, h]]
    1128
            let entry_offsets = [0, 3, 6, 8];
    1129
    1130
            let map_array =
    1131
                MapArray::new_from_strings(keys.clone().into_iter(), &values_data, &entry_offsets)
    1132
                    .unwrap();
    1133
            assert_eq!(
    1134
                "{d: 30, e: 40, f: 50}",
    1135
                array_value_to_string(&map_array, 1).unwrap()
    1136
            );
    1137
        }
    1138
    1139
        fn format_array(array: &dyn Array, fmt: &FormatOptions) -> Vec<String> {
    1140
            let fmt = ArrayFormatter::try_new(array, fmt).unwrap();
    1141
            (0..array.len()).map(|x| fmt.value(x).to_string()).collect()
    1142
        }
    1143
    1144
        #[test]
    1145
        fn test_array_value_to_string_duration() {
    1146
            let iso_fmt = FormatOptions::new();
    1147
            let pretty_fmt = FormatOptions::new().with_duration_format(DurationFormat::Pretty);
    1148
    1149
            let array = DurationNanosecondArray::from(vec![
    1150
                1,
    1151
                -1,
    1152
                1000,
    1153
                -1000,
    1154
                (45 * 60 * 60 * 24 + 14 * 60 * 60 + 2 * 60 + 34) * 1_000_000_000 + 123456789,
    1155
                -(45 * 60 * 60 * 24 + 14 * 60 * 60 + 2 * 60 + 34) * 1_000_000_000 - 123456789,
    1156
            ]);
    1157
            let iso = format_array(&array, &iso_fmt);
    1158
            let pretty = format_array(&array, &pretty_fmt);
    1159
    1160
            assert_eq!(iso[0], "PT0.000000001S");
    1161
            assert_eq!(pretty[0], "0 days 0 hours 0 mins 0.000000001 secs");
    1162
            assert_eq!(iso[1], "-PT0.000000001S");
    1163
            assert_eq!(pretty[1], "0 days 0 hours 0 mins -0.000000001 secs");
    1164
            assert_eq!(iso[2], "PT0.000001S");
    1165
            assert_eq!(pretty[2], "0 days 0 hours 0 mins 0.000001000 secs");
    1166
            assert_eq!(iso[3], "-PT0.000001S");
    1167
            assert_eq!(pretty[3], "0 days 0 hours 0 mins -0.000001000 secs");
    1168
            assert_eq!(iso[4], "PT3938554.123456789S");
    1169
            assert_eq!(pretty[4], "45 days 14 hours 2 mins 34.123456789 secs");
    1170
            assert_eq!(iso[5], "-PT3938554.123456789S");
    1171
            assert_eq!(pretty[5], "-45 days -14 hours -2 mins -34.123456789 secs");
    1172
    1173
            let array = DurationMicrosecondArray::from(vec![
    1174
                1,
    1175
                -1,
    1176
                1000,
    1177
                -1000,
    1178
                (45 * 60 * 60 * 24 + 14 * 60 * 60 + 2 * 60 + 34) * 1_000_000 + 123456,
    1179
                -(45 * 60 * 60 * 24 + 14 * 60 * 60 + 2 * 60 + 34) * 1_000_000 - 123456,
    1180
            ]);
    1181
            let iso = format_array(&array, &iso_fmt);
    1182
            let pretty = format_array(&array, &pretty_fmt);
    1183
    1184
            assert_eq!(iso[0], "PT0.000001S");
    1185
            assert_eq!(pretty[0], "0 days 0 hours 0 mins 0.000001 secs");
    1186
            assert_eq!(iso[1], "-PT0.000001S");
    1187
            assert_eq!(pretty[1], "0 days 0 hours 0 mins -0.000001 secs");
    1188
            assert_eq!(iso[2], "PT0.001S");
    1189
            assert_eq!(pretty[2], "0 days 0 hours 0 mins 0.001000 secs");
    1190
            assert_eq!(iso[3], "-PT0.001S");
    1191
            assert_eq!(pretty[3], "0 days 0 hours 0 mins -0.001000 secs");
    1192
            assert_eq!(iso[4], "PT3938554.123456S");
    1193
            assert_eq!(pretty[4], "45 days 14 hours 2 mins 34.123456 secs");
    1194
            assert_eq!(iso[5], "-PT3938554.123456S");
    1195
            assert_eq!(pretty[5], "-45 days -14 hours -2 mins -34.123456 secs");
    1196
    1197
            let array = DurationMillisecondArray::from(vec![
    1198
                1,
    1199
                -1,
    1200
                1000,
    1201
                -1000,
    1202
                (45 * 60 * 60 * 24 + 14 * 60 * 60 + 2 * 60 + 34) * 1_000 + 123,
    1203
                -(45 * 60 * 60 * 24 + 14 * 60 * 60 + 2 * 60 + 34) * 1_000 - 123,
    1204
            ]);
    1205
            let iso = format_array(&array, &iso_fmt);
    1206
            let pretty = format_array(&array, &pretty_fmt);
    1207
    1208
            assert_eq!(iso[0], "PT0.001S");
    1209
            assert_eq!(pretty[0], "0 days 0 hours 0 mins 0.001 secs");
    1210
            assert_eq!(iso[1], "-PT0.001S");
    1211
            assert_eq!(pretty[1], "0 days 0 hours 0 mins -0.001 secs");
    1212
            assert_eq!(iso[2], "PT1S");
    1213
            assert_eq!(pretty[2], "0 days 0 hours 0 mins 1.000 secs");
    1214
            assert_eq!(iso[3], "-PT1S");
    1215
            assert_eq!(pretty[3], "0 days 0 hours 0 mins -1.000 secs");
    1216
            assert_eq!(iso[4], "PT3938554.123S");
    1217
            assert_eq!(pretty[4], "45 days 14 hours 2 mins 34.123 secs");
    1218
            assert_eq!(iso[5], "-PT3938554.123S");
    1219
            assert_eq!(pretty[5], "-45 days -14 hours -2 mins -34.123 secs");
    1220
    1221
            let array = DurationSecondArray::from(vec![
    1222
                1,
    1223
                -1,
    1224
                1000,
    1225
                -1000,
    1226
                45 * 60 * 60 * 24 + 14 * 60 * 60 + 2 * 60 + 34,
    1227
                -45 * 60 * 60 * 24 - 14 * 60 * 60 - 2 * 60 - 34,
    1228
            ]);
    1229
            let iso = format_array(&array, &iso_fmt);
    1230
            let pretty = format_array(&array, &pretty_fmt);
    1231
    1232
            assert_eq!(iso[0], "PT1S");
    1233
            assert_eq!(pretty[0], "0 days 0 hours 0 mins 1 secs");
    1234
            assert_eq!(iso[1], "-PT1S");
    1235
            assert_eq!(pretty[1], "0 days 0 hours 0 mins -1 secs");
    1236
            assert_eq!(iso[2], "PT1000S");
    1237
            assert_eq!(pretty[2], "0 days 0 hours 16 mins 40 secs");
    1238
            assert_eq!(iso[3], "-PT1000S");
    1239
            assert_eq!(pretty[3], "0 days 0 hours -16 mins -40 secs");
    1240
            assert_eq!(iso[4], "PT3938554S");
    1241
            assert_eq!(pretty[4], "45 days 14 hours 2 mins 34 secs");
    1242
            assert_eq!(iso[5], "-PT3938554S");
    1243
            assert_eq!(pretty[5], "-45 days -14 hours -2 mins -34 secs");
    1244
        }
    1245
    1246
        #[test]
    1247
        fn test_null() {
    1248
            let array = NullArray::new(2);
    1249
            let options = FormatOptions::new().with_null("NULL");
    1250
            let formatted = format_array(&array, &options);
    1251
            assert_eq!(formatted, &["NULL".to_string(), "NULL".to_string()])
    1252
        }
    1253
    1254
        #[test]
    1255
        fn test_string_run_arry_to_string() {
    1256
            let mut builder = StringRunBuilder::<Int32Type>::new();
    1257
    1258
            builder.append_value("input_value");
    1259
            builder.append_value("input_value");
    1260
            builder.append_value("input_value");
    1261
            builder.append_value("input_value1");
    1262
    1263
            let map_array = builder.finish();
    1264
            assert_eq!("input_value", array_value_to_string(&map_array, 1).unwrap());
    1265
            assert_eq!(
    1266
                "input_value1",
    1267
                array_value_to_string(&map_array, 3).unwrap()
    1268
            );
    1269
        }
    1270
    }