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::{Display, 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 #[inline]
53 fn width(&self) -> usize {
54 self.visualize().width()
55 }
56}
57
58#[derive(Debug, Clone, PartialEq, Eq)]
60pub struct TreeHorizontalSlice<Name: Width> {
61 pub(super) ancestor_relative_positions: Vec<ChildPosition>,
62 pub(super) skeletal_component: TreeSkeletalComponent,
63 pub(super) name: Name,
64}
65
66impl<Name: Width> TreeHorizontalSlice<Name> {
67 #[inline]
68 fn depth(&self) -> usize {
69 self.ancestor_relative_positions.len()
70 }
71
72 #[inline]
73 fn indent_width(&self) -> usize {
74 self.depth() * 2
75 }
76
77 #[inline]
78 fn required_width(&self) -> usize {
79 self.indent_width() + self.skeletal_component.width()
80 }
81
82 #[inline]
83 fn indent(&self) -> impl Display + '_ {
84 self.ancestor_relative_positions
85 .iter()
86 .map(|position| match position {
87 ChildPosition::Init => "│ ",
88 ChildPosition::Last => " ",
89 })
90 .pipe(FmtIter::from)
91 }
92}
93
94impl<Name: Width> Display for TreeHorizontalSlice<Name> {
95 fn fmt(&self, formatter: &mut Formatter<'_>) -> Result<(), Error> {
96 write!(
97 formatter,
98 "{}{}{}",
99 self.indent(),
100 self.skeletal_component,
101 &self.name,
102 )
103 }
104}
105
106impl<Name: Width> Width for TreeHorizontalSlice<Name> {
107 #[inline]
108 fn width(&self) -> usize {
109 self.required_width() + self.name.width()
110 }
111}
112
113impl TreeHorizontalSlice<String> {
114 pub fn truncate(&mut self, max_width: usize) -> Result<(), usize> {
122 if self.width() <= max_width {
123 return Ok(());
124 }
125
126 let min_width = self.required_width() + "...".len();
127 if min_width >= max_width {
128 return Err(min_width);
129 }
130
131 self.name.truncate(max_width - min_width);
132 self.name += "...";
133 Ok(())
134 }
135}