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::{NaiveDate, NaiveDateTime, SecondsFormat, TimeZone, Utc};
38use lexical_core::FormattedSize;
39
40type TimeFormat<'a> = Option<&'a str>;
41
42#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
44#[non_exhaustive]
45pub enum DurationFormat {
46 ISO8601,
48 Pretty,
50}
51
52#[derive(Debug, Clone)]
63pub struct FormatOptions<'a> {
64 safe: bool,
67 null: &'a str,
69 date_format: TimeFormat<'a>,
71 datetime_format: TimeFormat<'a>,
73 timestamp_format: TimeFormat<'a>,
75 timestamp_tz_format: TimeFormat<'a>,
77 time_format: TimeFormat<'a>,
79 duration_format: DurationFormat,
81 types_info: bool,
83 formatter_factory: Option<&'a dyn ArrayFormatterFactory>,
86}
87
88impl Default for FormatOptions<'_> {
89 fn default() -> Self {
90 Self::new()
91 }
92}
93
94impl PartialEq for FormatOptions<'_> {
95 fn eq(&self, other: &Self) -> bool {
96 self.safe == other.safe
97 && self.null == other.null
98 && self.date_format == other.date_format
99 && self.datetime_format == other.datetime_format
100 && self.timestamp_format == other.timestamp_format
101 && self.timestamp_tz_format == other.timestamp_tz_format
102 && self.time_format == other.time_format
103 && self.duration_format == other.duration_format
104 && self.types_info == other.types_info
105 && match (self.formatter_factory, other.formatter_factory) {
106 (Some(f1), Some(f2)) => std::ptr::eq(f1, f2),
107 (None, None) => true,
108 _ => false,
109 }
110 }
111}
112
113impl Eq for FormatOptions<'_> {}
114
115impl Hash for FormatOptions<'_> {
116 fn hash<H: Hasher>(&self, state: &mut H) {
117 self.safe.hash(state);
118 self.null.hash(state);
119 self.date_format.hash(state);
120 self.datetime_format.hash(state);
121 self.timestamp_format.hash(state);
122 self.timestamp_tz_format.hash(state);
123 self.time_format.hash(state);
124 self.duration_format.hash(state);
125 self.types_info.hash(state);
126 self.formatter_factory
127 .map(|f| f as *const dyn ArrayFormatterFactory)
128 .hash(state);
129 }
130}
131
132impl<'a> FormatOptions<'a> {
133 pub const fn new() -> Self {
135 Self {
136 safe: true,
137 null: "",
138 date_format: None,
139 datetime_format: None,
140 timestamp_format: None,
141 timestamp_tz_format: None,
142 time_format: None,
143 duration_format: DurationFormat::ISO8601,
144 types_info: false,
145 formatter_factory: None,
146 }
147 }
148
149 pub const fn with_display_error(mut self, safe: bool) -> Self {
152 self.safe = safe;
153 self
154 }
155
156 pub const fn with_null(self, null: &'a str) -> Self {
160 Self { null, ..self }
161 }
162
163 pub const fn with_date_format(self, date_format: Option<&'a str>) -> Self {
165 Self {
166 date_format,
167 ..self
168 }
169 }
170
171 pub const fn with_datetime_format(self, datetime_format: Option<&'a str>) -> Self {
173 Self {
174 datetime_format,
175 ..self
176 }
177 }
178
179 pub const fn with_timestamp_format(self, timestamp_format: Option<&'a str>) -> Self {
181 Self {
182 timestamp_format,
183 ..self
184 }
185 }
186
187 pub const fn with_timestamp_tz_format(self, timestamp_tz_format: Option<&'a str>) -> Self {
189 Self {
190 timestamp_tz_format,
191 ..self
192 }
193 }
194
195 pub const fn with_time_format(self, time_format: Option<&'a str>) -> Self {
197 Self {
198 time_format,
199 ..self
200 }
201 }
202
203 pub const fn with_duration_format(self, duration_format: DurationFormat) -> Self {
207 Self {
208 duration_format,
209 ..self
210 }
211 }
212
213 pub const fn with_types_info(self, types_info: bool) -> Self {
217 Self { types_info, ..self }
218 }
219
220 pub const fn with_formatter_factory(
224 self,
225 formatter_factory: Option<&'a dyn ArrayFormatterFactory>,
226 ) -> Self {
227 Self {
228 formatter_factory,
229 ..self
230 }
231 }
232
233 pub const fn safe(&self) -> bool {
236 self.safe
237 }
238
239 pub const fn null(&self) -> &'a str {
241 self.null
242 }
243
244 pub const fn date_format(&self) -> TimeFormat<'a> {
246 self.date_format
247 }
248
249 pub const fn datetime_format(&self) -> TimeFormat<'a> {
251 self.datetime_format
252 }
253
254 pub const fn timestamp_format(&self) -> TimeFormat<'a> {
256 self.timestamp_format
257 }
258
259 pub const fn timestamp_tz_format(&self) -> TimeFormat<'a> {
261 self.timestamp_tz_format
262 }
263
264 pub const fn time_format(&self) -> TimeFormat<'a> {
266 self.time_format
267 }
268
269 pub const fn duration_format(&self) -> DurationFormat {
271 self.duration_format
272 }
273
274 pub const fn types_info(&self) -> bool {
276 self.types_info
277 }
278
279 pub const fn formatter_factory(&self) -> Option<&'a dyn ArrayFormatterFactory> {
281 self.formatter_factory
282 }
283}
284
285pub trait ArrayFormatterFactory: Debug + Send + Sync {
356 fn create_array_formatter<'formatter>(
363 &self,
364 array: &'formatter dyn Array,
365 options: &FormatOptions<'formatter>,
366 field: Option<&'formatter Field>,
367 ) -> Result<Option<ArrayFormatter<'formatter>>, ArrowError>;
368}
369
370pub(crate) fn make_array_formatter<'a>(
373 array: &'a dyn Array,
374 options: &FormatOptions<'a>,
375 field: Option<&'a Field>,
376) -> Result<ArrayFormatter<'a>, ArrowError> {
377 match options.formatter_factory() {
378 None => ArrayFormatter::try_new(array, options),
379 Some(formatters) => formatters
380 .create_array_formatter(array, options, field)
381 .transpose()
382 .unwrap_or_else(|| ArrayFormatter::try_new(array, options)),
383 }
384}
385
386pub struct ValueFormatter<'a> {
388 idx: usize,
389 formatter: &'a ArrayFormatter<'a>,
390}
391
392impl ValueFormatter<'_> {
393 pub fn write(&self, s: &mut dyn Write) -> Result<(), ArrowError> {
398 match self.formatter.format.write(self.idx, s) {
399 Ok(_) => Ok(()),
400 Err(FormatError::Arrow(e)) => Err(e),
401 Err(FormatError::Format(_)) => Err(ArrowError::CastError("Format error".to_string())),
402 }
403 }
404
405 pub fn try_to_string(&self) -> Result<String, ArrowError> {
407 let mut s = String::new();
408 self.write(&mut s)?;
409 Ok(s)
410 }
411}
412
413impl Display for ValueFormatter<'_> {
414 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
415 match self.formatter.format.write(self.idx, f) {
416 Ok(()) => Ok(()),
417 Err(FormatError::Arrow(e)) if self.formatter.safe => {
418 write!(f, "ERROR: {e}")
419 }
420 Err(_) => Err(std::fmt::Error),
421 }
422 }
423}
424
425pub struct ArrayFormatter<'a> {
478 format: Box<dyn DisplayIndex + 'a>,
479 safe: bool,
480}
481
482impl<'a> ArrayFormatter<'a> {
483 pub fn new(format: Box<dyn DisplayIndex + 'a>, safe: bool) -> Self {
485 Self { format, safe }
486 }
487
488 pub fn try_new(array: &'a dyn Array, options: &FormatOptions<'a>) -> Result<Self, ArrowError> {
492 Ok(Self::new(
493 make_default_display_index(array, options)?,
494 options.safe,
495 ))
496 }
497
498 pub fn value(&self, idx: usize) -> ValueFormatter<'_> {
501 ValueFormatter {
502 formatter: self,
503 idx,
504 }
505 }
506}
507
508fn make_default_display_index<'a>(
509 array: &'a dyn Array,
510 options: &FormatOptions<'a>,
511) -> Result<Box<dyn DisplayIndex + 'a>, ArrowError> {
512 downcast_primitive_array! {
513 array => array_format(array, options),
514 DataType::Null => array_format(as_null_array(array), options),
515 DataType::Boolean => array_format(as_boolean_array(array), options),
516 DataType::Utf8 => array_format(array.as_string::<i32>(), options),
517 DataType::LargeUtf8 => array_format(array.as_string::<i64>(), options),
518 DataType::Utf8View => array_format(array.as_string_view(), options),
519 DataType::Binary => array_format(array.as_binary::<i32>(), options),
520 DataType::BinaryView => array_format(array.as_binary_view(), options),
521 DataType::LargeBinary => array_format(array.as_binary::<i64>(), options),
522 DataType::FixedSizeBinary(_) => {
523 let a = array.as_any().downcast_ref::<FixedSizeBinaryArray>().unwrap();
524 array_format(a, options)
525 }
526 DataType::Dictionary(_, _) => downcast_dictionary_array! {
527 array => array_format(array, options),
528 _ => unreachable!()
529 }
530 DataType::List(_) => array_format(as_generic_list_array::<i32>(array), options),
531 DataType::LargeList(_) => array_format(as_generic_list_array::<i64>(array), options),
532 DataType::FixedSizeList(_, _) => {
533 let a = array.as_any().downcast_ref::<FixedSizeListArray>().unwrap();
534 array_format(a, options)
535 }
536 DataType::Struct(_) => array_format(as_struct_array(array), options),
537 DataType::Map(_, _) => array_format(as_map_array(array), options),
538 DataType::Union(_, _) => array_format(as_union_array(array), options),
539 DataType::RunEndEncoded(_, _) => downcast_run_array! {
540 array => array_format(array, options),
541 _ => unreachable!()
542 },
543 d => Err(ArrowError::NotYetImplemented(format!("formatting {d} is not yet supported"))),
544 }
545}
546
547pub enum FormatError {
549 Format(std::fmt::Error),
551 Arrow(ArrowError),
553}
554
555pub type FormatResult = Result<(), FormatError>;
557
558impl From<std::fmt::Error> for FormatError {
559 fn from(value: std::fmt::Error) -> Self {
560 Self::Format(value)
561 }
562}
563
564impl From<ArrowError> for FormatError {
565 fn from(value: ArrowError) -> Self {
566 Self::Arrow(value)
567 }
568}
569
570pub trait DisplayIndex {
572 fn write(&self, idx: usize, f: &mut dyn Write) -> FormatResult;
574}
575
576trait DisplayIndexState<'a> {
578 type State;
579
580 fn prepare(&self, options: &FormatOptions<'a>) -> Result<Self::State, ArrowError>;
581
582 fn write(&self, state: &Self::State, idx: usize, f: &mut dyn Write) -> FormatResult;
583}
584
585impl<'a, T: DisplayIndex> DisplayIndexState<'a> for T {
586 type State = ();
587
588 fn prepare(&self, _options: &FormatOptions<'a>) -> Result<Self::State, ArrowError> {
589 Ok(())
590 }
591
592 fn write(&self, _: &Self::State, idx: usize, f: &mut dyn Write) -> FormatResult {
593 DisplayIndex::write(self, idx, f)
594 }
595}
596
597struct ArrayFormat<'a, F: DisplayIndexState<'a>> {
598 state: F::State,
599 array: F,
600 null: &'a str,
601}
602
603fn array_format<'a, F>(
604 array: F,
605 options: &FormatOptions<'a>,
606) -> Result<Box<dyn DisplayIndex + 'a>, ArrowError>
607where
608 F: DisplayIndexState<'a> + Array + 'a,
609{
610 let state = array.prepare(options)?;
611 Ok(Box::new(ArrayFormat {
612 state,
613 array,
614 null: options.null,
615 }))
616}
617
618impl<'a, F: DisplayIndexState<'a> + Array> DisplayIndex for ArrayFormat<'a, F> {
619 fn write(&self, idx: usize, f: &mut dyn Write) -> FormatResult {
620 if self.array.is_null(idx) {
621 if !self.null.is_empty() {
622 f.write_str(self.null)?
623 }
624 return Ok(());
625 }
626 DisplayIndexState::write(&self.array, &self.state, idx, f)
627 }
628}
629
630impl DisplayIndex for &BooleanArray {
631 fn write(&self, idx: usize, f: &mut dyn Write) -> FormatResult {
632 write!(f, "{}", self.value(idx))?;
633 Ok(())
634 }
635}
636
637impl<'a> DisplayIndexState<'a> for &'a NullArray {
638 type State = &'a str;
639
640 fn prepare(&self, options: &FormatOptions<'a>) -> Result<Self::State, ArrowError> {
641 Ok(options.null)
642 }
643
644 fn write(&self, state: &Self::State, _idx: usize, f: &mut dyn Write) -> FormatResult {
645 f.write_str(state)?;
646 Ok(())
647 }
648}
649
650macro_rules! primitive_display {
651 ($($t:ty),+) => {
652 $(impl<'a> DisplayIndex for &'a PrimitiveArray<$t>
653 {
654 fn write(&self, idx: usize, f: &mut dyn Write) -> FormatResult {
655 let value = self.value(idx);
656 let mut buffer = [0u8; <$t as ArrowPrimitiveType>::Native::FORMATTED_SIZE];
657 let b = lexical_core::write(value, &mut buffer);
658 let s = unsafe { std::str::from_utf8_unchecked(b) };
660 f.write_str(s)?;
661 Ok(())
662 }
663 })+
664 };
665}
666
667macro_rules! primitive_display_float {
668 ($($t:ty),+) => {
669 $(impl<'a> DisplayIndex for &'a PrimitiveArray<$t>
670 {
671 fn write(&self, idx: usize, f: &mut dyn Write) -> FormatResult {
672 let value = self.value(idx);
673 let mut buffer = ryu::Buffer::new();
674 f.write_str(buffer.format(value))?;
675 Ok(())
676 }
677 })+
678 };
679}
680
681primitive_display!(Int8Type, Int16Type, Int32Type, Int64Type);
682primitive_display!(UInt8Type, UInt16Type, UInt32Type, UInt64Type);
683primitive_display_float!(Float32Type, Float64Type);
684
685impl DisplayIndex for &PrimitiveArray<Float16Type> {
686 fn write(&self, idx: usize, f: &mut dyn Write) -> FormatResult {
687 write!(f, "{}", self.value(idx))?;
688 Ok(())
689 }
690}
691
692macro_rules! decimal_display {
693 ($($t:ty),+) => {
694 $(impl<'a> DisplayIndexState<'a> for &'a PrimitiveArray<$t> {
695 type State = (u8, i8);
696
697 fn prepare(&self, _options: &FormatOptions<'a>) -> Result<Self::State, ArrowError> {
698 Ok((self.precision(), self.scale()))
699 }
700
701 fn write(&self, s: &Self::State, idx: usize, f: &mut dyn Write) -> FormatResult {
702 write!(f, "{}", <$t>::format_decimal(self.values()[idx], s.0, s.1))?;
703 Ok(())
704 }
705 })+
706 };
707}
708
709decimal_display!(Decimal32Type, Decimal64Type, Decimal128Type, Decimal256Type);
710
711fn write_timestamp(
712 f: &mut dyn Write,
713 naive: NaiveDateTime,
714 timezone: Option<Tz>,
715 format: Option<&str>,
716) -> FormatResult {
717 match timezone {
718 Some(tz) => {
719 let date = Utc.from_utc_datetime(&naive).with_timezone(&tz);
720 match format {
721 Some(s) => write!(f, "{}", date.format(s))?,
722 None => write!(f, "{}", date.to_rfc3339_opts(SecondsFormat::AutoSi, true))?,
723 }
724 }
725 None => match format {
726 Some(s) => write!(f, "{}", naive.format(s))?,
727 None => write!(f, "{naive:?}")?,
728 },
729 }
730 Ok(())
731}
732
733macro_rules! timestamp_display {
734 ($($t:ty),+) => {
735 $(impl<'a> DisplayIndexState<'a> for &'a PrimitiveArray<$t> {
736 type State = (Option<Tz>, TimeFormat<'a>);
737
738 fn prepare(&self, options: &FormatOptions<'a>) -> Result<Self::State, ArrowError> {
739 match self.data_type() {
740 DataType::Timestamp(_, Some(tz)) => Ok((Some(tz.parse()?), options.timestamp_tz_format)),
741 DataType::Timestamp(_, None) => Ok((None, options.timestamp_format)),
742 _ => unreachable!(),
743 }
744 }
745
746 fn write(&self, s: &Self::State, idx: usize, f: &mut dyn Write) -> FormatResult {
747 let value = self.value(idx);
748 let naive = as_datetime::<$t>(value).ok_or_else(|| {
749 ArrowError::CastError(format!(
750 "Failed to convert {} to datetime for {}",
751 value,
752 self.data_type()
753 ))
754 })?;
755
756 write_timestamp(f, naive, s.0, s.1.clone())
757 }
758 })+
759 };
760}
761
762timestamp_display!(
763 TimestampSecondType,
764 TimestampMillisecondType,
765 TimestampMicrosecondType,
766 TimestampNanosecondType
767);
768
769macro_rules! temporal_display {
770 ($convert:ident, $format:ident, $t:ty) => {
771 impl<'a> DisplayIndexState<'a> for &'a PrimitiveArray<$t> {
772 type State = TimeFormat<'a>;
773
774 fn prepare(&self, options: &FormatOptions<'a>) -> Result<Self::State, ArrowError> {
775 Ok(options.$format)
776 }
777
778 fn write(&self, fmt: &Self::State, idx: usize, f: &mut dyn Write) -> FormatResult {
779 let value = self.value(idx);
780 let naive = $convert(value as _).ok_or_else(|| {
781 ArrowError::CastError(format!(
782 "Failed to convert {} to temporal for {}",
783 value,
784 self.data_type()
785 ))
786 })?;
787
788 match fmt {
789 Some(s) => write!(f, "{}", naive.format(s))?,
790 None => write!(f, "{naive:?}")?,
791 }
792 Ok(())
793 }
794 }
795 };
796}
797
798#[inline]
799fn date32_to_date(value: i32) -> Option<NaiveDate> {
800 Some(date32_to_datetime(value)?.date())
801}
802
803temporal_display!(date32_to_date, date_format, Date32Type);
804temporal_display!(date64_to_datetime, datetime_format, Date64Type);
805temporal_display!(time32s_to_time, time_format, Time32SecondType);
806temporal_display!(time32ms_to_time, time_format, Time32MillisecondType);
807temporal_display!(time64us_to_time, time_format, Time64MicrosecondType);
808temporal_display!(time64ns_to_time, time_format, Time64NanosecondType);
809
810macro_rules! duration_display {
817 ($convert:ident, $t:ty, $scale:tt) => {
818 impl<'a> DisplayIndexState<'a> for &'a PrimitiveArray<$t> {
819 type State = DurationFormat;
820
821 fn prepare(&self, options: &FormatOptions<'a>) -> Result<Self::State, ArrowError> {
822 Ok(options.duration_format)
823 }
824
825 fn write(&self, fmt: &Self::State, idx: usize, f: &mut dyn Write) -> FormatResult {
826 let v = self.value(idx);
827 match fmt {
828 DurationFormat::ISO8601 => write!(f, "{}", $convert(v))?,
829 DurationFormat::Pretty => duration_fmt!(f, v, $scale)?,
830 }
831 Ok(())
832 }
833 }
834 };
835}
836
837macro_rules! duration_option_display {
839 ($convert:ident, $t:ty, $scale:tt) => {
840 impl<'a> DisplayIndexState<'a> for &'a PrimitiveArray<$t> {
841 type State = DurationFormat;
842
843 fn prepare(&self, options: &FormatOptions<'a>) -> Result<Self::State, ArrowError> {
844 Ok(options.duration_format)
845 }
846
847 fn write(&self, fmt: &Self::State, idx: usize, f: &mut dyn Write) -> FormatResult {
848 let v = self.value(idx);
849 match fmt {
850 DurationFormat::ISO8601 => match $convert(v) {
851 Some(td) => write!(f, "{}", td)?,
852 None => write!(f, "<invalid>")?,
853 },
854 DurationFormat::Pretty => match $convert(v) {
855 Some(_) => duration_fmt!(f, v, $scale)?,
856 None => write!(f, "<invalid>")?,
857 },
858 }
859 Ok(())
860 }
861 }
862 };
863}
864
865macro_rules! duration_fmt {
866 ($f:ident, $v:expr, 0) => {{
867 let secs = $v;
868 let mins = secs / 60;
869 let hours = mins / 60;
870 let days = hours / 24;
871
872 let secs = secs - (mins * 60);
873 let mins = mins - (hours * 60);
874 let hours = hours - (days * 24);
875 write!($f, "{days} days {hours} hours {mins} mins {secs} secs")
876 }};
877 ($f:ident, $v:expr, $scale:tt) => {{
878 let subsec = $v;
879 let secs = subsec / 10_i64.pow($scale);
880 let mins = secs / 60;
881 let hours = mins / 60;
882 let days = hours / 24;
883
884 let subsec = subsec - (secs * 10_i64.pow($scale));
885 let secs = secs - (mins * 60);
886 let mins = mins - (hours * 60);
887 let hours = hours - (days * 24);
888 match subsec.is_negative() {
889 true => {
890 write!(
891 $f,
892 concat!("{} days {} hours {} mins -{}.{:0", $scale, "} secs"),
893 days,
894 hours,
895 mins,
896 secs.abs(),
897 subsec.abs()
898 )
899 }
900 false => {
901 write!(
902 $f,
903 concat!("{} days {} hours {} mins {}.{:0", $scale, "} secs"),
904 days, hours, mins, secs, subsec
905 )
906 }
907 }
908 }};
909}
910
911duration_option_display!(try_duration_s_to_duration, DurationSecondType, 0);
912duration_option_display!(try_duration_ms_to_duration, DurationMillisecondType, 3);
913duration_display!(duration_us_to_duration, DurationMicrosecondType, 6);
914duration_display!(duration_ns_to_duration, DurationNanosecondType, 9);
915
916impl DisplayIndex for &PrimitiveArray<IntervalYearMonthType> {
917 fn write(&self, idx: usize, f: &mut dyn Write) -> FormatResult {
918 let interval = self.value(idx) as f64;
919 let years = (interval / 12_f64).floor();
920 let month = interval - (years * 12_f64);
921
922 write!(f, "{years} years {month} mons",)?;
923 Ok(())
924 }
925}
926
927impl DisplayIndex for &PrimitiveArray<IntervalDayTimeType> {
928 fn write(&self, idx: usize, f: &mut dyn Write) -> FormatResult {
929 let value = self.value(idx);
930 let mut prefix = "";
931
932 if value.days != 0 {
933 write!(f, "{prefix}{} days", value.days)?;
934 prefix = " ";
935 }
936
937 if value.milliseconds != 0 {
938 let millis_fmt = MillisecondsFormatter {
939 milliseconds: value.milliseconds,
940 prefix,
941 };
942
943 f.write_fmt(format_args!("{millis_fmt}"))?;
944 }
945
946 Ok(())
947 }
948}
949
950impl DisplayIndex for &PrimitiveArray<IntervalMonthDayNanoType> {
951 fn write(&self, idx: usize, f: &mut dyn Write) -> FormatResult {
952 let value = self.value(idx);
953 let mut prefix = "";
954
955 if value.months != 0 {
956 write!(f, "{prefix}{} mons", value.months)?;
957 prefix = " ";
958 }
959
960 if value.days != 0 {
961 write!(f, "{prefix}{} days", value.days)?;
962 prefix = " ";
963 }
964
965 if value.nanoseconds != 0 {
966 let nano_fmt = NanosecondsFormatter {
967 nanoseconds: value.nanoseconds,
968 prefix,
969 };
970 f.write_fmt(format_args!("{nano_fmt}"))?;
971 }
972
973 Ok(())
974 }
975}
976
977struct NanosecondsFormatter<'a> {
978 nanoseconds: i64,
979 prefix: &'a str,
980}
981
982impl Display for NanosecondsFormatter<'_> {
983 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
984 let mut prefix = self.prefix;
985
986 let secs = self.nanoseconds / 1_000_000_000;
987 let mins = secs / 60;
988 let hours = mins / 60;
989
990 let secs = secs - (mins * 60);
991 let mins = mins - (hours * 60);
992
993 let nanoseconds = self.nanoseconds % 1_000_000_000;
994
995 if hours != 0 {
996 write!(f, "{prefix}{hours} hours")?;
997 prefix = " ";
998 }
999
1000 if mins != 0 {
1001 write!(f, "{prefix}{mins} mins")?;
1002 prefix = " ";
1003 }
1004
1005 if secs != 0 || nanoseconds != 0 {
1006 let secs_sign = if secs < 0 || nanoseconds < 0 { "-" } else { "" };
1007 write!(
1008 f,
1009 "{prefix}{}{}.{:09} secs",
1010 secs_sign,
1011 secs.abs(),
1012 nanoseconds.abs()
1013 )?;
1014 }
1015
1016 Ok(())
1017 }
1018}
1019
1020struct MillisecondsFormatter<'a> {
1021 milliseconds: i32,
1022 prefix: &'a str,
1023}
1024
1025impl Display for MillisecondsFormatter<'_> {
1026 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
1027 let mut prefix = self.prefix;
1028
1029 let secs = self.milliseconds / 1_000;
1030 let mins = secs / 60;
1031 let hours = mins / 60;
1032
1033 let secs = secs - (mins * 60);
1034 let mins = mins - (hours * 60);
1035
1036 let milliseconds = self.milliseconds % 1_000;
1037
1038 if hours != 0 {
1039 write!(f, "{prefix}{hours} hours")?;
1040 prefix = " ";
1041 }
1042
1043 if mins != 0 {
1044 write!(f, "{prefix}{mins} mins")?;
1045 prefix = " ";
1046 }
1047
1048 if secs != 0 || milliseconds != 0 {
1049 let secs_sign = if secs < 0 || milliseconds < 0 {
1050 "-"
1051 } else {
1052 ""
1053 };
1054
1055 write!(
1056 f,
1057 "{prefix}{}{}.{:03} secs",
1058 secs_sign,
1059 secs.abs(),
1060 milliseconds.abs()
1061 )?;
1062 }
1063
1064 Ok(())
1065 }
1066}
1067
1068impl<O: OffsetSizeTrait> DisplayIndex for &GenericStringArray<O> {
1069 fn write(&self, idx: usize, f: &mut dyn Write) -> FormatResult {
1070 write!(f, "{}", self.value(idx))?;
1071 Ok(())
1072 }
1073}
1074
1075impl DisplayIndex for &StringViewArray {
1076 fn write(&self, idx: usize, f: &mut dyn Write) -> FormatResult {
1077 write!(f, "{}", self.value(idx))?;
1078 Ok(())
1079 }
1080}
1081
1082impl<O: OffsetSizeTrait> DisplayIndex for &GenericBinaryArray<O> {
1083 fn write(&self, idx: usize, f: &mut dyn Write) -> FormatResult {
1084 let v = self.value(idx);
1085 for byte in v {
1086 write!(f, "{byte:02x}")?;
1087 }
1088 Ok(())
1089 }
1090}
1091
1092impl DisplayIndex for &BinaryViewArray {
1093 fn write(&self, idx: usize, f: &mut dyn Write) -> FormatResult {
1094 let v = self.value(idx);
1095 for byte in v {
1096 write!(f, "{byte:02x}")?;
1097 }
1098 Ok(())
1099 }
1100}
1101
1102impl DisplayIndex for &FixedSizeBinaryArray {
1103 fn write(&self, idx: usize, f: &mut dyn Write) -> FormatResult {
1104 let v = self.value(idx);
1105 for byte in v {
1106 write!(f, "{byte:02x}")?;
1107 }
1108 Ok(())
1109 }
1110}
1111
1112impl<'a, K: ArrowDictionaryKeyType> DisplayIndexState<'a> for &'a DictionaryArray<K> {
1113 type State = Box<dyn DisplayIndex + 'a>;
1114
1115 fn prepare(&self, options: &FormatOptions<'a>) -> Result<Self::State, ArrowError> {
1116 make_default_display_index(self.values().as_ref(), options)
1117 }
1118
1119 fn write(&self, s: &Self::State, idx: usize, f: &mut dyn Write) -> FormatResult {
1120 let value_idx = self.keys().values()[idx].as_usize();
1121 s.as_ref().write(value_idx, f)
1122 }
1123}
1124
1125impl<'a, K: RunEndIndexType> DisplayIndexState<'a> for &'a RunArray<K> {
1126 type State = ArrayFormatter<'a>;
1127
1128 fn prepare(&self, options: &FormatOptions<'a>) -> Result<Self::State, ArrowError> {
1129 let field = match (*self).data_type() {
1130 DataType::RunEndEncoded(_, values_field) => values_field,
1131 _ => unreachable!(),
1132 };
1133 make_array_formatter(self.values().as_ref(), options, Some(field))
1134 }
1135
1136 fn write(&self, s: &Self::State, idx: usize, f: &mut dyn Write) -> FormatResult {
1137 let value_idx = self.get_physical_index(idx);
1138 write!(f, "{}", s.value(value_idx))?;
1139 Ok(())
1140 }
1141}
1142
1143fn write_list(
1144 f: &mut dyn Write,
1145 mut range: Range<usize>,
1146 values: &ArrayFormatter<'_>,
1147) -> FormatResult {
1148 f.write_char('[')?;
1149 if let Some(idx) = range.next() {
1150 write!(f, "{}", values.value(idx))?;
1151 }
1152 for idx in range {
1153 write!(f, ", {}", values.value(idx))?;
1154 }
1155 f.write_char(']')?;
1156 Ok(())
1157}
1158
1159impl<'a, O: OffsetSizeTrait> DisplayIndexState<'a> for &'a GenericListArray<O> {
1160 type State = ArrayFormatter<'a>;
1161
1162 fn prepare(&self, options: &FormatOptions<'a>) -> Result<Self::State, ArrowError> {
1163 let field = match (*self).data_type() {
1164 DataType::List(f) => f,
1165 DataType::LargeList(f) => f,
1166 _ => unreachable!(),
1167 };
1168 make_array_formatter(self.values().as_ref(), options, Some(field.as_ref()))
1169 }
1170
1171 fn write(&self, s: &Self::State, idx: usize, f: &mut dyn Write) -> FormatResult {
1172 let offsets = self.value_offsets();
1173 let end = offsets[idx + 1].as_usize();
1174 let start = offsets[idx].as_usize();
1175 write_list(f, start..end, s)
1176 }
1177}
1178
1179impl<'a> DisplayIndexState<'a> for &'a FixedSizeListArray {
1180 type State = (usize, ArrayFormatter<'a>);
1181
1182 fn prepare(&self, options: &FormatOptions<'a>) -> Result<Self::State, ArrowError> {
1183 let field = match (*self).data_type() {
1184 DataType::FixedSizeList(f, _) => f,
1185 _ => unreachable!(),
1186 };
1187 let formatter =
1188 make_array_formatter(self.values().as_ref(), options, Some(field.as_ref()))?;
1189 let length = self.value_length();
1190 Ok((length as usize, formatter))
1191 }
1192
1193 fn write(&self, s: &Self::State, idx: usize, f: &mut dyn Write) -> FormatResult {
1194 let start = idx * s.0;
1195 let end = start + s.0;
1196 write_list(f, start..end, &s.1)
1197 }
1198}
1199
1200type FieldDisplay<'a> = (&'a str, ArrayFormatter<'a>);
1202
1203impl<'a> DisplayIndexState<'a> for &'a StructArray {
1204 type State = Vec<FieldDisplay<'a>>;
1205
1206 fn prepare(&self, options: &FormatOptions<'a>) -> Result<Self::State, ArrowError> {
1207 let fields = match (*self).data_type() {
1208 DataType::Struct(f) => f,
1209 _ => unreachable!(),
1210 };
1211
1212 self.columns()
1213 .iter()
1214 .zip(fields)
1215 .map(|(a, f)| {
1216 let format = make_array_formatter(a.as_ref(), options, Some(f))?;
1217 Ok((f.name().as_str(), format))
1218 })
1219 .collect()
1220 }
1221
1222 fn write(&self, s: &Self::State, idx: usize, f: &mut dyn Write) -> FormatResult {
1223 let mut iter = s.iter();
1224 f.write_char('{')?;
1225 if let Some((name, display)) = iter.next() {
1226 write!(f, "{name}: {}", display.value(idx))?;
1227 }
1228 for (name, display) in iter {
1229 write!(f, ", {name}: {}", display.value(idx))?;
1230 }
1231 f.write_char('}')?;
1232 Ok(())
1233 }
1234}
1235
1236impl<'a> DisplayIndexState<'a> for &'a MapArray {
1237 type State = (ArrayFormatter<'a>, ArrayFormatter<'a>);
1238
1239 fn prepare(&self, options: &FormatOptions<'a>) -> Result<Self::State, ArrowError> {
1240 let (key_field, value_field) = (*self).entries_fields();
1241
1242 let keys = make_array_formatter(self.keys().as_ref(), options, Some(key_field))?;
1243 let values = make_array_formatter(self.values().as_ref(), options, Some(value_field))?;
1244 Ok((keys, values))
1245 }
1246
1247 fn write(&self, s: &Self::State, idx: usize, f: &mut dyn Write) -> FormatResult {
1248 let offsets = self.value_offsets();
1249 let end = offsets[idx + 1].as_usize();
1250 let start = offsets[idx].as_usize();
1251 let mut iter = start..end;
1252
1253 f.write_char('{')?;
1254 if let Some(idx) = iter.next() {
1255 write!(f, "{}: {}", s.0.value(idx), s.1.value(idx))?;
1256 }
1257
1258 for idx in iter {
1259 write!(f, ", {}", s.0.value(idx))?;
1260 write!(f, ": {}", s.1.value(idx))?;
1261 }
1262
1263 f.write_char('}')?;
1264 Ok(())
1265 }
1266}
1267
1268impl<'a> DisplayIndexState<'a> for &'a UnionArray {
1269 type State = (Vec<Option<FieldDisplay<'a>>>, UnionMode);
1270
1271 fn prepare(&self, options: &FormatOptions<'a>) -> Result<Self::State, ArrowError> {
1272 let (fields, mode) = match (*self).data_type() {
1273 DataType::Union(fields, mode) => (fields, mode),
1274 _ => unreachable!(),
1275 };
1276
1277 let max_id = fields.iter().map(|(id, _)| id).max().unwrap_or_default() as usize;
1278 let mut out: Vec<Option<FieldDisplay>> = (0..max_id + 1).map(|_| None).collect();
1279 for (i, field) in fields.iter() {
1280 let formatter = make_array_formatter(self.child(i).as_ref(), options, Some(field))?;
1281 out[i as usize] = Some((field.name().as_str(), formatter))
1282 }
1283 Ok((out, *mode))
1284 }
1285
1286 fn write(&self, s: &Self::State, idx: usize, f: &mut dyn Write) -> FormatResult {
1287 let id = self.type_id(idx);
1288 let idx = match s.1 {
1289 UnionMode::Dense => self.value_offset(idx),
1290 UnionMode::Sparse => idx,
1291 };
1292 let (name, field) = s.0[id as usize].as_ref().unwrap();
1293
1294 write!(f, "{{{name}={}}}", field.value(idx))?;
1295 Ok(())
1296 }
1297}
1298
1299pub fn array_value_to_string(column: &dyn Array, row: usize) -> Result<String, ArrowError> {
1306 let options = FormatOptions::default().with_display_error(true);
1307 let formatter = ArrayFormatter::try_new(column, &options)?;
1308 Ok(formatter.value(row).to_string())
1309}
1310
1311pub fn lexical_to_string<N: lexical_core::ToLexical>(n: N) -> String {
1313 let mut buf = Vec::<u8>::with_capacity(N::FORMATTED_SIZE_DECIMAL);
1314 unsafe {
1315 let slice = std::slice::from_raw_parts_mut(buf.as_mut_ptr(), buf.capacity());
1322 let len = lexical_core::write(n, slice).len();
1323 buf.set_len(len);
1324 String::from_utf8_unchecked(buf)
1325 }
1326}
1327
1328#[cfg(test)]
1329mod tests {
1330 use super::*;
1331 use arrow_array::builder::StringRunBuilder;
1332
1333 const TEST_CONST_OPTIONS: FormatOptions<'static> = FormatOptions::new()
1335 .with_date_format(Some("foo"))
1336 .with_timestamp_format(Some("404"));
1337
1338 #[test]
1339 fn test_const_options() {
1340 assert_eq!(TEST_CONST_OPTIONS.date_format, Some("foo"));
1341 }
1342
1343 #[test]
1345 fn test_options_send_sync() {
1346 fn assert_send_sync<T>()
1347 where
1348 T: Send + Sync,
1349 {
1350 }
1352
1353 assert_send_sync::<FormatOptions<'static>>();
1354 }
1355
1356 #[test]
1357 fn test_map_array_to_string() {
1358 let keys = vec!["a", "b", "c", "d", "e", "f", "g", "h"];
1359 let values_data = UInt32Array::from(vec![0u32, 10, 20, 30, 40, 50, 60, 70]);
1360
1361 let entry_offsets = [0, 3, 6, 8];
1364
1365 let map_array =
1366 MapArray::new_from_strings(keys.clone().into_iter(), &values_data, &entry_offsets)
1367 .unwrap();
1368 assert_eq!(
1369 "{d: 30, e: 40, f: 50}",
1370 array_value_to_string(&map_array, 1).unwrap()
1371 );
1372 }
1373
1374 fn format_array(array: &dyn Array, fmt: &FormatOptions) -> Vec<String> {
1375 let fmt = ArrayFormatter::try_new(array, fmt).unwrap();
1376 (0..array.len()).map(|x| fmt.value(x).to_string()).collect()
1377 }
1378
1379 #[test]
1380 fn test_array_value_to_string_duration() {
1381 let iso_fmt = FormatOptions::new();
1382 let pretty_fmt = FormatOptions::new().with_duration_format(DurationFormat::Pretty);
1383
1384 let array = DurationNanosecondArray::from(vec![
1385 1,
1386 -1,
1387 1000,
1388 -1000,
1389 (45 * 60 * 60 * 24 + 14 * 60 * 60 + 2 * 60 + 34) * 1_000_000_000 + 123456789,
1390 -(45 * 60 * 60 * 24 + 14 * 60 * 60 + 2 * 60 + 34) * 1_000_000_000 - 123456789,
1391 ]);
1392 let iso = format_array(&array, &iso_fmt);
1393 let pretty = format_array(&array, &pretty_fmt);
1394
1395 assert_eq!(iso[0], "PT0.000000001S");
1396 assert_eq!(pretty[0], "0 days 0 hours 0 mins 0.000000001 secs");
1397 assert_eq!(iso[1], "-PT0.000000001S");
1398 assert_eq!(pretty[1], "0 days 0 hours 0 mins -0.000000001 secs");
1399 assert_eq!(iso[2], "PT0.000001S");
1400 assert_eq!(pretty[2], "0 days 0 hours 0 mins 0.000001000 secs");
1401 assert_eq!(iso[3], "-PT0.000001S");
1402 assert_eq!(pretty[3], "0 days 0 hours 0 mins -0.000001000 secs");
1403 assert_eq!(iso[4], "PT3938554.123456789S");
1404 assert_eq!(pretty[4], "45 days 14 hours 2 mins 34.123456789 secs");
1405 assert_eq!(iso[5], "-PT3938554.123456789S");
1406 assert_eq!(pretty[5], "-45 days -14 hours -2 mins -34.123456789 secs");
1407
1408 let array = DurationMicrosecondArray::from(vec![
1409 1,
1410 -1,
1411 1000,
1412 -1000,
1413 (45 * 60 * 60 * 24 + 14 * 60 * 60 + 2 * 60 + 34) * 1_000_000 + 123456,
1414 -(45 * 60 * 60 * 24 + 14 * 60 * 60 + 2 * 60 + 34) * 1_000_000 - 123456,
1415 ]);
1416 let iso = format_array(&array, &iso_fmt);
1417 let pretty = format_array(&array, &pretty_fmt);
1418
1419 assert_eq!(iso[0], "PT0.000001S");
1420 assert_eq!(pretty[0], "0 days 0 hours 0 mins 0.000001 secs");
1421 assert_eq!(iso[1], "-PT0.000001S");
1422 assert_eq!(pretty[1], "0 days 0 hours 0 mins -0.000001 secs");
1423 assert_eq!(iso[2], "PT0.001S");
1424 assert_eq!(pretty[2], "0 days 0 hours 0 mins 0.001000 secs");
1425 assert_eq!(iso[3], "-PT0.001S");
1426 assert_eq!(pretty[3], "0 days 0 hours 0 mins -0.001000 secs");
1427 assert_eq!(iso[4], "PT3938554.123456S");
1428 assert_eq!(pretty[4], "45 days 14 hours 2 mins 34.123456 secs");
1429 assert_eq!(iso[5], "-PT3938554.123456S");
1430 assert_eq!(pretty[5], "-45 days -14 hours -2 mins -34.123456 secs");
1431
1432 let array = DurationMillisecondArray::from(vec![
1433 1,
1434 -1,
1435 1000,
1436 -1000,
1437 (45 * 60 * 60 * 24 + 14 * 60 * 60 + 2 * 60 + 34) * 1_000 + 123,
1438 -(45 * 60 * 60 * 24 + 14 * 60 * 60 + 2 * 60 + 34) * 1_000 - 123,
1439 ]);
1440 let iso = format_array(&array, &iso_fmt);
1441 let pretty = format_array(&array, &pretty_fmt);
1442
1443 assert_eq!(iso[0], "PT0.001S");
1444 assert_eq!(pretty[0], "0 days 0 hours 0 mins 0.001 secs");
1445 assert_eq!(iso[1], "-PT0.001S");
1446 assert_eq!(pretty[1], "0 days 0 hours 0 mins -0.001 secs");
1447 assert_eq!(iso[2], "PT1S");
1448 assert_eq!(pretty[2], "0 days 0 hours 0 mins 1.000 secs");
1449 assert_eq!(iso[3], "-PT1S");
1450 assert_eq!(pretty[3], "0 days 0 hours 0 mins -1.000 secs");
1451 assert_eq!(iso[4], "PT3938554.123S");
1452 assert_eq!(pretty[4], "45 days 14 hours 2 mins 34.123 secs");
1453 assert_eq!(iso[5], "-PT3938554.123S");
1454 assert_eq!(pretty[5], "-45 days -14 hours -2 mins -34.123 secs");
1455
1456 let array = DurationSecondArray::from(vec![
1457 1,
1458 -1,
1459 1000,
1460 -1000,
1461 45 * 60 * 60 * 24 + 14 * 60 * 60 + 2 * 60 + 34,
1462 -45 * 60 * 60 * 24 - 14 * 60 * 60 - 2 * 60 - 34,
1463 ]);
1464 let iso = format_array(&array, &iso_fmt);
1465 let pretty = format_array(&array, &pretty_fmt);
1466
1467 assert_eq!(iso[0], "PT1S");
1468 assert_eq!(pretty[0], "0 days 0 hours 0 mins 1 secs");
1469 assert_eq!(iso[1], "-PT1S");
1470 assert_eq!(pretty[1], "0 days 0 hours 0 mins -1 secs");
1471 assert_eq!(iso[2], "PT1000S");
1472 assert_eq!(pretty[2], "0 days 0 hours 16 mins 40 secs");
1473 assert_eq!(iso[3], "-PT1000S");
1474 assert_eq!(pretty[3], "0 days 0 hours -16 mins -40 secs");
1475 assert_eq!(iso[4], "PT3938554S");
1476 assert_eq!(pretty[4], "45 days 14 hours 2 mins 34 secs");
1477 assert_eq!(iso[5], "-PT3938554S");
1478 assert_eq!(pretty[5], "-45 days -14 hours -2 mins -34 secs");
1479 }
1480
1481 #[test]
1482 fn test_null() {
1483 let array = NullArray::new(2);
1484 let options = FormatOptions::new().with_null("NULL");
1485 let formatted = format_array(&array, &options);
1486 assert_eq!(formatted, &["NULL".to_string(), "NULL".to_string()])
1487 }
1488
1489 #[test]
1490 fn test_string_run_arry_to_string() {
1491 let mut builder = StringRunBuilder::<Int32Type>::new();
1492
1493 builder.append_value("input_value");
1494 builder.append_value("input_value");
1495 builder.append_value("input_value");
1496 builder.append_value("input_value1");
1497
1498 let map_array = builder.finish();
1499 assert_eq!("input_value", array_value_to_string(&map_array, 1).unwrap());
1500 assert_eq!(
1501 "input_value1",
1502 array_value_to_string(&map_array, 3).unwrap()
1503 );
1504 }
1505}