parallel_disk_usage/visualizer/
tree.rs1use super::{ChildPosition, Direction, Parenthood};
2use derive_more::{AsRef, Deref, Display, Into};
3use fmt_iter::FmtIter;
4use pipe_trait::Pipe;
5use std::fmt::{Error, Formatter};
6use zero_copy_pads::Width;
7
8#[derive(Debug, Clone, Copy, PartialEq, Eq)]
11pub struct TreeSkeletalComponent {
12 pub child_position: ChildPosition,
14 pub direction: Direction,
16 pub parenthood: Parenthood,
18}
19
20#[derive(Debug, Clone, Copy, PartialEq, Eq, AsRef, Deref, Display, Into)]
22pub struct TreeSkeletalComponentVisualization(&'static str);
23
24impl TreeSkeletalComponent {
25 pub const fn visualize(self) -> TreeSkeletalComponentVisualization {
28 use ChildPosition::*;
29 use Direction::*;
30 use Parenthood::*;
31 let result = match (self.child_position, self.direction, self.parenthood) {
32 (Init, BottomUp, Parent) => "├─┴",
33 (Init, BottomUp, Childless) => "├──",
34 (Init, TopDown, Parent) => "├─┬",
35 (Init, TopDown, Childless) => "├──",
36 (Last, BottomUp, Parent) => "┌─┴",
37 (Last, BottomUp, Childless) => "┌──",
38 (Last, TopDown, Parent) => "└─┬",
39 (Last, TopDown, Childless) => "└──",
40 };
41 TreeSkeletalComponentVisualization(result)
42 }
43}
44
45impl Display for TreeSkeletalComponent {
46 fn fmt(&self, formatter: &mut Formatter<'_>) -> Result<(), Error> {
47 write!(formatter, "{}", self.visualize())
48 }
49}
50
51impl Width for TreeSkeletalComponent {
52 fn width(&self) -> usize {
53 self.visualize().width()
54 }
55}
56
57#[derive(Debug, Clone, PartialEq, Eq)]
59pub struct TreeHorizontalSlice<Name: Width> {
60 pub(super) ancestor_relative_positions: Vec<ChildPosition>,
61 pub(super) skeletal_component: TreeSkeletalComponent,
62 pub(super) name: Name,
63}
64
65impl<Name: Width> TreeHorizontalSlice<Name> {
66 #[inline]
67 fn depth(&self) -> usize {
68 self.ancestor_relative_positions.len()
69 }
70
71 #[inline]
72 fn indent_width(&self) -> usize {
73 self.depth() * 2
74 }
75
76 #[inline]
77 fn required_width(&self) -> usize {
78 self.indent_width() + self.skeletal_component.width()
79 }
80
81 #[inline]
82 fn indent(&self) -> impl Display + '_ {
83 self.ancestor_relative_positions
84 .iter()
85 .map(|position| match position {
86 ChildPosition::Init => "│ ",
87 ChildPosition::Last => " ",
88 })
89 .pipe(FmtIter::from)
90 }
91}
92
93impl<Name: Width> Display for TreeHorizontalSlice<Name> {
94 fn fmt(&self, formatter: &mut Formatter<'_>) -> Result<(), Error> {
95 write!(
96 formatter,
97 "{}{}{}",
98 self.indent(),
99 self.skeletal_component,
100 &self.name,
101 )
102 }
103}
104
105impl<Name: Width> Width for TreeHorizontalSlice<Name> {
106 fn width(&self) -> usize {
107 self.required_width() + self.name.width()
108 }
109}
110
111impl TreeHorizontalSlice<String> {
112 pub fn truncate(&mut self, max_width: usize) -> Result<(), usize> {
120 if self.width() <= max_width {
121 return Ok(());
122 }
123
124 let min_width = self.required_width() + "...".len();
125 if min_width >= max_width {
126 return Err(min_width);
127 }
128
129 self.name.truncate(max_width - min_width);
130 self.name += "...";
131 Ok(())
132 }
133}