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        remaining_depth: usize,
50        index_as_child: usize,
51        ancestors: Vec<NodeInfo<Name, NodeData>>,
52        preceding_sibling: Option<NodeInfo<Name, NodeData>>,
53    }
54
55    struct ActResult<Name, NodeData> {
56        node_info: NodeInfo<Name, NodeData>,
57    }
58
59    struct TraverseResult<Name, NodeData> {
60        node_info: NodeInfo<Name, NodeData>,
61    }
62
63    fn traverse<'a, Name, Size, Act>(
64        tree: &'a DataTree<Name, Size>,
65        act: &mut Act,
66        param: Param<&'a Name, Size>,
67    ) -> Option<TraverseResult<&'a Name, Size>>
68    where
69        Size: size::Size,
70        Act: FnMut(&'a DataTree<Name, Size>, Param<&'a Name, Size>) -> ActResult<&'a Name, Size>,
71    {
72        if param.remaining_depth == 0 {
73            return None;
74        }
75        let ActResult { node_info } = act(tree, param.clone());
76        let remaining_depth = param.remaining_depth - 1;
77        let mut preceding_sibling = None;
78        for (index_as_child, child) in tree.children().iter().enumerate() {
79            let mut ancestors = Vec::with_capacity(param.ancestors.len() + 1);
80            ancestors.clone_from(&param.ancestors);
81            ancestors.push(node_info);
82            let traverse_result = traverse(
83                child,
84                act,
85                Param {
86                    remaining_depth,
87                    index_as_child,
88                    ancestors,
89                    preceding_sibling,
90                },
91            );
92            preceding_sibling = traverse_result.map(|x| x.node_info);
93        }
94        Some(TraverseResult { node_info })
95    }
96
97    let mut initial_table = InitialTable::default();
98    let total_fs_size = visualizer.data_tree.size().into();
99
100    traverse(
101        visualizer.data_tree,
102        &mut |node, param| {
103            let Param {
104                index_as_child,
105                ancestors,
106                remaining_depth,
107                preceding_sibling,
108            } = param;
109            let name = node.name();
110            let node_data = node.size();
111            let row_index = initial_table.len();
112            debug_assert_op!(remaining_depth > 0);
113            let children_count = if remaining_depth != 1 {
114                node.children().len()
115            } else {
116                0
117            };
118            let fs_size = node.size().into();
119            let percentage = if total_fs_size == 0 {
120                "0%".to_string()
121            } else {
122                let percentage = rounded_div::u64(fs_size * 100, total_fs_size);
123                format!("{percentage}%")
124            };
125            let size = node.size().display(visualizer.bytes_format).to_string();
126            let sibling_count = ancestors.last().map_or(1, |parent| parent.children_count);
127            debug_assert_op!(sibling_count != 0);
128            debug_assert_op!(index_as_child < sibling_count);
129            let sibling_count = unsafe { NonZeroUsize::new_unchecked(sibling_count) };
130            let node_info = NodeInfo {
131                name,
132                node_data,
133                row_index,
134                sibling_count,
135                index_as_child,
136                children_count,
137                remaining_depth,
138            };
139
140            initial_table.column_width.size_column_width =
141                max(initial_table.column_width.size_column_width, size.len());
142
143            initial_table.push_back(InitialRow {
144                node_info,
145                ancestors,
146                preceding_sibling,
147                size,
148                percentage,
149            });
150
151            ActResult { node_info }
152        },
153        Param {
154            remaining_depth: visualizer.max_depth.get(),
155            index_as_child: 0,
156            ancestors: Vec::with_capacity(0),
157            preceding_sibling: None,
158        },
159    );
160
161    initial_table
162}