1use std::fmt::{self};
2
3use humansize::{DECIMAL, format_size};
4
5use crate::arrays::ChunkedEncoding;
6use crate::nbytes::NBytes;
7use crate::vtable::EncodingVTable;
8use crate::{Array, ArrayRef, ArrayVisitor};
9
10impl dyn Array + '_ {
11 pub fn tree_display(&self) -> impl fmt::Display {
12 TreeDisplayWrapper(self.to_array())
13 }
14}
15
16struct TreeDisplayWrapper(ArrayRef);
17
18impl fmt::Display for TreeDisplayWrapper {
19 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
20 let mut array_fmt = TreeFormatter {
21 fmt,
22 indent: "".to_string(),
23 total_size: None,
24 };
25 array_fmt.format("root", self.0.clone())
26 }
27}
28
29pub struct TreeFormatter<'a, 'b: 'a> {
30 fmt: &'a mut fmt::Formatter<'b>,
31 indent: String,
32 total_size: Option<usize>,
33}
34
35impl<'a, 'b: 'a> TreeFormatter<'a, 'b> {
36 fn format(&mut self, name: &str, array: ArrayRef) -> fmt::Result {
37 let nbytes = array.nbytes();
38 let total_size = self.total_size.unwrap_or(nbytes);
39 writeln!(
40 self,
41 "{}: {} nbytes={} ({:.2}%)",
42 name,
43 array,
44 format_size(nbytes, DECIMAL),
45 100f64 * nbytes as f64 / total_size as f64
46 )?;
47
48 self.indent(|i| {
49 write!(i, "metadata: ")?;
50 array.metadata_fmt(i.fmt)?;
51 writeln!(i.fmt)?;
52
53 for buffer in array.buffers() {
54 writeln!(
55 i,
56 "buffer (align={}): {}",
57 buffer.alignment(),
58 format_size(buffer.len(), DECIMAL)
59 )?;
60 }
61
62 Ok(())
63 })?;
64
65 let old_total_size = self.total_size;
66 if array.is_encoding(ChunkedEncoding.id()) {
67 self.total_size = None
69 } else {
70 self.total_size = Some(total_size);
71 }
72
73 self.indent(|i| {
74 for (name, child) in array
75 .children_names()
76 .into_iter()
77 .zip(array.children().into_iter())
78 {
79 i.format(&name, child)?;
80 }
81 Ok(())
82 })?;
83
84 self.total_size = old_total_size;
85 Ok(())
86 }
87
88 fn indent<F>(&mut self, indented: F) -> fmt::Result
89 where
90 F: FnOnce(&mut TreeFormatter) -> fmt::Result,
91 {
92 let original_ident = self.indent.clone();
93 self.indent += " ";
94 let res = indented(self);
95 self.indent = original_ident;
96 res
97 }
98
99 fn write_fmt(&mut self, fmt: fmt::Arguments<'_>) -> fmt::Result {
100 write!(self.fmt, "{}{}", self.indent, fmt)
101 }
102}