@@ -18,7 +18,7 @@ use semver::Version;
1818use std:: {
1919 collections:: BTreeMap ,
2020 fmt:: Display ,
21- ops:: { AddAssign , Deref , DerefMut } ,
21+ ops:: { Deref , DerefMut , Range } ,
2222 path:: { Path , PathBuf } ,
2323 sync:: Arc ,
2424} ;
@@ -82,40 +82,29 @@ impl CoverageReport {
8282 self . anchors . extend ( anchors) ;
8383 }
8484
85- /// Get coverage summaries by source file path.
86- pub fn summary_by_file ( & self ) -> impl Iterator < Item = ( PathBuf , CoverageSummary ) > {
87- let mut summaries = BTreeMap :: new ( ) ;
88-
89- for ( version, items) in self . items . iter ( ) {
90- for item in items {
91- let Some ( path) =
92- self . source_paths . get ( & ( version. clone ( ) , item. loc . source_id ) ) . cloned ( )
93- else {
94- continue ;
95- } ;
96- * summaries. entry ( path) . or_default ( ) += item;
97- }
98- }
99-
100- summaries. into_iter ( )
85+ /// Returns an iterator over coverage summaries by source file path.
86+ pub fn summary_by_file ( & self ) -> impl Iterator < Item = ( & Path , CoverageSummary ) > {
87+ self . by_file ( |summary : & mut CoverageSummary , item| summary. add_item ( item) )
10188 }
10289
103- /// Get coverage items by source file path.
104- pub fn items_by_source ( & self ) -> impl Iterator < Item = ( PathBuf , Vec < CoverageItem > ) > {
105- let mut items_by_source: BTreeMap < _ , Vec < _ > > = BTreeMap :: new ( ) ;
90+ /// Returns an iterator over coverage items by source file path.
91+ pub fn items_by_file ( & self ) -> impl Iterator < Item = ( & Path , Vec < & CoverageItem > ) > {
92+ self . by_file ( |list : & mut Vec < _ > , item| list. push ( item) )
93+ }
10694
107- for ( version, items) in self . items . iter ( ) {
95+ fn by_file < ' a , T : Default > (
96+ & ' a self ,
97+ mut f : impl FnMut ( & mut T , & ' a CoverageItem ) ,
98+ ) -> impl Iterator < Item = ( & ' a Path , T ) > {
99+ let mut by_file: BTreeMap < & Path , T > = BTreeMap :: new ( ) ;
100+ for ( version, items) in & self . items {
108101 for item in items {
109- let Some ( path) =
110- self . source_paths . get ( & ( version. clone ( ) , item. loc . source_id ) ) . cloned ( )
111- else {
112- continue ;
113- } ;
114- items_by_source. entry ( path) . or_default ( ) . push ( item. clone ( ) ) ;
102+ let key = ( version. clone ( ) , item. loc . source_id ) ;
103+ let Some ( path) = self . source_paths . get ( & key) else { continue } ;
104+ f ( by_file. entry ( path) . or_default ( ) , item) ;
115105 }
116106 }
117-
118- items_by_source. into_iter ( )
107+ by_file. into_iter ( )
119108 }
120109
121110 /// Processes data from a [`HitMap`] and sets hit counts for coverage items in this coverage
@@ -345,30 +334,34 @@ impl Display for CoverageItem {
345334 }
346335}
347336
337+ /// A source location.
348338#[ derive( Clone , Debug ) ]
349339pub struct SourceLocation {
350340 /// The source ID.
351341 pub source_id : usize ,
352342 /// The contract this source range is in.
353343 pub contract_name : Arc < str > ,
354- /// Start byte in the source code.
355- pub start : u32 ,
356- /// Number of bytes in the source code.
357- pub length : Option < u32 > ,
358- /// The line in the source code.
359- pub line : usize ,
344+ /// Byte range.
345+ pub bytes : Range < u32 > ,
346+ /// Line range. Indices are 1-based.
347+ pub lines : Range < u32 > ,
360348}
361349
362350impl Display for SourceLocation {
363351 fn fmt ( & self , f : & mut std:: fmt:: Formatter < ' _ > ) -> std:: fmt:: Result {
364- write ! (
365- f,
366- "source ID {}, line {}, chars {}-{}" ,
367- self . source_id,
368- self . line,
369- self . start,
370- self . length. map_or( self . start, |length| self . start + length)
371- )
352+ write ! ( f, "source ID {}, lines {:?}, bytes {:?}" , self . source_id, self . lines, self . bytes)
353+ }
354+ }
355+
356+ impl SourceLocation {
357+ /// Returns the length of the byte range.
358+ pub fn len ( & self ) -> u32 {
359+ self . bytes . len ( ) as u32
360+ }
361+
362+ /// Returns true if the byte range is empty.
363+ pub fn is_empty ( & self ) -> bool {
364+ self . len ( ) == 0
372365 }
373366}
374367
@@ -393,21 +386,43 @@ pub struct CoverageSummary {
393386 pub function_hits : usize ,
394387}
395388
396- impl AddAssign < & Self > for CoverageSummary {
397- fn add_assign ( & mut self , other : & Self ) {
398- self . line_count += other. line_count ;
399- self . line_hits += other. line_hits ;
400- self . statement_count += other. statement_count ;
401- self . statement_hits += other. statement_hits ;
402- self . branch_count += other. branch_count ;
403- self . branch_hits += other. branch_hits ;
404- self . function_count += other. function_count ;
405- self . function_hits += other. function_hits ;
389+ impl CoverageSummary {
390+ /// Creates a new, empty coverage summary.
391+ pub fn new ( ) -> Self {
392+ Self :: default ( )
393+ }
394+
395+ /// Creates a coverage summary from a collection of coverage items.
396+ pub fn from_items < ' a > ( items : impl IntoIterator < Item = & ' a CoverageItem > ) -> Self {
397+ let mut summary = Self :: default ( ) ;
398+ summary. add_items ( items) ;
399+ summary
406400 }
407- }
408401
409- impl AddAssign < & CoverageItem > for CoverageSummary {
410- fn add_assign ( & mut self , item : & CoverageItem ) {
402+ /// Adds another coverage summary to this one.
403+ pub fn merge ( & mut self , other : & Self ) {
404+ let Self {
405+ line_count,
406+ line_hits,
407+ statement_count,
408+ statement_hits,
409+ branch_count,
410+ branch_hits,
411+ function_count,
412+ function_hits,
413+ } = self ;
414+ * line_count += other. line_count ;
415+ * line_hits += other. line_hits ;
416+ * statement_count += other. statement_count ;
417+ * statement_hits += other. statement_hits ;
418+ * branch_count += other. branch_count ;
419+ * branch_hits += other. branch_hits ;
420+ * function_count += other. function_count ;
421+ * function_hits += other. function_hits ;
422+ }
423+
424+ /// Adds a coverage item to this summary.
425+ pub fn add_item ( & mut self , item : & CoverageItem ) {
411426 match item. kind {
412427 CoverageItemKind :: Line => {
413428 self . line_count += 1 ;
@@ -435,4 +450,11 @@ impl AddAssign<&CoverageItem> for CoverageSummary {
435450 }
436451 }
437452 }
453+
454+ /// Adds multiple coverage items to this summary.
455+ pub fn add_items < ' a > ( & mut self , items : impl IntoIterator < Item = & ' a CoverageItem > ) {
456+ for item in items {
457+ self . add_item ( item) ;
458+ }
459+ }
438460}
0 commit comments