1#[derive(Debug, Clone)]
5pub struct EmbedStats {
6 pub templates: CategoryStats,
8 pub packages: PackageStats,
10 pub fonts: CategoryStats,
12}
13
14#[derive(Debug, Clone)]
16pub struct CategoryStats {
17 pub original_size: usize,
19 pub compressed_size: usize,
21 pub file_count: usize,
23}
24
25#[derive(Debug, Clone)]
27pub struct PackageStats {
28 pub packages: Vec<PackageInfo>,
30 pub total_original: usize,
32 pub total_compressed: usize,
34}
35
36#[derive(Debug, Clone)]
38pub struct PackageInfo {
39 pub name: String,
41 pub original_size: usize,
43 pub compressed_size: usize,
45 pub file_count: usize,
47}
48
49impl EmbedStats {
50 pub fn total_original(&self) -> usize {
52 self.templates.original_size + self.packages.total_original + self.fonts.original_size
53 }
54
55 pub fn total_compressed(&self) -> usize {
57 self.templates.compressed_size + self.packages.total_compressed + self.fonts.compressed_size
58 }
59
60 pub fn compression_ratio(&self) -> f64 {
62 let original = self.total_original();
63 if original == 0 {
64 return 0.0;
65 }
66 1.0 - (self.total_compressed() as f64 / original as f64)
67 }
68
69 pub fn display(&self) {
71 println!("Compression Statistics:");
72 println!("========================");
73
74 if self.templates.file_count > 0 {
76 println!(
77 "Templates: {:>9} -> {:>9} ({:>5.1}% reduced, {} files)",
78 format_size(self.templates.original_size),
79 format_size(self.templates.compressed_size),
80 self.templates.compression_ratio() * 100.0,
81 self.templates.file_count
82 );
83 }
84
85 if self.fonts.file_count > 0 {
87 println!(
88 "Fonts: {:>9} -> {:>9} ({:>5.1}% reduced, {} files)",
89 format_size(self.fonts.original_size),
90 format_size(self.fonts.compressed_size),
91 self.fonts.compression_ratio() * 100.0,
92 self.fonts.file_count
93 );
94 }
95
96 if !self.packages.packages.is_empty() {
98 println!("Packages:");
99
100 let name_width = self
102 .packages
103 .packages
104 .iter()
105 .map(|p| p.name.len())
106 .max()
107 .unwrap_or(0);
108 let orig_width = self
109 .packages
110 .packages
111 .iter()
112 .map(|p| format_size(p.original_size).len())
113 .max()
114 .unwrap_or(0);
115 let comp_width = self
116 .packages
117 .packages
118 .iter()
119 .map(|p| format_size(p.compressed_size).len())
120 .max()
121 .unwrap_or(0);
122
123 for pkg in &self.packages.packages {
124 println!(
125 " {:<name_w$} {:>orig_w$} -> {:>comp_w$} ({:>5.1}%)",
126 pkg.name,
127 format_size(pkg.original_size),
128 format_size(pkg.compressed_size),
129 pkg.compression_ratio() * 100.0,
130 name_w = name_width,
131 orig_w = orig_width,
132 comp_w = comp_width,
133 );
134 }
135 }
136
137 println!("------------------------");
139 println!(
140 "Total: {} -> {} ({:.1}% reduced)",
141 format_size(self.total_original()),
142 format_size(self.total_compressed()),
143 self.compression_ratio() * 100.0
144 );
145 }
146}
147
148impl CategoryStats {
149 pub fn compression_ratio(&self) -> f64 {
151 if self.original_size == 0 {
152 return 0.0;
153 }
154 1.0 - (self.compressed_size as f64 / self.original_size as f64)
155 }
156}
157
158impl PackageInfo {
159 pub fn compression_ratio(&self) -> f64 {
161 if self.original_size == 0 {
162 return 0.0;
163 }
164 1.0 - (self.compressed_size as f64 / self.original_size as f64)
165 }
166}
167
168impl PackageStats {
169 pub fn compression_ratio(&self) -> f64 {
171 if self.total_original == 0 {
172 return 0.0;
173 }
174 1.0 - (self.total_compressed as f64 / self.total_original as f64)
175 }
176}
177
178fn format_size(bytes: usize) -> String {
180 const KB: usize = 1024;
181 const MB: usize = KB * 1024;
182
183 if bytes >= MB {
184 format!("{:.2} MB", bytes as f64 / MB as f64)
185 } else if bytes >= KB {
186 format!("{:.1} KB", bytes as f64 / KB as f64)
187 } else {
188 format!("{} B", bytes)
189 }
190}