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