@@ -126,35 +126,120 @@ struct Top {
126
126
impl traits:: Emit for Top {
127
127
#[ cfg( feature = "emit_text" ) ]
128
128
fn emit_text ( & self , items : & ir:: Items , dest : & mut io:: Write ) -> Result < ( ) , traits:: Error > {
129
- let sort_label = if self . opts . retained ( ) {
130
- "Retained"
131
- } else {
132
- "Shallow"
129
+ // A struct used to represent a row in the table that will be emitted.
130
+ struct TableRow {
131
+ size : u32 ,
132
+ size_percent : f64 ,
133
+ name : String ,
134
+ } ;
135
+
136
+ // Helper function used to process an item, and return a struct
137
+ // representing a row containing its size and name.
138
+ fn process_item ( id : ir:: Id , items : & ir:: Items , retained : bool ) -> TableRow {
139
+ let item = & items[ id] ;
140
+ let size = if retained {
141
+ items. retained_size ( id)
142
+ } else {
143
+ item. size ( )
144
+ } ;
145
+ let size_percent = ( f64:: from ( size) ) / ( f64:: from ( items. size ( ) ) ) * 100.0 ;
146
+ let name = item. name ( ) . to_string ( ) ;
147
+ TableRow {
148
+ size,
149
+ size_percent,
150
+ name,
151
+ }
133
152
} ;
134
153
154
+ // Helper function used to summnarize a sequence of table rows. This is
155
+ // used to generate the remaining summary and total rows. Returns a tuple
156
+ // containing the total size, total size percentage, and number of items.
157
+ fn summarize_rows ( rows : impl Iterator < Item = TableRow > ) -> ( u32 , f64 , u32 ) {
158
+ rows. fold (
159
+ ( 0 , 0.0 , 0 ) ,
160
+ |( total_size, total_percent, remaining_count) ,
161
+ TableRow {
162
+ size,
163
+ size_percent,
164
+ name : _,
165
+ } | {
166
+ (
167
+ total_size + size,
168
+ total_percent + size_percent,
169
+ remaining_count + 1 ,
170
+ )
171
+ } ,
172
+ )
173
+ }
174
+
175
+ // Access the options that are relevant to emitting the correct output.
176
+ let max_items = self . opts . max_items ( ) as usize ;
177
+ let retained = self . opts . retained ( ) ;
178
+ let sort_label = if retained { "Retained" } else { "Shallow" } ;
179
+
180
+ // Initialize a new table.
135
181
let mut table = Table :: with_header ( vec ! [
136
182
( Align :: Right , format!( "{} Bytes" , sort_label) ) ,
137
183
( Align :: Right , format!( "{} %" , sort_label) ) ,
138
184
( Align :: Left , "Item" . to_string( ) ) ,
139
185
] ) ;
140
186
141
- for & id in & self . items {
142
- let item = & items[ id] ;
187
+ // Process the number of items specified, and add them to the table.
188
+ self . items
189
+ . iter ( )
190
+ . take ( max_items)
191
+ . map ( |& id| process_item ( id, items, retained) )
192
+ . for_each (
193
+ |TableRow {
194
+ size,
195
+ size_percent,
196
+ name,
197
+ } | {
198
+ table. add_row ( vec ! [
199
+ size. to_string( ) ,
200
+ format!( "{:.2}%" , size_percent) ,
201
+ name,
202
+ ] )
203
+ } ,
204
+ ) ;
143
205
144
- let size = if self . opts . retained ( ) {
145
- items. retained_size ( id)
206
+ // Find the summary statistics by processing the remaining items.
207
+ let remaining_rows = self
208
+ . items
209
+ . iter ( )
210
+ . skip ( max_items)
211
+ . map ( |& id| process_item ( id, items, retained) ) ;
212
+ let ( rem_size, rem_size_percent, rem_count) = summarize_rows ( remaining_rows) ;
213
+
214
+ // If there were items remaining, add a summary row to the table.
215
+ if rem_count > 0 {
216
+ let rem_name_col = format ! ( "... and {} more." , rem_count) ;
217
+ let ( rem_size_col, rem_size_percent_col) = if retained {
218
+ ( "..." . to_string ( ) , "..." . to_string ( ) )
146
219
} else {
147
- item . size ( )
220
+ ( rem_size . to_string ( ) , format ! ( "{:.2}%" , rem_size_percent ) )
148
221
} ;
149
-
150
- let size_percent = ( f64:: from ( size) ) / ( f64:: from ( items. size ( ) ) ) * 100.0 ;
151
- table. add_row ( vec ! [
152
- size. to_string( ) ,
153
- format!( "{:.2}%" , size_percent) ,
154
- item. name( ) . to_string( ) ,
155
- ] ) ;
222
+ table. add_row ( vec ! [ rem_size_col, rem_size_percent_col, rem_name_col] ) ;
156
223
}
157
224
225
+ // Add a row containing the totals to the table.
226
+ let all_rows = self
227
+ . items
228
+ . iter ( )
229
+ . map ( |& id| process_item ( id, items, retained) ) ;
230
+ let ( total_size, total_size_percent, total_count) = summarize_rows ( all_rows) ;
231
+ let total_name_col = format ! ( "Ξ£ [{} Total Rows]" , total_count) ;
232
+ let ( total_size_col, total_size_percent_col) = if retained {
233
+ ( "..." . to_string ( ) , "..." . to_string ( ) )
234
+ } else {
235
+ (
236
+ total_size. to_string ( ) ,
237
+ format ! ( "{:.2}%" , total_size_percent) ,
238
+ )
239
+ } ;
240
+ table. add_row ( vec ! [ total_size_col, total_size_percent_col, total_name_col] ) ;
241
+
242
+ // Write the generated table out to the destination and return.
158
243
write ! ( dest, "{}" , & table) ?;
159
244
Ok ( ( ) )
160
245
}
@@ -163,7 +248,10 @@ impl traits::Emit for Top {
163
248
fn emit_json ( & self , items : & ir:: Items , dest : & mut io:: Write ) -> Result < ( ) , traits:: Error > {
164
249
let mut arr = json:: array ( dest) ?;
165
250
166
- for & id in & self . items {
251
+ let max_items = self . opts . max_items ( ) as usize ;
252
+ let items_iter = self . items . iter ( ) ;
253
+
254
+ for & id in items_iter. take ( max_items) {
167
255
let item = & items[ id] ;
168
256
169
257
let mut obj = arr. object ( ) ?;
@@ -199,7 +287,10 @@ impl traits::Emit for Top {
199
287
retained_size_percent : Option < f64 > ,
200
288
}
201
289
202
- for & id in & self . items {
290
+ let max_items = self . opts . max_items ( ) as usize ;
291
+ let items_iter = self . items . iter ( ) ;
292
+
293
+ for & id in items_iter. take ( max_items) {
203
294
let item = & items[ id] ;
204
295
205
296
let ( shallow_size, shallow_size_percent) = {
@@ -252,8 +343,6 @@ pub fn top(items: &mut ir::Items, opts: &opt::Top) -> Result<Box<traits::Emit>,
252
343
. cmp ( & items. retained_size ( a. id ( ) ) ) ,
253
344
} ) ;
254
345
255
- top_items. truncate ( opts. number ( ) as usize ) ;
256
-
257
346
let top_items: Vec < _ > = top_items. into_iter ( ) . map ( |i| i. id ( ) ) . collect ( ) ;
258
347
259
348
let top = Top {
0 commit comments