1use unicode_width::UnicodeWidthStr;
2
3#[derive(Debug, Clone, Copy)]
4pub enum Align {
5 None,
6 Left,
7 Center,
8 Right,
9}
10
11impl Align {
12 pub fn new(s: String) -> Self {
13 match s.to_lowercase().as_str() {
14 "l" | "left" => Self::Left,
15 "c" | "center" => Self::Center,
16 "r" | "right" => Self::Right,
17 _ => Self::None,
18 }
19 }
20}
21
22#[derive(Debug, Clone)]
23pub struct Cell<T>
24where
25 T: std::fmt::Display,
26{
27 value: T,
28 width: usize,
29 align: Align,
30}
31
32impl<T> Cell<T>
33where
34 T: std::fmt::Display + Clone,
35{
36 pub fn new(v: T) -> Self {
37 Self {
38 value: v.clone(),
39 width: format!("{}", v.clone()).width(),
40 align: Align::None,
41 }
42 }
43
44 pub fn set_width(&mut self, w: usize) -> &mut Self {
45 self.width = w;
46 self
47 }
48
49 pub fn set_align(&mut self, a: Align) -> &mut Self {
50 self.align = a;
51 self
52 }
53
54 pub fn width(&self) -> usize {
55 self.width
56 }
57}
58
59impl<T> std::fmt::Display for Cell<T>
60where
61 T: std::fmt::Display,
62{
63 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
64 let s = match self.align {
65 Align::Right => {
66 format!(
67 "{}{}",
68 " ".repeat(self.width - format!("{}", self.value).width()),
69 self.value
70 )
71 }
72 Align::None | Align::Left => format!(
73 "{}{}",
74 self.value,
75 " ".repeat(self.width - format!("{}", self.value).width())
76 ),
77 Align::Center => {
78 let pad = (self.width - format!("{}", self.value).width()) as f32 / 2.0;
79 let left_pad = pad.ceil() as usize;
80 let right_pad = pad.floor() as usize;
81 format!(
82 "{}{}{}",
83 " ".repeat(left_pad),
84 self.value,
85 " ".repeat(right_pad)
86 )
87 }
88 };
89
90 write!(f, "{}", s)
91 }
92}
93
94#[cfg(test)]
95mod tests {
96 use super::{Align, Cell};
97
98 #[test]
99 fn create_cell() {
100 let cell = Cell::new(String::from("Hello"));
101 assert_eq!(cell.value, String::from("Hello"));
102 }
103
104 #[test]
105 fn display_cell() {
106 let cell = Cell::new(String::from("Hello"));
107 assert_eq!("Hello", format!("{}", cell))
108 }
109
110 #[test]
111 fn display_cell_with_width() {
112 let mut cell = Cell::new(String::from("Hello"));
113 cell.set_width(10);
114 assert_eq!("Hello ", format!("{}", cell))
115 }
116
117 #[test]
118 fn display_cell_with_align() {
119 struct TestCase<'a> {
120 value: &'a str,
121 width: usize,
122 align: Align,
123 expect: &'a str,
124 }
125
126 let data_set = vec![
127 TestCase {
128 value: "Hello",
129 width: 10,
130 align: Align::None,
131 expect: "Hello ",
132 },
133 TestCase {
134 value: "Hello",
135 width: 10,
136 align: Align::Left,
137 expect: "Hello ",
138 },
139 TestCase {
140 value: "Hello",
141 width: 10,
142 align: Align::Center,
143 expect: " Hello ",
144 },
145 TestCase {
146 value: "Hello",
147 width: 10,
148 align: Align::Right,
149 expect: " Hello",
150 },
151 ];
152
153 data_set.iter().for_each(|case| {
154 let mut cell = Cell::new(case.value);
155 cell.set_width(case.width).set_align(case.align);
156 assert_eq!(case.expect, format!("{}", cell));
157 });
158 }
159}