vortex_array/
tree.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
use std::fmt;

use humansize::{format_size, DECIMAL};
use serde::ser::Error;
use vortex_buffer::Buffer;
use vortex_error::{VortexError, VortexResult};

use crate::array::visitor::ArrayVisitor;
use crate::array::ChunkedArray;
use crate::{Array, ArrayData};

impl Array {
    pub fn tree_display(&self) -> TreeDisplayWrapper {
        TreeDisplayWrapper(self)
    }
}

pub struct TreeDisplayWrapper<'a>(&'a Array);
impl<'a> TreeDisplayWrapper<'a> {
    pub fn new(array: &'a Array) -> Self {
        Self(array)
    }
}

impl fmt::Display for TreeDisplayWrapper<'_> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        let array = self.0;
        let mut array_fmt = TreeFormatter::new(f, "".to_string());
        array_fmt
            .visit_child("root", array)
            .map_err(fmt::Error::custom)
    }
}

pub struct TreeFormatter<'a, 'b: 'a> {
    fmt: &'a mut fmt::Formatter<'b>,
    indent: String,
    total_size: Option<usize>,
}

/// TODO(ngates): I think we want to go back to the old explicit style. It gives arrays more
///  control over how their metadata etc is displayed.
impl<'a, 'b: 'a> ArrayVisitor for TreeFormatter<'a, 'b> {
    fn visit_child(&mut self, name: &str, array: &Array) -> VortexResult<()> {
        array.with_dyn(|a| {
            let nbytes = a.nbytes();
            let total_size = self.total_size.unwrap_or(nbytes);
            writeln!(
                self.fmt,
                "{}{}: {} nbytes={} ({:.2}%)",
                self.indent,
                name,
                array,
                format_size(nbytes, DECIMAL),
                100f64 * nbytes as f64 / total_size as f64
            )?;
            self.indent(|i| {
                let array_data = ArrayData::from(array.clone());
                writeln!(i.fmt, "{}metadata: {}", i.indent, array_data.metadata())
            })?;

            let old_total_size = self.total_size;
            if ChunkedArray::try_from(array).is_ok() {
                // Clear the total size so each chunk is treated as a new root.
                self.total_size = None
            } else {
                self.total_size = Some(total_size);
            }

            self.indent(|i| a.accept(i).map_err(fmt::Error::custom))
                .map_err(VortexError::from)?;

            self.total_size = old_total_size;
            Ok(())
        })
    }

    fn visit_buffer(&mut self, buffer: &Buffer) -> VortexResult<()> {
        Ok(writeln!(
            self.fmt,
            "{}buffer: {}",
            self.indent,
            format_size(buffer.len(), DECIMAL)
        )?)
    }
}

impl<'a, 'b: 'a> TreeFormatter<'a, 'b> {
    fn new(fmt: &'a mut fmt::Formatter<'b>, indent: String) -> Self {
        TreeFormatter {
            fmt,
            indent,
            total_size: None,
        }
    }

    fn indent<F>(&mut self, indented: F) -> fmt::Result
    where
        F: FnOnce(&mut TreeFormatter) -> fmt::Result,
    {
        let original_ident = self.indent.clone();
        self.indent += "  ";
        let res = indented(self);
        self.indent = original_ident;
        res
    }
}