parallel_disk_usage/visualizer/methods/
initial_table.rs

1use super::{NodeInfo, Table, BORDER_COLUMNS, PERCENTAGE_COLUMN_MAX_WIDTH};
2use crate::{data_tree::DataTree, size, visualizer::Visualizer};
3use assert_cmp::debug_assert_op;
4use derive_more::{Deref, DerefMut};
5use std::{cmp::max, fmt::Display, num::NonZeroUsize};
6
7#[derive(Deref, DerefMut)]
8pub(super) struct InitialRow<Name, NodeData> {
9    #[deref]
10    #[deref_mut]
11    pub(super) node_info: NodeInfo<Name, NodeData>,
12    pub(super) ancestors: Vec<NodeInfo<Name, NodeData>>,
13    pub(super) preceding_sibling: Option<NodeInfo<Name, NodeData>>,
14    pub(super) size: String,
15    pub(super) percentage: String,
16}
17
18impl<Name, NodeData> InitialRow<Name, NodeData> {
19    #[inline]
20    pub(super) fn parent(&self) -> Option<&'_ NodeInfo<Name, NodeData>> {
21        self.ancestors.last()
22    }
23}
24
25#[derive(Default, Clone, Copy)]
26pub(super) struct InitialColumnWidth {
27    pub(super) size_column_width: usize,
28}
29
30impl InitialColumnWidth {
31    #[inline]
32    pub(super) const fn total_max_width(self) -> usize {
33        self.size_column_width + PERCENTAGE_COLUMN_MAX_WIDTH + BORDER_COLUMNS
34    }
35}
36
37pub(super) type InitialTable<Name, NodeData> =
38    Table<InitialRow<Name, NodeData>, InitialColumnWidth>;
39
40pub(super) fn render_initial<Name, Size>(
41    visualizer: Visualizer<Name, Size>,
42) -> InitialTable<&'_ Name, Size>
43where
44    Name: Display,
45    Size: size::Size + Into<u64>,
46{
47    #[derive(Clone)]
48    struct Param<Name, NodeData> {
49        index_as_child: usize,
50        ancestors: Vec<NodeInfo<Name, NodeData>>,
51        preceding_sibling: Option<NodeInfo<Name, NodeData>>,
52    }
53
54    struct ActResult<Name, NodeData> {
55        node_info: NodeInfo<Name, NodeData>,
56    }
57
58    struct TraverseResult<Name, NodeData> {
59        node_info: NodeInfo<Name, NodeData>,
60    }
61
62    fn traverse<'a, Name, Size, Act>(
63        tree: &'a DataTree<Name, Size>,
64        act: &mut Act,
65        param: Param<&'a Name, Size>,
66    ) -> Option<TraverseResult<&'a Name, Size>>
67    where
68        Size: size::Size,
69        Act: FnMut(&'a DataTree<Name, Size>, Param<&'a Name, Size>) -> ActResult<&'a Name, Size>,
70    {
71        let ActResult { node_info } = act(tree, param.clone());
72        let mut preceding_sibling = None;
73        for (index_as_child, child) in tree.children().iter().enumerate() {
74            let mut ancestors = Vec::with_capacity(param.ancestors.len() + 1);
75            ancestors.clone_from(&param.ancestors);
76            ancestors.push(node_info);
77            let traverse_result = traverse(
78                child,
79                act,
80                Param {
81                    index_as_child,
82                    ancestors,
83                    preceding_sibling,
84                },
85            );
86            preceding_sibling = traverse_result.map(|x| x.node_info);
87        }
88        Some(TraverseResult { node_info })
89    }
90
91    let mut initial_table = InitialTable::default();
92    let total_fs_size = visualizer.data_tree.size().into();
93
94    traverse(
95        visualizer.data_tree,
96        &mut |node, param| {
97            let Param {
98                index_as_child,
99                ancestors,
100                preceding_sibling,
101            } = param;
102            let name = node.name();
103            let node_data = node.size();
104            let row_index = initial_table.len();
105            let children_count = node.children().len();
106            let fs_size = node.size().into();
107            let percentage = if total_fs_size == 0 {
108                "0%".to_string()
109            } else {
110                let percentage = rounded_div::u64(fs_size * 100, total_fs_size);
111                format!("{percentage}%")
112            };
113            let size = node.size().display(visualizer.bytes_format).to_string();
114            let sibling_count = ancestors.last().map_or(1, |parent| parent.children_count);
115            debug_assert_op!(sibling_count != 0);
116            debug_assert_op!(index_as_child < sibling_count);
117            let sibling_count = unsafe { NonZeroUsize::new_unchecked(sibling_count) };
118            let node_info = NodeInfo {
119                name,
120                node_data,
121                row_index,
122                sibling_count,
123                index_as_child,
124                children_count,
125            };
126
127            initial_table.column_width.size_column_width =
128                max(initial_table.column_width.size_column_width, size.len());
129
130            initial_table.push_back(InitialRow {
131                node_info,
132                ancestors,
133                preceding_sibling,
134                size,
135                percentage,
136            });
137
138            ActResult { node_info }
139        },
140        Param {
141            index_as_child: 0,
142            ancestors: Vec::new(),
143            preceding_sibling: None,
144        },
145    );
146
147    initial_table
148}