kubectl_view_allocations/
tree.rs1#[derive(Debug, Clone)]
45struct TreeNode {
46 parent: Option<usize>,
47 level: Vec<bool>,
48 children: Vec<usize>,
49}
50
51fn level_to_string(level: &[bool]) -> String {
52 const EMPTY: &str = " ";
53 const EDGE: &str = " └─";
54 const PIPE: &str = " │ ";
55 const BRANCH: &str = " ├─";
56
57 let mut prefix = String::new();
58 if !level.is_empty() {
59 let last_col = level.len() - 1;
60 for (col, is_last_child) in level.iter().enumerate() {
61 let is_last_col = col == last_col;
62 let s = match (*is_last_child, is_last_col) {
63 (true, false) => EMPTY,
64 (true, true) => EDGE,
65 (false, false) => PIPE,
66 (false, true) => BRANCH,
67 };
68 prefix.push_str(s);
69 }
70 }
71 prefix
72}
73
74fn write_tree_level_of_children(nodes: &mut [TreeNode], idx: usize) {
75 if let Some(node) = nodes.get(idx) {
76 let treenode = node.clone();
77 let mut d = treenode.children.len();
78 for s in treenode.children.iter() {
79 if let Some(child) = nodes.get_mut(*s) {
80 let mut lnext = treenode.level.clone();
81 lnext.push(d == 1);
82 d -= 1;
83 child.level = lnext;
84 }
85 }
86 }
87}
88
89fn make_tree_by_reverse_depth_first<I, F>(items: &[I], is_parent_of: F) -> Vec<TreeNode>
90where
91 F: Fn(&I, &I) -> bool,
92{
93 let mut current: Option<usize> = None;
94 let mut nodes: Vec<TreeNode> = vec![];
95 for (i, item) in items.iter().enumerate() {
96 while current.is_some() && !is_parent_of(&items[current.unwrap()], item) {
97 current = nodes.get_mut(current.unwrap()).and_then(|n| n.parent);
98 }
99 let treenode = TreeNode {
100 parent: current,
101 level: vec![],
102 children: vec![],
103 };
104 if let Some(parent) = current
105 && let Some(node) = nodes.get_mut(parent)
106 {
107 node.children.push(i);
108 }
109 nodes.push(treenode);
110 current = Some(i);
111 }
112 nodes
113}
114
115pub fn provide_prefix<I, F>(items: &[I], is_parent_of: F) -> Vec<String>
123where
124 F: Fn(&I, &I) -> bool,
125{
126 let mut nodes: Vec<TreeNode> = make_tree_by_reverse_depth_first(items, is_parent_of);
127 for i in 0..nodes.len() {
129 write_tree_level_of_children(&mut nodes, i);
130 }
131 nodes.iter().map(|n| level_to_string(&n.level)).collect()
133}
134
135#[cfg(test)]
136mod tests {
137 use super::*;
138
139 #[test]
140 fn test_() {
141 let items = vec!["1/2", "1/2/3", "1/2/3/4", "1/2/5", "6", "7", "7/8", "7/9"];
142
143 let prefixes = provide_prefix(&items, |parent, item| {
144 let pi = item.split('/');
145 let pp = parent.split('/');
146 (pi.count() == pp.count() + 1) && item.starts_with(parent)
147 });
148
149 let mut actual = String::new();
150 prefixes
151 .iter()
152 .zip(items)
153 .for_each(|(p, i)| actual.push_str(&format!("{} {}\n", p, i)));
154
155 let expected = r#" 1/2
156 ├─ 1/2/3
157 │ └─ 1/2/3/4
158 └─ 1/2/5
159 6
160 7
161 ├─ 7/8
162 └─ 7/9
163"#;
164 assert_eq!(actual, expected);
166 }
167}