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