codanna/display/
tables.rs1use comfy_table::{
4 Attribute, Cell, Color, Table, modifiers::UTF8_ROUND_CORNERS, presets::UTF8_FULL,
5};
6
7pub struct TableBuilder {
9 table: Table,
10}
11
12impl Default for TableBuilder {
13 fn default() -> Self {
14 Self::new()
15 }
16}
17
18impl TableBuilder {
19 pub fn new() -> Self {
21 let mut table = Table::new();
22 table.load_preset(UTF8_FULL);
23 table.apply_modifier(UTF8_ROUND_CORNERS);
25 Self { table }
26 }
27
28 pub fn set_headers(mut self, headers: Vec<&str>) -> Self {
30 let header_cells: Vec<Cell> = headers
31 .into_iter()
32 .map(|h| Cell::new(h).add_attribute(Attribute::Bold))
33 .collect();
34 self.table.set_header(header_cells);
35 self
36 }
37
38 pub fn add_row(mut self, row: Vec<String>) -> Self {
40 self.table.add_row(row);
41 self
42 }
43
44 pub fn build(self) -> String {
46 self.table.to_string()
47 }
48}
49
50pub fn create_benchmark_table(
52 language: &str,
53 file_path: Option<&str>,
54 symbols: usize,
55 avg_time: std::time::Duration,
56 rate: f64,
57) -> String {
58 let mut table = Table::new();
59 table.load_preset(UTF8_FULL);
60 table.apply_modifier(UTF8_ROUND_CORNERS);
62
63 table.set_header(vec![
65 Cell::new("Metric").add_attribute(Attribute::Bold),
66 Cell::new("Value").add_attribute(Attribute::Bold),
67 ]);
68
69 table.add_row(vec!["Language", language]);
71
72 if let Some(path) = file_path {
73 table.add_row(vec!["File", path]);
74 } else {
75 table.add_row(vec!["File", "<generated benchmark code>"]);
76 }
77
78 table.add_row(vec!["Symbols parsed", &symbols.to_string()]);
79
80 table.add_row(vec!["Average time", &format!("{avg_time:?}")]);
81
82 table.add_row(vec!["Rate", &format!("{rate:.0} symbols/second")]);
83
84 let performance_ratio = rate / 10_000.0;
86 let (performance_text, color) = if performance_ratio >= 1.0 {
87 (
88 format!("✓ {performance_ratio:.1}x faster than target"),
89 Color::Green,
90 )
91 } else {
92 (
93 format!("⚠ {performance_ratio:.1}x of target"),
94 Color::Yellow,
95 )
96 };
97
98 table.add_row(vec![
99 Cell::new("Performance"),
100 Cell::new(performance_text)
101 .fg(color)
102 .add_attribute(Attribute::Bold),
103 ]);
104
105 table.to_string()
106}
107
108pub fn create_summary_table(
110 results: Vec<(String, usize, usize, std::time::Duration)>, ) -> String {
112 let mut table = Table::new();
113 table.load_preset(UTF8_FULL);
114 table.apply_modifier(UTF8_ROUND_CORNERS);
116
117 table.set_header(vec![
119 Cell::new("Language").add_attribute(Attribute::Bold),
120 Cell::new("Files").add_attribute(Attribute::Bold),
121 Cell::new("Symbols").add_attribute(Attribute::Bold),
122 Cell::new("Time").add_attribute(Attribute::Bold),
123 Cell::new("Rate").add_attribute(Attribute::Bold),
124 ]);
125
126 let mut total_files = 0;
128 let mut total_symbols = 0;
129 let mut total_time = std::time::Duration::ZERO;
130
131 for (lang, files, symbols, time) in results {
132 total_files += files;
133 total_symbols += symbols;
134 total_time += time;
135
136 let rate = if time.as_secs_f64() > 0.0 {
137 symbols as f64 / time.as_secs_f64()
138 } else {
139 0.0
140 };
141
142 table.add_row(vec![
143 lang,
144 files.to_string(),
145 symbols.to_string(),
146 format!("{:?}", time),
147 format!("{:.0}/s", rate),
148 ]);
149 }
150
151 if total_time.as_secs_f64() > 0.0 {
153 let total_rate = total_symbols as f64 / total_time.as_secs_f64();
154 table.add_row(vec![
155 Cell::new("TOTAL").add_attribute(Attribute::Bold),
156 Cell::new(total_files).add_attribute(Attribute::Bold),
157 Cell::new(total_symbols).add_attribute(Attribute::Bold),
158 Cell::new(format!("{total_time:?}")).add_attribute(Attribute::Bold),
159 Cell::new(format!("{total_rate:.0}/s")).add_attribute(Attribute::Bold),
160 ]);
161 }
162
163 table.to_string()
164}
165
166#[cfg(test)]
167mod tests {
168 use super::*;
169
170 #[test]
171 fn test_table_builder() {
172 let table = TableBuilder::new()
173 .set_headers(vec!["Column 1", "Column 2"])
174 .add_row(vec!["Value 1".to_string(), "Value 2".to_string()])
175 .build();
176
177 assert!(table.contains("Column 1"));
178 assert!(table.contains("Value 1"));
179 }
180}