1use crate::DataType;
19use crate::Metadata;
20use std::fmt;
21use std::fmt::Display;
22
23impl Display for DataType {
24 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
25 fn format_metadata(metadata: &Metadata) -> String {
26 format!("{}", FormatMetadata(metadata))
27 }
28
29 fn format_nullability(field: &crate::Field) -> &str {
30 if field.is_nullable() { "" } else { "non-null " }
31 }
32
33 fn format_field(field: &crate::Field) -> String {
34 let name = field.name();
35 let maybe_nullable = format_nullability(field);
36 let data_type = field.data_type();
37 let metadata_str = format_metadata(field.metadata());
38 format!("{name:?}: {maybe_nullable}{data_type}{metadata_str}")
39 }
40
41 match &self {
48 Self::Null => write!(f, "Null"),
49 Self::Boolean => write!(f, "Boolean"),
50 Self::Int8 => write!(f, "Int8"),
51 Self::Int16 => write!(f, "Int16"),
52 Self::Int32 => write!(f, "Int32"),
53 Self::Int64 => write!(f, "Int64"),
54 Self::UInt8 => write!(f, "UInt8"),
55 Self::UInt16 => write!(f, "UInt16"),
56 Self::UInt32 => write!(f, "UInt32"),
57 Self::UInt64 => write!(f, "UInt64"),
58 Self::Float16 => write!(f, "Float16"),
59 Self::Float32 => write!(f, "Float32"),
60 Self::Float64 => write!(f, "Float64"),
61 Self::Timestamp(time_unit, timezone) => {
62 if let Some(timezone) = timezone {
63 write!(f, "Timestamp({time_unit}, {timezone:?})")
64 } else {
65 write!(f, "Timestamp({time_unit})")
66 }
67 }
68 Self::Date32 => write!(f, "Date32"),
69 Self::Date64 => write!(f, "Date64"),
70 Self::Time32(time_unit) => write!(f, "Time32({time_unit})"),
71 Self::Time64(time_unit) => write!(f, "Time64({time_unit})"),
72 Self::Duration(time_unit) => write!(f, "Duration({time_unit})"),
73 Self::Interval(interval_unit) => write!(f, "Interval({interval_unit:?})"),
74 Self::Binary => write!(f, "Binary"),
75 Self::FixedSizeBinary(bytes_per_value) => {
76 write!(f, "FixedSizeBinary({bytes_per_value:?})")
77 }
78 Self::LargeBinary => write!(f, "LargeBinary"),
79 Self::BinaryView => write!(f, "BinaryView"),
80 Self::Utf8 => write!(f, "Utf8"),
81 Self::LargeUtf8 => write!(f, "LargeUtf8"),
82 Self::Utf8View => write!(f, "Utf8View"),
83 Self::List(field)
84 | Self::LargeList(field)
85 | Self::ListView(field)
86 | Self::LargeListView(field) => {
87 let type_name = if matches!(self, Self::List(_)) {
88 "List"
89 } else if matches!(self, Self::ListView(_)) {
90 "ListView"
91 } else if matches!(self, Self::LargeList(_)) {
92 "LargeList"
93 } else {
94 "LargeListView"
95 };
96
97 let name = field.name();
98 let maybe_nullable = format_nullability(field);
99 let data_type = field.data_type();
100 let field_name_str = if name == "item" {
101 String::default()
102 } else {
103 format!(", field: '{name}'")
104 };
105 let metadata_str = format_metadata(field.metadata());
106
107 write!(
109 f,
110 "{type_name}({maybe_nullable}{data_type}{field_name_str}{metadata_str})"
111 )
112 }
113 Self::FixedSizeList(field, size) => {
114 let name = field.name();
115 let maybe_nullable = format_nullability(field);
116 let data_type = field.data_type();
117 let field_name_str = if name == "item" {
118 String::default()
119 } else {
120 format!(", field: '{name}'")
121 };
122 let metadata_str = format_metadata(field.metadata());
123
124 write!(
125 f,
126 "FixedSizeList({size} x {maybe_nullable}{data_type}{field_name_str}{metadata_str})",
127 )
128 }
129 Self::Struct(fields) => {
130 write!(f, "Struct(")?;
131 if !fields.is_empty() {
132 let fields_str = fields
133 .iter()
134 .map(|field| format_field(field))
135 .collect::<Vec<_>>()
136 .join(", ");
137 write!(f, "{fields_str}")?;
138 }
139 write!(f, ")")?;
140 Ok(())
141 }
142 Self::Union(union_fields, union_mode) => {
143 write!(f, "Union({union_mode:?}")?;
144 if !union_fields.is_empty() {
145 write!(f, ", ")?;
146 let fields_str = union_fields
147 .iter()
148 .map(|v| {
149 let type_id = v.0;
150 let field_str = format_field(v.1);
151 format!("{type_id:?}: ({field_str})")
152 })
153 .collect::<Vec<_>>()
154 .join(", ");
155 write!(f, "{fields_str}")?;
156 }
157 write!(f, ")")?;
158 Ok(())
159 }
160 Self::Dictionary(data_type, data_type1) => {
161 write!(f, "Dictionary({data_type}, {data_type1})")
162 }
163 Self::Decimal32(precision, scale) => write!(f, "Decimal32({precision}, {scale})"),
164 Self::Decimal64(precision, scale) => write!(f, "Decimal64({precision}, {scale})"),
165 Self::Decimal128(precision, scale) => write!(f, "Decimal128({precision}, {scale})"),
166 Self::Decimal256(precision, scale) => write!(f, "Decimal256({precision}, {scale})"),
167 Self::Map(field, sorted) => {
168 write!(f, "Map(")?;
169 let map_field_str = format_field(field);
170 let keys_are_sorted = if *sorted { "sorted" } else { "unsorted" };
171
172 write!(f, "{map_field_str}, {keys_are_sorted})")?;
173 Ok(())
174 }
175 Self::RunEndEncoded(run_ends_field, values_field) => {
176 write!(f, "RunEndEncoded(")?;
177 let run_ends_str = format_field(run_ends_field);
178 let values_str = format_field(values_field);
179
180 write!(f, "{run_ends_str}, {values_str})")?;
181 Ok(())
182 }
183 }
184 }
185}
186
187struct FormatMetadata<'a>(&'a Metadata);
189
190impl fmt::Display for FormatMetadata<'_> {
191 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
192 let metadata = self.0;
193 if metadata.is_empty() {
194 Ok(())
195 } else {
196 write!(f, ", metadata: ")?;
198 f.debug_map().entries(metadata.iter()).finish()
199 }
200 }
201}
202
203#[cfg(test)]
204mod tests {
205
206 use std::collections::HashMap;
207 use std::sync::Arc;
208
209 use crate::Field;
210
211 use super::*;
212
213 #[test]
214 fn test_display_list() {
215 let list_data_type = DataType::List(Arc::new(Field::new_list_field(DataType::Int32, true)));
216 let list_data_type_string = list_data_type.to_string();
217 let expected_string = "List(Int32)";
218 assert_eq!(list_data_type_string, expected_string);
219 }
220
221 #[test]
222 fn test_display_list_view() {
223 let list_view_data_type =
224 DataType::ListView(Arc::new(Field::new("item", DataType::Int32, true)));
225 let list_view_data_type_string = list_view_data_type.to_string();
226 let expected_string = "ListView(Int32)";
227 assert_eq!(list_view_data_type_string, expected_string);
228 }
229
230 #[test]
231 fn test_display_list_with_named_field() {
232 let list_data_type = DataType::List(Arc::new(Field::new("foo", DataType::UInt64, false)));
233 let list_data_type_string = list_data_type.to_string();
234 let expected_string = "List(non-null UInt64, field: 'foo')";
235 assert_eq!(list_data_type_string, expected_string);
236 }
237
238 #[test]
239 fn test_display_list_view_with_named_field() {
240 let list_view_data_type =
241 DataType::ListView(Arc::new(Field::new("bar", DataType::UInt64, false)));
242 let list_view_data_type_string = list_view_data_type.to_string();
243 let expected_string = "ListView(non-null UInt64, field: 'bar')";
244 assert_eq!(list_view_data_type_string, expected_string);
245 }
246
247 #[test]
248 fn test_display_nested_list() {
249 let nested_data_type = DataType::List(Arc::new(Field::new_list_field(
250 DataType::List(Arc::new(Field::new_list_field(DataType::UInt64, false))),
251 false,
252 )));
253 let nested_data_type_string = nested_data_type.to_string();
254 let nested_expected_string = "List(non-null List(non-null UInt64))";
255 assert_eq!(nested_data_type_string, nested_expected_string);
256 }
257
258 #[test]
259 fn test_display_nested_list_view() {
260 let nested_view_data_type = DataType::ListView(Arc::new(Field::new_list_field(
261 DataType::ListView(Arc::new(Field::new_list_field(DataType::UInt64, false))),
262 false,
263 )));
264 let nested_view_data_type_string = nested_view_data_type.to_string();
265 let nested_view_expected_string = "ListView(non-null ListView(non-null UInt64))";
266 assert_eq!(nested_view_data_type_string, nested_view_expected_string);
267 }
268
269 #[test]
270 fn test_display_list_with_metadata() {
271 let mut field = Field::new_list_field(DataType::Int32, true);
272 let metadata = HashMap::from([("foo1".to_string(), "value1".to_string())]);
273 field.set_metadata(metadata);
274 let list_data_type = DataType::List(Arc::new(field));
275 let list_data_type_string = list_data_type.to_string();
276 let expected_string = "List(Int32, metadata: {\"foo1\": \"value1\"})";
277
278 assert_eq!(list_data_type_string, expected_string);
279 }
280
281 #[test]
282 fn test_display_list_view_with_metadata() {
283 let mut field = Field::new_list_field(DataType::Int32, true);
284 let metadata = HashMap::from([("foo2".to_string(), "value2".to_string())]);
285 field.set_metadata(metadata);
286 let list_view_data_type = DataType::ListView(Arc::new(field));
287 let list_view_data_type_string = list_view_data_type.to_string();
288 let expected_string = "ListView(Int32, metadata: {\"foo2\": \"value2\"})";
289 assert_eq!(list_view_data_type_string, expected_string);
290 }
291
292 #[test]
293 fn test_display_large_list() {
294 let large_list_data_type =
295 DataType::LargeList(Arc::new(Field::new_list_field(DataType::Int32, true)));
296 let large_list_data_type_string = large_list_data_type.to_string();
297 let expected_string = "LargeList(Int32)";
298 assert_eq!(large_list_data_type_string, expected_string);
299
300 let large_list_named =
302 DataType::LargeList(Arc::new(Field::new("bar", DataType::UInt64, false)));
303 let large_list_named_string = large_list_named.to_string();
304 let expected_named_string = "LargeList(non-null UInt64, field: 'bar')";
305 assert_eq!(large_list_named_string, expected_named_string);
306
307 let mut field = Field::new_list_field(DataType::Int32, true);
309 let metadata = HashMap::from([("key1".to_string(), "value1".to_string())]);
310 field.set_metadata(metadata);
311 let large_list_metadata = DataType::LargeList(Arc::new(field));
312 let large_list_metadata_string = large_list_metadata.to_string();
313 let expected_metadata_string = "LargeList(Int32, metadata: {\"key1\": \"value1\"})";
314 assert_eq!(large_list_metadata_string, expected_metadata_string);
315 }
316
317 #[test]
318 fn test_display_large_list_view() {
319 let large_list_view_data_type =
320 DataType::LargeListView(Arc::new(Field::new("item", DataType::Int32, true)));
321 let large_list_view_data_type_string = large_list_view_data_type.to_string();
322 let expected_string = "LargeListView(Int32)";
323 assert_eq!(large_list_view_data_type_string, expected_string);
324
325 let large_list_view_named =
327 DataType::LargeListView(Arc::new(Field::new("bar", DataType::UInt64, false)));
328 let large_list_view_named_string = large_list_view_named.to_string();
329 let expected_named_string = "LargeListView(non-null UInt64, field: 'bar')";
330 assert_eq!(large_list_view_named_string, expected_named_string);
331
332 let mut field = Field::new_list_field(DataType::Int32, true);
334 let metadata = HashMap::from([("key1".to_string(), "value1".to_string())]);
335 field.set_metadata(metadata);
336 let large_list_view_metadata = DataType::LargeListView(Arc::new(field));
337 let large_list_view_metadata_string = large_list_view_metadata.to_string();
338 let expected_metadata_string = "LargeListView(Int32, metadata: {\"key1\": \"value1\"})";
339 assert_eq!(large_list_view_metadata_string, expected_metadata_string);
340 }
341
342 #[test]
343 fn test_display_fixed_size_list() {
344 let fixed_size_list =
345 DataType::FixedSizeList(Arc::new(Field::new_list_field(DataType::Int32, true)), 5);
346 let fixed_size_list_string = fixed_size_list.to_string();
347 let expected_string = "FixedSizeList(5 x Int32)";
348 assert_eq!(fixed_size_list_string, expected_string);
349
350 let fixed_size_named =
352 DataType::FixedSizeList(Arc::new(Field::new("baz", DataType::UInt64, false)), 3);
353 let fixed_size_named_string = fixed_size_named.to_string();
354 let expected_named_string = "FixedSizeList(3 x non-null UInt64, field: 'baz')";
355 assert_eq!(fixed_size_named_string, expected_named_string);
356
357 let mut field = Field::new_list_field(DataType::Int32, true);
359 let metadata = HashMap::from([("key2".to_string(), "value2".to_string())]);
360 field.set_metadata(metadata);
361 let fixed_size_metadata = DataType::FixedSizeList(Arc::new(field), 4);
362 let fixed_size_metadata_string = fixed_size_metadata.to_string();
363 let expected_metadata_string = "FixedSizeList(4 x Int32, metadata: {\"key2\": \"value2\"})";
364 assert_eq!(fixed_size_metadata_string, expected_metadata_string);
365 }
366
367 #[test]
368 fn test_display_struct() {
369 let fields = vec![
370 Field::new("a", DataType::Int32, false),
371 Field::new("b", DataType::Utf8, true),
372 ];
373 let struct_data_type = DataType::Struct(fields.into());
374 let struct_data_type_string = struct_data_type.to_string();
375 let expected_string = "Struct(\"a\": non-null Int32, \"b\": Utf8)";
376 assert_eq!(struct_data_type_string, expected_string);
377
378 let mut field_with_metadata = Field::new("b", DataType::Utf8, true);
380 let metadata = HashMap::from([
381 ("key".to_string(), "value".to_string()),
382 ("key2".to_string(), "value2".to_string()),
383 ]);
384 field_with_metadata.set_metadata(metadata);
385 let struct_fields_with_metadata =
386 vec![Field::new("a", DataType::Int32, false), field_with_metadata];
387 let struct_data_type_with_metadata = DataType::Struct(struct_fields_with_metadata.into());
388 let struct_data_type_with_metadata_string = struct_data_type_with_metadata.to_string();
389 let expected_string_with_metadata = "Struct(\"a\": non-null Int32, \"b\": Utf8, metadata: {\"key\": \"value\", \"key2\": \"value2\"})";
390 assert_eq!(
391 struct_data_type_with_metadata_string,
392 expected_string_with_metadata
393 );
394 }
395
396 #[test]
397 fn test_display_union() {
398 let fields = vec![
399 Field::new("a", DataType::Int32, false),
400 Field::new("b", DataType::Utf8, true),
401 ];
402 let type_ids = vec![0, 1];
403 let union_fields = type_ids
404 .into_iter()
405 .zip(fields.into_iter().map(Arc::new))
406 .collect();
407
408 let union_data_type = DataType::Union(union_fields, crate::UnionMode::Sparse);
409 let union_data_type_string = union_data_type.to_string();
410 let expected_string = "Union(Sparse, 0: (\"a\": non-null Int32), 1: (\"b\": Utf8))";
411 assert_eq!(union_data_type_string, expected_string);
412
413 let mut field_with_metadata = Field::new("b", DataType::Utf8, true);
415 let metadata = HashMap::from([("key".to_string(), "value".to_string())]);
416 field_with_metadata.set_metadata(metadata);
417 let union_fields_with_metadata = vec![
418 (0, Arc::new(Field::new("a", DataType::Int32, false))),
419 (1, Arc::new(field_with_metadata)),
420 ]
421 .into_iter()
422 .collect();
423 let union_data_type_with_metadata =
424 DataType::Union(union_fields_with_metadata, crate::UnionMode::Sparse);
425 let union_data_type_with_metadata_string = union_data_type_with_metadata.to_string();
426 let expected_string_with_metadata = "Union(Sparse, 0: (\"a\": non-null Int32), 1: (\"b\": Utf8, metadata: {\"key\": \"value\"}))";
427 assert_eq!(
428 union_data_type_with_metadata_string,
429 expected_string_with_metadata
430 );
431 }
432
433 #[test]
434 fn test_display_map() {
435 let entry_field = Field::new(
436 Field::MAP_ENTRIES_FIELD_DEFAULT_NAME,
437 DataType::Struct(
438 vec![
439 Field::new(Field::MAP_KEY_FIELD_DEFAULT_NAME, DataType::Utf8, false),
440 Field::new(Field::MAP_VALUE_FIELD_DEFAULT_NAME, DataType::Int32, true),
441 ]
442 .into(),
443 ),
444 false,
445 );
446 let map_data_type = DataType::Map(Arc::new(entry_field), true);
447 let map_data_type_string = map_data_type.to_string();
448 let expected_string =
449 "Map(\"entries\": non-null Struct(\"key\": non-null Utf8, \"value\": Int32), sorted)";
450 assert_eq!(map_data_type_string, expected_string);
451
452 let mut entry_field_with_metadata = Field::new(
454 Field::MAP_ENTRIES_FIELD_DEFAULT_NAME,
455 DataType::Struct(
456 vec![
457 Field::new(Field::MAP_KEY_FIELD_DEFAULT_NAME, DataType::Utf8, false),
458 Field::new(Field::MAP_VALUE_FIELD_DEFAULT_NAME, DataType::Int32, true),
459 ]
460 .into(),
461 ),
462 false,
463 );
464 let metadata = HashMap::from([("key".to_string(), "value".to_string())]);
465 entry_field_with_metadata.set_metadata(metadata);
466 let map_data_type_with_metadata = DataType::Map(Arc::new(entry_field_with_metadata), true);
467 let map_data_type_with_metadata_string = map_data_type_with_metadata.to_string();
468 let expected_string_with_metadata = "Map(\"entries\": non-null Struct(\"key\": non-null Utf8, \"value\": Int32), metadata: {\"key\": \"value\"}, sorted)";
469 assert_eq!(
470 map_data_type_with_metadata_string,
471 expected_string_with_metadata
472 );
473 }
474
475 #[test]
476 fn test_display_run_end_encoded() {
477 let run_ends_field = Arc::new(Field::new("run_ends", DataType::UInt32, false));
478 let values_field = Arc::new(Field::new("values", DataType::Int32, true));
479 let ree_data_type = DataType::RunEndEncoded(run_ends_field.clone(), values_field.clone());
480 let ree_data_type_string = ree_data_type.to_string();
481 let expected_string = "RunEndEncoded(\"run_ends\": non-null UInt32, \"values\": Int32)";
482 assert_eq!(ree_data_type_string, expected_string);
483
484 let mut run_ends_field_with_metadata = Field::new("run_ends", DataType::UInt32, false);
486 let metadata = HashMap::from([("key".to_string(), "value".to_string())]);
487 run_ends_field_with_metadata.set_metadata(metadata);
488 let ree_data_type_with_metadata =
489 DataType::RunEndEncoded(Arc::new(run_ends_field_with_metadata), values_field.clone());
490 let ree_data_type_with_metadata_string = ree_data_type_with_metadata.to_string();
491 let expected_string_with_metadata = "RunEndEncoded(\"run_ends\": non-null UInt32, metadata: {\"key\": \"value\"}, \"values\": Int32)";
492 assert_eq!(
493 ree_data_type_with_metadata_string,
494 expected_string_with_metadata
495 );
496 }
497
498 #[test]
499 fn test_display_dictionary() {
500 let dict_data_type =
501 DataType::Dictionary(Box::new(DataType::Int8), Box::new(DataType::Utf8));
502 let dict_data_type_string = dict_data_type.to_string();
503 let expected_string = "Dictionary(Int8, Utf8)";
504 assert_eq!(dict_data_type_string, expected_string);
505
506 let complex_dict_data_type = DataType::Dictionary(
508 Box::new(DataType::Int16),
509 Box::new(DataType::Struct(
510 vec![
511 Field::new("a", DataType::Int32, false),
512 Field::new("b", DataType::Utf8, true),
513 ]
514 .into(),
515 )),
516 );
517 let complex_dict_data_type_string = complex_dict_data_type.to_string();
518 let expected_complex_string =
519 "Dictionary(Int16, Struct(\"a\": non-null Int32, \"b\": Utf8))";
520 assert_eq!(complex_dict_data_type_string, expected_complex_string);
521 }
522
523 #[test]
524 fn test_display_interval() {
525 let interval_year_month = DataType::Interval(crate::IntervalUnit::YearMonth);
526 let interval_year_month_string = interval_year_month.to_string();
527 let expected_year_month_string = "Interval(YearMonth)";
528 assert_eq!(interval_year_month_string, expected_year_month_string);
529
530 let interval_day_time = DataType::Interval(crate::IntervalUnit::DayTime);
531 let interval_day_time_string = interval_day_time.to_string();
532 let expected_day_time_string = "Interval(DayTime)";
533 assert_eq!(interval_day_time_string, expected_day_time_string);
534
535 let interval_month_day_nano = DataType::Interval(crate::IntervalUnit::MonthDayNano);
536 let interval_month_day_nano_string = interval_month_day_nano.to_string();
537 let expected_month_day_nano_string = "Interval(MonthDayNano)";
538 assert_eq!(
539 interval_month_day_nano_string,
540 expected_month_day_nano_string
541 );
542 }
543
544 #[test]
545 fn test_display_timestamp() {
546 let timestamp_without_tz = DataType::Timestamp(crate::TimeUnit::Microsecond, None);
547 let timestamp_without_tz_string = timestamp_without_tz.to_string();
548 let expected_without_tz_string = "Timestamp(µs)";
549 assert_eq!(timestamp_without_tz_string, expected_without_tz_string);
550
551 let timestamp_with_tz =
552 DataType::Timestamp(crate::TimeUnit::Nanosecond, Some(Arc::from("UTC")));
553 let timestamp_with_tz_string = timestamp_with_tz.to_string();
554 let expected_with_tz_string = "Timestamp(ns, \"UTC\")";
555 assert_eq!(timestamp_with_tz_string, expected_with_tz_string);
556 }
557}