1use std::fmt::{Debug, Display, Formatter, Write};
14use std::hash::{Hash, Hasher};
15use std::ops::Range;
16
17use arrow_array::cast::*;
18use arrow_array::temporal_conversions::*;
19use arrow_array::timezone::Tz;
20use arrow_array::types::*;
21use arrow_array::*;
22use arrow_buffer::ArrowNativeType;
23use arrow_data::decimal::write_decimal;
24use arrow_schema::*;
25use chrono::format::{Item, StrftimeItems};
26use chrono::{NaiveDate, NaiveDateTime, SecondsFormat, TimeZone, Utc};
27use lexical_core::FormattedSize;
28
29type TimeFormat<'a> = Option<&'a str>;
30
31struct CompiledItems<'a>(Vec<Item<'a>>);
32
33enum CompiledTimeFormat<'a> {
34 Default,
35 Custom(Box<CompiledItems<'a>>),
36}
37
38impl<'a> CompiledTimeFormat<'a> {
39 fn new(format: TimeFormat<'a>) -> Self {
40 match format {
41 Some(format) => Self::Custom(Box::new(CompiledItems(
42 StrftimeItems::new(format).collect(),
43 ))),
44 None => Self::Default,
45 }
46 }
47}
48
49#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
51#[non_exhaustive]
52pub enum DurationFormat {
53 ISO8601,
55 Pretty,
57}
58
59#[derive(Debug, Clone)]
70pub struct FormatOptions<'a> {
71 safe: bool,
74 null: &'a str,
76 date_format: TimeFormat<'a>,
78 datetime_format: TimeFormat<'a>,
80 timestamp_format: TimeFormat<'a>,
82 timestamp_tz_format: TimeFormat<'a>,
84 time_format: TimeFormat<'a>,
86 duration_format: DurationFormat,
88 types_info: bool,
90 quoted_strings: bool,
92 formatter_factory: Option<&'a dyn ArrayFormatterFactory>,
95}
96
97impl Default for FormatOptions<'_> {
98 fn default() -> Self {
99 Self::new()
100 }
101}
102
103impl PartialEq for FormatOptions<'_> {
104 fn eq(&self, other: &Self) -> bool {
105 self.safe == other.safe
106 && self.null == other.null
107 && self.date_format == other.date_format
108 && self.datetime_format == other.datetime_format
109 && self.timestamp_format == other.timestamp_format
110 && self.timestamp_tz_format == other.timestamp_tz_format
111 && self.time_format == other.time_format
112 && self.duration_format == other.duration_format
113 && self.types_info == other.types_info
114 && self.quoted_strings == other.quoted_strings
115 && match (self.formatter_factory, other.formatter_factory) {
116 (Some(f1), Some(f2)) => std::ptr::eq(f1, f2),
117 (None, None) => true,
118 _ => false,
119 }
120 }
121}
122
123impl Eq for FormatOptions<'_> {}
124
125impl Hash for FormatOptions<'_> {
126 fn hash<H: Hasher>(&self, state: &mut H) {
127 self.safe.hash(state);
128 self.null.hash(state);
129 self.date_format.hash(state);
130 self.datetime_format.hash(state);
131 self.timestamp_format.hash(state);
132 self.timestamp_tz_format.hash(state);
133 self.time_format.hash(state);
134 self.duration_format.hash(state);
135 self.types_info.hash(state);
136 self.quoted_strings.hash(state);
137 self.formatter_factory
138 .map(std::ptr::from_ref::<dyn ArrayFormatterFactory>)
139 .hash(state);
140 }
141}
142
143impl<'a> FormatOptions<'a> {
144 pub const fn new() -> Self {
146 Self {
147 safe: true,
148 null: "",
149 date_format: None,
150 datetime_format: None,
151 timestamp_format: None,
152 timestamp_tz_format: None,
153 time_format: None,
154 duration_format: DurationFormat::ISO8601,
155 types_info: false,
156 quoted_strings: false,
157 formatter_factory: None,
158 }
159 }
160
161 pub const fn with_display_error(mut self, safe: bool) -> Self {
164 self.safe = safe;
165 self
166 }
167
168 pub const fn with_null(self, null: &'a str) -> Self {
172 Self { null, ..self }
173 }
174
175 pub const fn with_date_format(self, date_format: Option<&'a str>) -> Self {
177 Self {
178 date_format,
179 ..self
180 }
181 }
182
183 pub const fn with_datetime_format(self, datetime_format: Option<&'a str>) -> Self {
185 Self {
186 datetime_format,
187 ..self
188 }
189 }
190
191 pub const fn with_timestamp_format(self, timestamp_format: Option<&'a str>) -> Self {
193 Self {
194 timestamp_format,
195 ..self
196 }
197 }
198
199 pub const fn with_timestamp_tz_format(self, timestamp_tz_format: Option<&'a str>) -> Self {
201 Self {
202 timestamp_tz_format,
203 ..self
204 }
205 }
206
207 pub const fn with_time_format(self, time_format: Option<&'a str>) -> Self {
209 Self {
210 time_format,
211 ..self
212 }
213 }
214
215 pub const fn with_duration_format(self, duration_format: DurationFormat) -> Self {
219 Self {
220 duration_format,
221 ..self
222 }
223 }
224
225 pub const fn with_types_info(self, types_info: bool) -> Self {
229 Self { types_info, ..self }
230 }
231
232 pub const fn with_quoted_strings(self, quoted_strings: bool) -> Self {
237 Self {
238 quoted_strings,
239 ..self
240 }
241 }
242
243 pub const fn with_formatter_factory(
247 self,
248 formatter_factory: Option<&'a dyn ArrayFormatterFactory>,
249 ) -> Self {
250 Self {
251 formatter_factory,
252 ..self
253 }
254 }
255
256 pub const fn safe(&self) -> bool {
259 self.safe
260 }
261
262 pub const fn null(&self) -> &'a str {
264 self.null
265 }
266
267 pub const fn date_format(&self) -> TimeFormat<'a> {
269 self.date_format
270 }
271
272 pub const fn datetime_format(&self) -> TimeFormat<'a> {
274 self.datetime_format
275 }
276
277 pub const fn timestamp_format(&self) -> TimeFormat<'a> {
279 self.timestamp_format
280 }
281
282 pub const fn timestamp_tz_format(&self) -> TimeFormat<'a> {
284 self.timestamp_tz_format
285 }
286
287 pub const fn time_format(&self) -> TimeFormat<'a> {
289 self.time_format
290 }
291
292 pub const fn duration_format(&self) -> DurationFormat {
294 self.duration_format
295 }
296
297 pub const fn types_info(&self) -> bool {
299 self.types_info
300 }
301
302 pub const fn quoted_strings(&self) -> bool {
304 self.quoted_strings
305 }
306
307 pub const fn formatter_factory(&self) -> Option<&'a dyn ArrayFormatterFactory> {
309 self.formatter_factory
310 }
311}
312
313pub trait ArrayFormatterFactory: Debug + Send + Sync {
386 fn create_array_formatter<'formatter>(
393 &self,
394 array: &'formatter dyn Array,
395 options: &FormatOptions<'formatter>,
396 field: Option<&'formatter Field>,
397 ) -> Result<Option<ArrayFormatter<'formatter>>, ArrowError>;
398}
399
400pub(crate) fn make_array_formatter<'a>(
403 array: &'a dyn Array,
404 options: &FormatOptions<'a>,
405 field: Option<&'a Field>,
406) -> Result<ArrayFormatter<'a>, ArrowError> {
407 match options.formatter_factory() {
408 None => ArrayFormatter::try_new(array, options),
409 Some(formatters) => formatters
410 .create_array_formatter(array, options, field)
411 .transpose()
412 .unwrap_or_else(|| ArrayFormatter::try_new(array, options)),
413 }
414}
415
416pub struct ValueFormatter<'a> {
418 idx: usize,
419 formatter: &'a ArrayFormatter<'a>,
420}
421
422impl ValueFormatter<'_> {
423 pub fn write(&self, s: &mut dyn Write) -> Result<(), ArrowError> {
428 match self.formatter.format.write(self.idx, s) {
429 Ok(()) => Ok(()),
430 Err(FormatError::Arrow(e)) => Err(e),
431 Err(FormatError::Format(_)) => Err(ArrowError::CastError("Format error".to_string())),
432 }
433 }
434
435 pub fn try_to_string(&self) -> Result<String, ArrowError> {
437 let mut s = String::new();
438 self.write(&mut s)?;
439 Ok(s)
440 }
441}
442
443impl Display for ValueFormatter<'_> {
444 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
445 match self.formatter.format.write(self.idx, f) {
446 Ok(()) => Ok(()),
447 Err(FormatError::Arrow(e)) if self.formatter.safe => {
448 write!(f, "ERROR: {e}")
449 }
450 Err(_) => Err(std::fmt::Error),
451 }
452 }
453}
454
455pub struct ArrayFormatter<'a> {
508 format: Box<dyn DisplayIndex + 'a>,
509 safe: bool,
510}
511
512impl<'a> ArrayFormatter<'a> {
513 pub fn new(format: Box<dyn DisplayIndex + 'a>, safe: bool) -> Self {
515 Self { format, safe }
516 }
517
518 pub fn try_new(array: &'a dyn Array, options: &FormatOptions<'a>) -> Result<Self, ArrowError> {
522 Ok(Self::new(
523 make_default_display_index(array, options)?,
524 options.safe,
525 ))
526 }
527
528 pub fn value(&self, idx: usize) -> ValueFormatter<'_> {
531 ValueFormatter {
532 formatter: self,
533 idx,
534 }
535 }
536}
537
538fn make_default_display_index<'a>(
539 array: &'a dyn Array,
540 options: &FormatOptions<'a>,
541) -> Result<Box<dyn DisplayIndex + 'a>, ArrowError> {
542 downcast_primitive_array! {
543 array => array_format(array, options),
544 DataType::Null => array_format(as_null_array(array), options),
545 DataType::Boolean => array_format(as_boolean_array(array), options),
546 DataType::Utf8 => array_format(array.as_string::<i32>(), options),
547 DataType::LargeUtf8 => array_format(array.as_string::<i64>(), options),
548 DataType::Utf8View => array_format(array.as_string_view(), options),
549 DataType::Binary => array_format(array.as_binary::<i32>(), options),
550 DataType::BinaryView => array_format(array.as_binary_view(), options),
551 DataType::LargeBinary => array_format(array.as_binary::<i64>(), options),
552 DataType::FixedSizeBinary(_) => {
553 let a = array.as_any().downcast_ref::<FixedSizeBinaryArray>().unwrap();
554 array_format(a, options)
555 }
556 DataType::Dictionary(_, _) => downcast_dictionary_array! {
557 array => array_format(array, options),
558 _ => unreachable!()
559 }
560 DataType::List(_) => array_format(as_generic_list_array::<i32>(array), options),
561 DataType::LargeList(_) => array_format(as_generic_list_array::<i64>(array), options),
562 DataType::ListView(_) => array_format(array.as_list_view::<i32>(), options),
563 DataType::LargeListView(_) => array_format(array.as_list_view::<i64>(), options),
564 DataType::FixedSizeList(_, _) => {
565 let a = array.as_any().downcast_ref::<FixedSizeListArray>().unwrap();
566 array_format(a, options)
567 }
568 DataType::Struct(_) => array_format(as_struct_array(array), options),
569 DataType::Map(_, _) => array_format(as_map_array(array), options),
570 DataType::Union(_, _) => array_format(as_union_array(array), options),
571 DataType::RunEndEncoded(_, _) => downcast_run_array! {
572 array => array_format(array, options),
573 _ => unreachable!()
574 },
575 d => Err(ArrowError::NotYetImplemented(format!("formatting {d} is not yet supported"))),
576 }
577}
578
579pub enum FormatError {
581 Format(std::fmt::Error),
583 Arrow(ArrowError),
585}
586
587pub type FormatResult = Result<(), FormatError>;
589
590impl From<std::fmt::Error> for FormatError {
591 fn from(value: std::fmt::Error) -> Self {
592 Self::Format(value)
593 }
594}
595
596impl From<ArrowError> for FormatError {
597 fn from(value: ArrowError) -> Self {
598 Self::Arrow(value)
599 }
600}
601
602pub trait DisplayIndex {
604 fn write(&self, idx: usize, f: &mut dyn Write) -> FormatResult;
606}
607
608trait DisplayIndexState<'a> {
610 type State;
611
612 fn prepare(&self, options: &FormatOptions<'a>) -> Result<Self::State, ArrowError>;
613
614 fn write(&self, state: &Self::State, idx: usize, f: &mut dyn Write) -> FormatResult;
615}
616
617impl<'a, T: DisplayIndex> DisplayIndexState<'a> for T {
618 type State = ();
619
620 fn prepare(&self, _options: &FormatOptions<'a>) -> Result<Self::State, ArrowError> {
621 Ok(())
622 }
623
624 fn write(&self, (): &Self::State, idx: usize, f: &mut dyn Write) -> FormatResult {
625 DisplayIndex::write(self, idx, f)
626 }
627}
628
629struct ArrayFormat<'a, F: DisplayIndexState<'a>> {
630 state: F::State,
631 array: F,
632 null: &'a str,
633}
634
635fn array_format<'a, F>(
636 array: F,
637 options: &FormatOptions<'a>,
638) -> Result<Box<dyn DisplayIndex + 'a>, ArrowError>
639where
640 F: DisplayIndexState<'a> + Array + 'a,
641{
642 let state = array.prepare(options)?;
643 Ok(Box::new(ArrayFormat {
644 state,
645 array,
646 null: options.null,
647 }))
648}
649
650impl<'a, F: DisplayIndexState<'a> + Array> DisplayIndex for ArrayFormat<'a, F> {
651 fn write(&self, idx: usize, f: &mut dyn Write) -> FormatResult {
652 if self.array.is_null(idx) {
653 if !self.null.is_empty() {
654 f.write_str(self.null)?
655 }
656 return Ok(());
657 }
658 DisplayIndexState::write(&self.array, &self.state, idx, f)
659 }
660}
661
662impl DisplayIndex for &BooleanArray {
663 fn write(&self, idx: usize, f: &mut dyn Write) -> FormatResult {
664 f.write_str(if self.value(idx) { "true" } else { "false" })?;
665 Ok(())
666 }
667}
668
669impl<'a> DisplayIndexState<'a> for &'a NullArray {
670 type State = &'a str;
671
672 fn prepare(&self, options: &FormatOptions<'a>) -> Result<Self::State, ArrowError> {
673 Ok(options.null)
674 }
675
676 fn write(&self, state: &Self::State, _idx: usize, f: &mut dyn Write) -> FormatResult {
677 f.write_str(state)?;
678 Ok(())
679 }
680}
681
682macro_rules! primitive_display {
683 ($($t:ty),+) => {
684 $(impl<'a> DisplayIndex for &'a PrimitiveArray<$t>
685 {
686 fn write(&self, idx: usize, f: &mut dyn Write) -> FormatResult {
687 let value = self.value(idx);
688 let mut buffer = [0u8; <$t as ArrowPrimitiveType>::Native::FORMATTED_SIZE];
689 let b = lexical_core::write(value, &mut buffer);
690 let s = unsafe { std::str::from_utf8_unchecked(b) };
692 f.write_str(s)?;
693 Ok(())
694 }
695 })+
696 };
697}
698
699macro_rules! primitive_display_float {
700 ($($t:ty),+) => {
701 $(impl<'a> DisplayIndex for &'a PrimitiveArray<$t>
702 {
703 fn write(&self, idx: usize, f: &mut dyn Write) -> FormatResult {
704 let value = self.value(idx);
705 let mut buffer = ryu::Buffer::new();
706 f.write_str(buffer.format(value))?;
707 Ok(())
708 }
709 })+
710 };
711}
712
713primitive_display!(Int8Type, Int16Type, Int32Type, Int64Type);
714primitive_display!(UInt8Type, UInt16Type, UInt32Type, UInt64Type);
715primitive_display_float!(Float32Type, Float64Type);
716
717impl DisplayIndex for &PrimitiveArray<Float16Type> {
718 fn write(&self, idx: usize, f: &mut dyn Write) -> FormatResult {
719 write!(f, "{}", self.value(idx))?;
720 Ok(())
721 }
722}
723
724macro_rules! decimal_display {
725 ($($t:ty),+) => {
726 $(impl<'a> DisplayIndexState<'a> for &'a PrimitiveArray<$t> {
727 type State = i8;
728
729 fn prepare(&self, _options: &FormatOptions<'a>) -> Result<Self::State, ArrowError> {
730 Ok(self.scale())
731 }
732
733 fn write(&self, scale: &Self::State, idx: usize, f: &mut dyn Write) -> FormatResult {
734 write_decimal(f, self.values()[idx], *scale)?;
735 Ok(())
736 }
737 })+
738 };
739}
740
741decimal_display!(Decimal32Type, Decimal64Type, Decimal128Type, Decimal256Type);
742
743fn write_timestamp(
744 f: &mut dyn Write,
745 naive: NaiveDateTime,
746 timezone: Option<Tz>,
747 format: &CompiledTimeFormat<'_>,
748) -> FormatResult {
749 match timezone {
750 Some(tz) => {
751 let date = Utc.from_utc_datetime(&naive).with_timezone(&tz);
752 match format {
753 CompiledTimeFormat::Custom(items) => {
754 write!(f, "{}", date.format_with_items(items.0.iter()))?
755 }
756 CompiledTimeFormat::Default => {
757 write!(f, "{}", date.to_rfc3339_opts(SecondsFormat::AutoSi, true))?
758 }
759 }
760 }
761 None => match format {
762 CompiledTimeFormat::Custom(items) => {
763 write!(f, "{}", naive.format_with_items(items.0.iter()))?
764 }
765 CompiledTimeFormat::Default => write!(f, "{naive:?}")?,
766 },
767 }
768 Ok(())
769}
770
771macro_rules! timestamp_display {
772 ($($t:ty),+) => {
773 $(impl<'a> DisplayIndexState<'a> for &'a PrimitiveArray<$t> {
774 type State = (Option<Tz>, CompiledTimeFormat<'a>);
775
776 fn prepare(&self, options: &FormatOptions<'a>) -> Result<Self::State, ArrowError> {
777 match self.data_type() {
778 DataType::Timestamp(_, Some(tz)) => Ok((Some(tz.parse()?), CompiledTimeFormat::new(options.timestamp_tz_format))),
779 DataType::Timestamp(_, None) => Ok((None, CompiledTimeFormat::new(options.timestamp_format))),
780 _ => unreachable!(),
781 }
782 }
783
784 fn write(&self, s: &Self::State, idx: usize, f: &mut dyn Write) -> FormatResult {
785 let value = self.value(idx);
786 let naive = as_datetime::<$t>(value).ok_or_else(|| {
787 ArrowError::CastError(format!(
788 "Failed to convert {} to datetime for {}",
789 value,
790 self.data_type()
791 ))
792 })?;
793
794 write_timestamp(f, naive, s.0, &s.1)
795 }
796 })+
797 };
798}
799
800timestamp_display!(
801 TimestampSecondType,
802 TimestampMillisecondType,
803 TimestampMicrosecondType,
804 TimestampNanosecondType
805);
806
807macro_rules! temporal_display {
808 ($convert:ident, $format:ident, $t:ty) => {
809 impl<'a> DisplayIndexState<'a> for &'a PrimitiveArray<$t> {
810 type State = CompiledTimeFormat<'a>;
811
812 fn prepare(&self, options: &FormatOptions<'a>) -> Result<Self::State, ArrowError> {
813 Ok(CompiledTimeFormat::new(options.$format))
814 }
815
816 fn write(&self, fmt: &Self::State, idx: usize, f: &mut dyn Write) -> FormatResult {
817 let value = self.value(idx);
818 let naive = $convert(value).ok_or_else(|| {
819 ArrowError::CastError(format!(
820 "Failed to convert {} to temporal for {}",
821 value,
822 self.data_type()
823 ))
824 })?;
825
826 match fmt {
827 CompiledTimeFormat::Custom(items) => {
828 write!(f, "{}", naive.format_with_items(items.0.iter()))?
829 }
830 CompiledTimeFormat::Default => write!(f, "{naive:?}")?,
831 }
832 Ok(())
833 }
834 }
835 };
836}
837
838#[inline]
839fn date32_to_date(value: i32) -> Option<NaiveDate> {
840 Some(date32_to_datetime(value)?.date())
841}
842
843temporal_display!(date32_to_date, date_format, Date32Type);
844temporal_display!(date64_to_datetime, datetime_format, Date64Type);
845temporal_display!(time32s_to_time, time_format, Time32SecondType);
846temporal_display!(time32ms_to_time, time_format, Time32MillisecondType);
847temporal_display!(time64us_to_time, time_format, Time64MicrosecondType);
848temporal_display!(time64ns_to_time, time_format, Time64NanosecondType);
849
850macro_rules! duration_display {
857 ($convert:ident, $t:ty, $scale:tt) => {
858 impl<'a> DisplayIndexState<'a> for &'a PrimitiveArray<$t> {
859 type State = DurationFormat;
860
861 fn prepare(&self, options: &FormatOptions<'a>) -> Result<Self::State, ArrowError> {
862 Ok(options.duration_format)
863 }
864
865 fn write(&self, fmt: &Self::State, idx: usize, f: &mut dyn Write) -> FormatResult {
866 let v = self.value(idx);
867 match fmt {
868 DurationFormat::ISO8601 => write!(f, "{}", $convert(v))?,
869 DurationFormat::Pretty => duration_fmt!(f, v, $scale)?,
870 }
871 Ok(())
872 }
873 }
874 };
875}
876
877macro_rules! duration_option_display {
879 ($convert:ident, $t:ty, $scale:tt) => {
880 impl<'a> DisplayIndexState<'a> for &'a PrimitiveArray<$t> {
881 type State = DurationFormat;
882
883 fn prepare(&self, options: &FormatOptions<'a>) -> Result<Self::State, ArrowError> {
884 Ok(options.duration_format)
885 }
886
887 fn write(&self, fmt: &Self::State, idx: usize, f: &mut dyn Write) -> FormatResult {
888 let v = self.value(idx);
889 match fmt {
890 DurationFormat::ISO8601 => match $convert(v) {
891 Some(td) => write!(f, "{}", td)?,
892 None => write!(f, "<invalid>")?,
893 },
894 DurationFormat::Pretty => match $convert(v) {
895 Some(_) => duration_fmt!(f, v, $scale)?,
896 None => write!(f, "<invalid>")?,
897 },
898 }
899 Ok(())
900 }
901 }
902 };
903}
904
905macro_rules! duration_fmt {
906 ($f:ident, $v:expr, 0) => {{
907 let secs = $v;
908 let mins = secs / 60;
909 let hours = mins / 60;
910 let days = hours / 24;
911
912 let secs = secs - (mins * 60);
913 let mins = mins - (hours * 60);
914 let hours = hours - (days * 24);
915 write!($f, "{days} days {hours} hours {mins} mins {secs} secs")
916 }};
917 ($f:ident, $v:expr, $scale:tt) => {{
918 let subsec = $v;
919 let secs = subsec / 10_i64.pow($scale);
920 let mins = secs / 60;
921 let hours = mins / 60;
922 let days = hours / 24;
923
924 let subsec = subsec - (secs * 10_i64.pow($scale));
925 let secs = secs - (mins * 60);
926 let mins = mins - (hours * 60);
927 let hours = hours - (days * 24);
928 match subsec.is_negative() {
929 true => {
930 write!(
931 $f,
932 concat!("{} days {} hours {} mins -{}.{:0", $scale, "} secs"),
933 days,
934 hours,
935 mins,
936 secs.abs(),
937 subsec.abs()
938 )
939 }
940 false => {
941 write!(
942 $f,
943 concat!("{} days {} hours {} mins {}.{:0", $scale, "} secs"),
944 days, hours, mins, secs, subsec
945 )
946 }
947 }
948 }};
949}
950
951duration_option_display!(try_duration_s_to_duration, DurationSecondType, 0);
952duration_option_display!(try_duration_ms_to_duration, DurationMillisecondType, 3);
953duration_display!(duration_us_to_duration, DurationMicrosecondType, 6);
954duration_display!(duration_ns_to_duration, DurationNanosecondType, 9);
955
956impl DisplayIndex for &PrimitiveArray<IntervalYearMonthType> {
957 fn write(&self, idx: usize, f: &mut dyn Write) -> FormatResult {
958 let interval = self.value(idx) as f64;
959 let years = (interval / 12_f64).floor();
960 let month = interval - (years * 12_f64);
961
962 write!(f, "{years} years {month} mons")?;
963 Ok(())
964 }
965}
966
967impl DisplayIndex for &PrimitiveArray<IntervalDayTimeType> {
968 fn write(&self, idx: usize, f: &mut dyn Write) -> FormatResult {
969 let value = self.value(idx);
970
971 if value.is_zero() {
972 write!(f, "0 secs")?;
973 return Ok(());
974 }
975
976 let mut prefix = "";
977
978 if value.days != 0 {
979 write!(f, "{prefix}{} days", value.days)?;
980 prefix = " ";
981 }
982
983 if value.milliseconds != 0 {
984 let millis_fmt = MillisecondsFormatter {
985 milliseconds: value.milliseconds,
986 prefix,
987 };
988
989 f.write_fmt(format_args!("{millis_fmt}"))?;
990 }
991
992 Ok(())
993 }
994}
995
996impl DisplayIndex for &PrimitiveArray<IntervalMonthDayNanoType> {
997 fn write(&self, idx: usize, f: &mut dyn Write) -> FormatResult {
998 let value = self.value(idx);
999
1000 if value.is_zero() {
1001 write!(f, "0 secs")?;
1002 return Ok(());
1003 }
1004
1005 let mut prefix = "";
1006
1007 if value.months != 0 {
1008 write!(f, "{prefix}{} mons", value.months)?;
1009 prefix = " ";
1010 }
1011
1012 if value.days != 0 {
1013 write!(f, "{prefix}{} days", value.days)?;
1014 prefix = " ";
1015 }
1016
1017 if value.nanoseconds != 0 {
1018 let nano_fmt = NanosecondsFormatter {
1019 nanoseconds: value.nanoseconds,
1020 prefix,
1021 };
1022 f.write_fmt(format_args!("{nano_fmt}"))?;
1023 }
1024
1025 Ok(())
1026 }
1027}
1028
1029struct NanosecondsFormatter<'a> {
1030 nanoseconds: i64,
1031 prefix: &'a str,
1032}
1033
1034impl Display for NanosecondsFormatter<'_> {
1035 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
1036 let mut prefix = self.prefix;
1037
1038 let secs = self.nanoseconds / 1_000_000_000;
1039 let mins = secs / 60;
1040 let hours = mins / 60;
1041
1042 let secs = secs - (mins * 60);
1043 let mins = mins - (hours * 60);
1044
1045 let nanoseconds = self.nanoseconds % 1_000_000_000;
1046
1047 if hours != 0 {
1048 write!(f, "{prefix}{hours} hours")?;
1049 prefix = " ";
1050 }
1051
1052 if mins != 0 {
1053 write!(f, "{prefix}{mins} mins")?;
1054 prefix = " ";
1055 }
1056
1057 if secs != 0 || nanoseconds != 0 {
1058 let secs_sign = if secs < 0 || nanoseconds < 0 { "-" } else { "" };
1059 write!(
1060 f,
1061 "{prefix}{}{}.{:09} secs",
1062 secs_sign,
1063 secs.abs(),
1064 nanoseconds.abs()
1065 )?;
1066 }
1067
1068 Ok(())
1069 }
1070}
1071
1072struct MillisecondsFormatter<'a> {
1073 milliseconds: i32,
1074 prefix: &'a str,
1075}
1076
1077impl Display for MillisecondsFormatter<'_> {
1078 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
1079 let mut prefix = self.prefix;
1080
1081 let secs = self.milliseconds / 1_000;
1082 let mins = secs / 60;
1083 let hours = mins / 60;
1084
1085 let secs = secs - (mins * 60);
1086 let mins = mins - (hours * 60);
1087
1088 let milliseconds = self.milliseconds % 1_000;
1089
1090 if hours != 0 {
1091 write!(f, "{prefix}{hours} hours")?;
1092 prefix = " ";
1093 }
1094
1095 if mins != 0 {
1096 write!(f, "{prefix}{mins} mins")?;
1097 prefix = " ";
1098 }
1099
1100 if secs != 0 || milliseconds != 0 {
1101 let secs_sign = if secs < 0 || milliseconds < 0 {
1102 "-"
1103 } else {
1104 ""
1105 };
1106
1107 write!(
1108 f,
1109 "{prefix}{}{}.{:03} secs",
1110 secs_sign,
1111 secs.abs(),
1112 milliseconds.abs()
1113 )?;
1114 }
1115
1116 Ok(())
1117 }
1118}
1119
1120impl<'a, O: OffsetSizeTrait> DisplayIndexState<'a> for &'a GenericStringArray<O> {
1121 type State = bool;
1122
1123 fn prepare(&self, options: &FormatOptions<'a>) -> Result<Self::State, ArrowError> {
1124 Ok(options.quoted_strings())
1125 }
1126
1127 fn write(&self, state: &Self::State, idx: usize, f: &mut dyn Write) -> FormatResult {
1128 let value = self.value(idx);
1129 if *state {
1130 write!(f, "{value:?}")?;
1131 } else {
1132 write!(f, "{value}")?;
1133 }
1134 Ok(())
1135 }
1136}
1137
1138impl<'a> DisplayIndexState<'a> for &'a StringViewArray {
1139 type State = bool;
1140
1141 fn prepare(&self, options: &FormatOptions<'a>) -> Result<Self::State, ArrowError> {
1142 Ok(options.quoted_strings())
1143 }
1144
1145 fn write(&self, state: &Self::State, idx: usize, f: &mut dyn Write) -> FormatResult {
1146 let value = self.value(idx);
1147 if *state {
1148 write!(f, "{value:?}")?;
1149 } else {
1150 write!(f, "{value}")?;
1151 }
1152 Ok(())
1153 }
1154}
1155
1156impl<O: OffsetSizeTrait> DisplayIndex for &GenericBinaryArray<O> {
1157 fn write(&self, idx: usize, f: &mut dyn Write) -> FormatResult {
1158 let v = self.value(idx);
1159 for byte in v {
1160 write!(f, "{byte:02x}")?;
1161 }
1162 Ok(())
1163 }
1164}
1165
1166impl DisplayIndex for &BinaryViewArray {
1167 fn write(&self, idx: usize, f: &mut dyn Write) -> FormatResult {
1168 let v = self.value(idx);
1169 for byte in v {
1170 write!(f, "{byte:02x}")?;
1171 }
1172 Ok(())
1173 }
1174}
1175
1176impl DisplayIndex for &FixedSizeBinaryArray {
1177 fn write(&self, idx: usize, f: &mut dyn Write) -> FormatResult {
1178 let v = self.value(idx);
1179 for byte in v {
1180 write!(f, "{byte:02x}")?;
1181 }
1182 Ok(())
1183 }
1184}
1185
1186impl<'a, K: ArrowDictionaryKeyType> DisplayIndexState<'a> for &'a DictionaryArray<K> {
1187 type State = Box<dyn DisplayIndex + 'a>;
1188
1189 fn prepare(&self, options: &FormatOptions<'a>) -> Result<Self::State, ArrowError> {
1190 make_default_display_index(self.values().as_ref(), options)
1191 }
1192
1193 fn write(&self, s: &Self::State, idx: usize, f: &mut dyn Write) -> FormatResult {
1194 let value_idx = self.keys().values()[idx].as_usize();
1195 s.as_ref().write(value_idx, f)
1196 }
1197}
1198
1199impl<'a, K: RunEndIndexType> DisplayIndexState<'a> for &'a RunArray<K> {
1200 type State = ArrayFormatter<'a>;
1201
1202 fn prepare(&self, options: &FormatOptions<'a>) -> Result<Self::State, ArrowError> {
1203 let DataType::RunEndEncoded(_, field) = (*self).data_type() else {
1204 unreachable!()
1205 };
1206 make_array_formatter(self.values().as_ref(), options, Some(field))
1207 }
1208
1209 fn write(&self, s: &Self::State, idx: usize, f: &mut dyn Write) -> FormatResult {
1210 let value_idx = self.get_physical_index(idx);
1211 write!(f, "{}", s.value(value_idx))?;
1212 Ok(())
1213 }
1214}
1215
1216fn write_list(
1217 f: &mut dyn Write,
1218 mut range: Range<usize>,
1219 values: &ArrayFormatter<'_>,
1220) -> FormatResult {
1221 f.write_char('[')?;
1222 if let Some(idx) = range.next() {
1223 write!(f, "{}", values.value(idx))?;
1224 }
1225 for idx in range {
1226 write!(f, ", {}", values.value(idx))?;
1227 }
1228 f.write_char(']')?;
1229 Ok(())
1230}
1231
1232impl<'a, O: OffsetSizeTrait> DisplayIndexState<'a> for &'a GenericListArray<O> {
1233 type State = ArrayFormatter<'a>;
1234
1235 fn prepare(&self, options: &FormatOptions<'a>) -> Result<Self::State, ArrowError> {
1236 let field = match (*self).data_type() {
1237 DataType::List(f) => f,
1238 DataType::LargeList(f) => f,
1239 _ => unreachable!(),
1240 };
1241 make_array_formatter(self.values().as_ref(), options, Some(field.as_ref()))
1242 }
1243
1244 fn write(&self, s: &Self::State, idx: usize, f: &mut dyn Write) -> FormatResult {
1245 let offsets = self.value_offsets();
1246 let end = offsets[idx + 1].as_usize();
1247 let start = offsets[idx].as_usize();
1248 write_list(f, start..end, s)
1249 }
1250}
1251
1252impl<'a, O: OffsetSizeTrait> DisplayIndexState<'a> for &'a GenericListViewArray<O> {
1253 type State = ArrayFormatter<'a>;
1254
1255 fn prepare(&self, options: &FormatOptions<'a>) -> Result<Self::State, ArrowError> {
1256 let field = match (*self).data_type() {
1257 DataType::ListView(f) => f,
1258 DataType::LargeListView(f) => f,
1259 _ => unreachable!(),
1260 };
1261 make_array_formatter(self.values().as_ref(), options, Some(field.as_ref()))
1262 }
1263
1264 fn write(&self, s: &Self::State, idx: usize, f: &mut dyn Write) -> FormatResult {
1265 let offsets = self.value_offsets();
1266 let sizes = self.value_sizes();
1267 let start = offsets[idx].as_usize();
1268 let end = start + sizes[idx].as_usize();
1269 write_list(f, start..end, s)
1270 }
1271}
1272
1273impl<'a> DisplayIndexState<'a> for &'a FixedSizeListArray {
1274 type State = (usize, ArrayFormatter<'a>);
1275
1276 fn prepare(&self, options: &FormatOptions<'a>) -> Result<Self::State, ArrowError> {
1277 let DataType::FixedSizeList(field, _) = (*self).data_type() else {
1278 unreachable!()
1279 };
1280 let formatter =
1281 make_array_formatter(self.values().as_ref(), options, Some(field.as_ref()))?;
1282 let length = self.value_length();
1283 Ok((length as usize, formatter))
1284 }
1285
1286 fn write(&self, s: &Self::State, idx: usize, f: &mut dyn Write) -> FormatResult {
1287 let start = idx * s.0;
1288 let end = start + s.0;
1289 write_list(f, start..end, &s.1)
1290 }
1291}
1292
1293type FieldDisplay<'a> = (&'a str, ArrayFormatter<'a>);
1295
1296impl<'a> DisplayIndexState<'a> for &'a StructArray {
1297 type State = Vec<FieldDisplay<'a>>;
1298
1299 fn prepare(&self, options: &FormatOptions<'a>) -> Result<Self::State, ArrowError> {
1300 let DataType::Struct(fields) = (*self).data_type() else {
1301 unreachable!()
1302 };
1303
1304 self.columns()
1305 .iter()
1306 .zip(fields)
1307 .map(|(a, f)| {
1308 let format = make_array_formatter(a.as_ref(), options, Some(f))?;
1309 Ok((f.name().as_str(), format))
1310 })
1311 .collect()
1312 }
1313
1314 fn write(&self, s: &Self::State, idx: usize, f: &mut dyn Write) -> FormatResult {
1315 let mut iter = s.iter();
1316 f.write_char('{')?;
1317 if let Some((name, display)) = iter.next() {
1318 write!(f, "{name}: {}", display.value(idx))?;
1319 }
1320 for (name, display) in iter {
1321 write!(f, ", {name}: {}", display.value(idx))?;
1322 }
1323 f.write_char('}')?;
1324 Ok(())
1325 }
1326}
1327
1328impl<'a> DisplayIndexState<'a> for &'a MapArray {
1329 type State = (ArrayFormatter<'a>, ArrayFormatter<'a>);
1330
1331 fn prepare(&self, options: &FormatOptions<'a>) -> Result<Self::State, ArrowError> {
1332 let (key_field, value_field) = (*self).entries_fields();
1333
1334 let keys = make_array_formatter(self.keys().as_ref(), options, Some(key_field))?;
1335 let values = make_array_formatter(self.values().as_ref(), options, Some(value_field))?;
1336 Ok((keys, values))
1337 }
1338
1339 fn write(&self, s: &Self::State, idx: usize, f: &mut dyn Write) -> FormatResult {
1340 let offsets = self.value_offsets();
1341 let end = offsets[idx + 1].as_usize();
1342 let start = offsets[idx].as_usize();
1343 let mut iter = start..end;
1344
1345 f.write_char('{')?;
1346 if let Some(idx) = iter.next() {
1347 write!(f, "{}: {}", s.0.value(idx), s.1.value(idx))?;
1348 }
1349
1350 for idx in iter {
1351 write!(f, ", {}", s.0.value(idx))?;
1352 write!(f, ": {}", s.1.value(idx))?;
1353 }
1354
1355 f.write_char('}')?;
1356 Ok(())
1357 }
1358}
1359
1360impl<'a> DisplayIndexState<'a> for &'a UnionArray {
1361 type State = (Vec<Option<FieldDisplay<'a>>>, UnionMode);
1362
1363 fn prepare(&self, options: &FormatOptions<'a>) -> Result<Self::State, ArrowError> {
1364 let DataType::Union(fields, mode) = (*self).data_type() else {
1365 unreachable!()
1366 };
1367
1368 let max_id = fields.iter().map(|(id, _)| id).max().unwrap_or_default() as usize;
1369 let mut out: Vec<Option<FieldDisplay>> = (0..max_id + 1).map(|_| None).collect();
1370 for (i, field) in fields.iter() {
1371 let formatter = make_array_formatter(self.child(i).as_ref(), options, Some(field))?;
1372 out[i as usize] = Some((field.name().as_str(), formatter))
1373 }
1374 Ok((out, *mode))
1375 }
1376
1377 fn write(&self, s: &Self::State, idx: usize, f: &mut dyn Write) -> FormatResult {
1378 let id = self.type_id(idx);
1379 let idx = match s.1 {
1380 UnionMode::Dense => self.value_offset(idx),
1381 UnionMode::Sparse => idx,
1382 };
1383 let (name, field) = s.0[id as usize].as_ref().unwrap();
1384
1385 write!(f, "{{{name}={}}}", field.value(idx))?;
1386 Ok(())
1387 }
1388}
1389
1390pub fn array_value_to_string(column: &dyn Array, row: usize) -> Result<String, ArrowError> {
1397 let options = FormatOptions::default().with_display_error(true);
1398 let formatter = ArrayFormatter::try_new(column, &options)?;
1399 Ok(formatter.value(row).to_string())
1400}
1401
1402pub fn lexical_to_string<N: lexical_core::ToLexical>(n: N) -> String {
1404 let mut buf = Vec::<u8>::with_capacity(N::FORMATTED_SIZE_DECIMAL);
1405 unsafe {
1406 let slice = std::slice::from_raw_parts_mut(buf.as_mut_ptr(), buf.capacity());
1413 let len = lexical_core::write(n, slice).len();
1414 buf.set_len(len);
1415 String::from_utf8_unchecked(buf)
1416 }
1417}
1418
1419#[cfg(test)]
1420mod tests {
1421 use super::*;
1422 use arrow_array::builder::StringRunBuilder;
1423 const TEST_CONST_OPTIONS: FormatOptions<'static> = FormatOptions::new()
1425 .with_date_format(Some("foo"))
1426 .with_timestamp_format(Some("404"));
1427
1428 #[test]
1429 fn test_const_options() {
1430 assert_eq!(TEST_CONST_OPTIONS.date_format, Some("foo"));
1431 }
1432
1433 #[test]
1435 fn test_options_send_sync() {
1436 fn assert_send_sync<T>()
1437 where
1438 T: Send + Sync,
1439 {
1440 }
1442
1443 assert_send_sync::<FormatOptions<'static>>();
1444 }
1445
1446 #[test]
1447 fn test_map_array_to_string() {
1448 let keys = vec!["a", "b", "c", "d", "e", "f", "g", "h"];
1449 let values_data = UInt32Array::from(vec![0u32, 10, 20, 30, 40, 50, 60, 70]);
1450
1451 let entry_offsets = [0, 3, 6, 8];
1454
1455 let map_array =
1456 MapArray::new_from_strings(keys.clone().into_iter(), &values_data, &entry_offsets)
1457 .unwrap();
1458 assert_eq!(
1459 "{d: 30, e: 40, f: 50}",
1460 array_value_to_string(&map_array, 1).unwrap()
1461 );
1462 }
1463
1464 fn format_array(array: &dyn Array, fmt: &FormatOptions) -> Vec<String> {
1465 let fmt = ArrayFormatter::try_new(array, fmt).unwrap();
1466 (0..array.len()).map(|x| fmt.value(x).to_string()).collect()
1467 }
1468
1469 #[test]
1470 fn test_temporal_custom_format() {
1471 let options = FormatOptions::new()
1472 .with_date_format(Some("%Y-%m-%d"))
1473 .with_datetime_format(Some("%Y-%m-%d %H:%M:%S"))
1474 .with_time_format(Some("%H:%M:%S"))
1475 .with_timestamp_format(Some("%Y-%m-%d %H:%M:%S"))
1476 .with_timestamp_tz_format(Some("%Y-%m-%d %H:%M:%S %:z"));
1477
1478 let date32 = Date32Array::from(vec![0]);
1479 assert_eq!(format_array(&date32, &options), ["1970-01-01"]);
1480
1481 let date64 = Date64Array::from(vec![0]);
1482 assert_eq!(format_array(&date64, &options), ["1970-01-01 00:00:00"]);
1483
1484 let time = Time32SecondArray::from(vec![3661]);
1485 assert_eq!(format_array(&time, &options), ["01:01:01"]);
1486
1487 let timestamp = TimestampSecondArray::from(vec![0]);
1488 assert_eq!(format_array(×tamp, &options), ["1970-01-01 00:00:00"]);
1489
1490 let timestamp_tz = TimestampSecondArray::from(vec![0]).with_timezone("+08:00");
1491 assert_eq!(
1492 format_array(×tamp_tz, &options),
1493 ["1970-01-01 08:00:00 +08:00"]
1494 );
1495
1496 let invalid_options = FormatOptions::new().with_datetime_format(Some("%"));
1497 let formatter = ArrayFormatter::try_new(&date64, &invalid_options).unwrap();
1498 assert!(formatter.value(0).try_to_string().is_err());
1499 }
1500
1501 #[test]
1502 fn test_array_value_to_string_duration() {
1503 let iso_fmt = FormatOptions::new();
1504 let pretty_fmt = FormatOptions::new().with_duration_format(DurationFormat::Pretty);
1505
1506 let array = DurationNanosecondArray::from(vec![
1507 1,
1508 -1,
1509 1000,
1510 -1000,
1511 (45 * 60 * 60 * 24 + 14 * 60 * 60 + 2 * 60 + 34) * 1_000_000_000 + 123456789,
1512 -(45 * 60 * 60 * 24 + 14 * 60 * 60 + 2 * 60 + 34) * 1_000_000_000 - 123456789,
1513 ]);
1514 let iso = format_array(&array, &iso_fmt);
1515 let pretty = format_array(&array, &pretty_fmt);
1516
1517 assert_eq!(iso[0], "PT0.000000001S");
1518 assert_eq!(pretty[0], "0 days 0 hours 0 mins 0.000000001 secs");
1519 assert_eq!(iso[1], "-PT0.000000001S");
1520 assert_eq!(pretty[1], "0 days 0 hours 0 mins -0.000000001 secs");
1521 assert_eq!(iso[2], "PT0.000001S");
1522 assert_eq!(pretty[2], "0 days 0 hours 0 mins 0.000001000 secs");
1523 assert_eq!(iso[3], "-PT0.000001S");
1524 assert_eq!(pretty[3], "0 days 0 hours 0 mins -0.000001000 secs");
1525 assert_eq!(iso[4], "PT3938554.123456789S");
1526 assert_eq!(pretty[4], "45 days 14 hours 2 mins 34.123456789 secs");
1527 assert_eq!(iso[5], "-PT3938554.123456789S");
1528 assert_eq!(pretty[5], "-45 days -14 hours -2 mins -34.123456789 secs");
1529
1530 let array = DurationMicrosecondArray::from(vec![
1531 1,
1532 -1,
1533 1000,
1534 -1000,
1535 (45 * 60 * 60 * 24 + 14 * 60 * 60 + 2 * 60 + 34) * 1_000_000 + 123456,
1536 -(45 * 60 * 60 * 24 + 14 * 60 * 60 + 2 * 60 + 34) * 1_000_000 - 123456,
1537 ]);
1538 let iso = format_array(&array, &iso_fmt);
1539 let pretty = format_array(&array, &pretty_fmt);
1540
1541 assert_eq!(iso[0], "PT0.000001S");
1542 assert_eq!(pretty[0], "0 days 0 hours 0 mins 0.000001 secs");
1543 assert_eq!(iso[1], "-PT0.000001S");
1544 assert_eq!(pretty[1], "0 days 0 hours 0 mins -0.000001 secs");
1545 assert_eq!(iso[2], "PT0.001S");
1546 assert_eq!(pretty[2], "0 days 0 hours 0 mins 0.001000 secs");
1547 assert_eq!(iso[3], "-PT0.001S");
1548 assert_eq!(pretty[3], "0 days 0 hours 0 mins -0.001000 secs");
1549 assert_eq!(iso[4], "PT3938554.123456S");
1550 assert_eq!(pretty[4], "45 days 14 hours 2 mins 34.123456 secs");
1551 assert_eq!(iso[5], "-PT3938554.123456S");
1552 assert_eq!(pretty[5], "-45 days -14 hours -2 mins -34.123456 secs");
1553
1554 let array = DurationMillisecondArray::from(vec![
1555 1,
1556 -1,
1557 1000,
1558 -1000,
1559 (45 * 60 * 60 * 24 + 14 * 60 * 60 + 2 * 60 + 34) * 1_000 + 123,
1560 -(45 * 60 * 60 * 24 + 14 * 60 * 60 + 2 * 60 + 34) * 1_000 - 123,
1561 ]);
1562 let iso = format_array(&array, &iso_fmt);
1563 let pretty = format_array(&array, &pretty_fmt);
1564
1565 assert_eq!(iso[0], "PT0.001S");
1566 assert_eq!(pretty[0], "0 days 0 hours 0 mins 0.001 secs");
1567 assert_eq!(iso[1], "-PT0.001S");
1568 assert_eq!(pretty[1], "0 days 0 hours 0 mins -0.001 secs");
1569 assert_eq!(iso[2], "PT1S");
1570 assert_eq!(pretty[2], "0 days 0 hours 0 mins 1.000 secs");
1571 assert_eq!(iso[3], "-PT1S");
1572 assert_eq!(pretty[3], "0 days 0 hours 0 mins -1.000 secs");
1573 assert_eq!(iso[4], "PT3938554.123S");
1574 assert_eq!(pretty[4], "45 days 14 hours 2 mins 34.123 secs");
1575 assert_eq!(iso[5], "-PT3938554.123S");
1576 assert_eq!(pretty[5], "-45 days -14 hours -2 mins -34.123 secs");
1577
1578 let array = DurationSecondArray::from(vec![
1579 1,
1580 -1,
1581 1000,
1582 -1000,
1583 45 * 60 * 60 * 24 + 14 * 60 * 60 + 2 * 60 + 34,
1584 -45 * 60 * 60 * 24 - 14 * 60 * 60 - 2 * 60 - 34,
1585 ]);
1586 let iso = format_array(&array, &iso_fmt);
1587 let pretty = format_array(&array, &pretty_fmt);
1588
1589 assert_eq!(iso[0], "PT1S");
1590 assert_eq!(pretty[0], "0 days 0 hours 0 mins 1 secs");
1591 assert_eq!(iso[1], "-PT1S");
1592 assert_eq!(pretty[1], "0 days 0 hours 0 mins -1 secs");
1593 assert_eq!(iso[2], "PT1000S");
1594 assert_eq!(pretty[2], "0 days 0 hours 16 mins 40 secs");
1595 assert_eq!(iso[3], "-PT1000S");
1596 assert_eq!(pretty[3], "0 days 0 hours -16 mins -40 secs");
1597 assert_eq!(iso[4], "PT3938554S");
1598 assert_eq!(pretty[4], "45 days 14 hours 2 mins 34 secs");
1599 assert_eq!(iso[5], "-PT3938554S");
1600 assert_eq!(pretty[5], "-45 days -14 hours -2 mins -34 secs");
1601 }
1602
1603 #[test]
1604 fn test_null() {
1605 let array = NullArray::new(2);
1606 let options = FormatOptions::new().with_null("NULL");
1607 let formatted = format_array(&array, &options);
1608 assert_eq!(formatted, &["NULL".to_string(), "NULL".to_string()])
1609 }
1610
1611 #[test]
1612 fn test_string_run_array_to_string() {
1613 let mut builder = StringRunBuilder::<Int32Type>::new();
1614
1615 builder.append_value("input_value");
1616 builder.append_value("input_value");
1617 builder.append_value("input_value");
1618 builder.append_value("input_value1");
1619
1620 let map_array = builder.finish();
1621 assert_eq!("input_value", array_value_to_string(&map_array, 1).unwrap());
1622 assert_eq!(
1623 "input_value1",
1624 array_value_to_string(&map_array, 3).unwrap()
1625 );
1626 }
1627
1628 #[test]
1629 fn test_list_view_to_string() {
1630 let list_view = ListViewArray::from_iter_primitive::<Int32Type, _, _>(vec![
1631 Some(vec![Some(1), Some(2), Some(3)]),
1632 None,
1633 Some(vec![Some(4), None, Some(6)]),
1634 Some(vec![]),
1635 ]);
1636
1637 assert_eq!("[1, 2, 3]", array_value_to_string(&list_view, 0).unwrap());
1638 assert_eq!("", array_value_to_string(&list_view, 1).unwrap());
1639 assert_eq!("[4, , 6]", array_value_to_string(&list_view, 2).unwrap());
1640 assert_eq!("[]", array_value_to_string(&list_view, 3).unwrap());
1641 }
1642
1643 #[test]
1644 fn test_large_list_view_to_string() {
1645 let list_view = LargeListViewArray::from_iter_primitive::<Int32Type, _, _>(vec![
1646 Some(vec![Some(1), Some(2), Some(3)]),
1647 None,
1648 Some(vec![Some(4), None, Some(6)]),
1649 Some(vec![]),
1650 ]);
1651
1652 assert_eq!("[1, 2, 3]", array_value_to_string(&list_view, 0).unwrap());
1653 assert_eq!("", array_value_to_string(&list_view, 1).unwrap());
1654 assert_eq!("[4, , 6]", array_value_to_string(&list_view, 2).unwrap());
1655 assert_eq!("[]", array_value_to_string(&list_view, 3).unwrap());
1656 }
1657}