@@ -37,10 +37,84 @@ use std::{collections::HashMap, fmt, mem, sync::OnceLock};
37
37
use memchr:: { memchr, memmem} ;
38
38
use serde:: { de, de:: IgnoredAny , Deserialize } ;
39
39
40
- use crate :: report:: pyreport:: { CHUNKS_FILE_END_OF_CHUNK , CHUNKS_FILE_HEADER_TERMINATOR } ;
40
+ use super :: report_json:: ParsedReportJson ;
41
+ use crate :: {
42
+ error:: CodecovError ,
43
+ report:: {
44
+ models,
45
+ pyreport:: {
46
+ types:: { self , PyreportCoverage , ReportLine } ,
47
+ CHUNKS_FILE_END_OF_CHUNK , CHUNKS_FILE_HEADER_TERMINATOR ,
48
+ } ,
49
+ Report , ReportBuilder ,
50
+ } ,
51
+ } ;
52
+
53
+ pub fn parse_chunks_file < B , R > (
54
+ input : & [ u8 ] ,
55
+ _report_json : & ParsedReportJson ,
56
+ builder : & mut B ,
57
+ ) -> Result < ( ) , CodecovError >
58
+ where
59
+ B : ReportBuilder < R > ,
60
+ R : Report ,
61
+ {
62
+ let chunks_file = ChunksFile :: new ( input) ?;
63
+
64
+ let mut labels_index = HashMap :: with_capacity ( chunks_file. labels_index ( ) . len ( ) ) ;
65
+ for ( index, name) in chunks_file. labels_index ( ) {
66
+ let context = builder. insert_context ( name) ?;
67
+ labels_index. insert ( index. clone ( ) , context. id ) ;
68
+ }
69
+
70
+ let mut report_lines = vec ! [ ] ;
71
+
72
+ let mut chunks = chunks_file. chunks ( ) ;
73
+ while let Some ( mut chunk) = chunks. next_chunk ( ) ? {
74
+ let mut line_no = 0 ;
75
+ report_lines. clear ( ) ;
76
+ while let Some ( line) = chunk. next_line ( ) ? {
77
+ line_no += 1 ;
78
+ if let Some ( line) = line {
79
+ let coverage_type = match line. 1 . unwrap_or_default ( ) {
80
+ CoverageType :: Line => models:: CoverageType :: Line ,
81
+ CoverageType :: Branch => models:: CoverageType :: Branch ,
82
+ CoverageType :: Method => models:: CoverageType :: Method ,
83
+ } ;
84
+ let sessions = line
85
+ . 2
86
+ . into_iter ( )
87
+ . map ( |session| types:: LineSession {
88
+ session_id : session. 0 ,
89
+ coverage : session. 1 . into ( ) ,
90
+ branches : None , // TODO
91
+ partials : None , // TODO
92
+ complexity : None , // TODO
93
+ } )
94
+ . collect ( ) ;
95
+
96
+ let mut report_line = ReportLine {
97
+ line_no,
98
+ coverage : line. 0 . into ( ) ,
99
+ coverage_type,
100
+ sessions,
101
+ _messages : None ,
102
+ _complexity : None ,
103
+ datapoints : None , // TODO
104
+ } ;
105
+ report_line. normalize ( ) ;
106
+ report_lines. push ( report_line) ;
107
+ }
108
+ }
109
+ // TODO:
110
+ // utils::save_report_lines()?;
111
+ }
112
+
113
+ Ok ( ( ) )
114
+ }
41
115
42
116
#[ derive( Debug , thiserror:: Error ) ]
43
- pub enum ParserError {
117
+ pub enum ChunksFileParseError {
44
118
#[ error( "unexpected EOF" ) ]
45
119
UnexpectedEof ,
46
120
#[ error( "unexpected input" ) ]
@@ -53,12 +127,12 @@ pub enum ParserError {
53
127
InvalidLineRecord ( #[ source] serde_json:: Error ) ,
54
128
}
55
129
56
- impl PartialEq for ParserError {
130
+ impl PartialEq for ChunksFileParseError {
57
131
fn eq ( & self , other : & Self ) -> bool {
58
132
core:: mem:: discriminant ( self ) == core:: mem:: discriminant ( other)
59
133
}
60
134
}
61
- impl Eq for ParserError { }
135
+ impl Eq for ChunksFileParseError { }
62
136
63
137
#[ derive( Debug ) ]
64
138
pub struct ChunksFile < ' d > {
@@ -67,16 +141,16 @@ pub struct ChunksFile<'d> {
67
141
}
68
142
69
143
impl < ' d > ChunksFile < ' d > {
70
- pub fn new ( mut input : & ' d [ u8 ] ) -> Result < Self , ParserError > {
144
+ pub fn new ( mut input : & ' d [ u8 ] ) -> Result < Self , ChunksFileParseError > {
71
145
static HEADER_FINDER : OnceLock < memmem:: Finder > = OnceLock :: new ( ) ;
72
146
let header_finder =
73
147
HEADER_FINDER . get_or_init ( || memmem:: Finder :: new ( CHUNKS_FILE_HEADER_TERMINATOR ) ) ;
74
148
75
149
let file_header = if let Some ( pos) = header_finder. find ( input) {
76
150
let header_bytes = & input[ ..pos] ;
77
151
input = & input[ pos + header_finder. needle ( ) . len ( ) ..] ;
78
- let file_header: FileHeader =
79
- serde_json :: from_slice ( header_bytes ) . map_err ( ParserError :: InvalidFileHeader ) ?;
152
+ let file_header: FileHeader = serde_json :: from_slice ( header_bytes )
153
+ . map_err ( ChunksFileParseError :: InvalidFileHeader ) ?;
80
154
file_header
81
155
} else {
82
156
FileHeader :: default ( )
@@ -99,7 +173,7 @@ pub struct Chunks<'d> {
99
173
}
100
174
101
175
impl < ' d > Chunks < ' d > {
102
- pub fn next_chunk ( & mut self ) -> Result < Option < Chunk < ' d > > , ParserError > {
176
+ pub fn next_chunk ( & mut self ) -> Result < Option < Chunk < ' d > > , ChunksFileParseError > {
103
177
if self . input . is_empty ( ) {
104
178
return Ok ( None ) ;
105
179
}
@@ -123,9 +197,10 @@ impl<'d> Chunks<'d> {
123
197
} ) ) ;
124
198
}
125
199
126
- let header_bytes = next_line ( & mut chunk_bytes) . ok_or ( ParserError :: UnexpectedInput ) ?;
127
- let chunk_header: ChunkHeader =
128
- serde_json:: from_slice ( header_bytes) . map_err ( ParserError :: InvalidFileHeader ) ?;
200
+ let header_bytes =
201
+ next_line ( & mut chunk_bytes) . ok_or ( ChunksFileParseError :: UnexpectedInput ) ?;
202
+ let chunk_header: ChunkHeader = serde_json:: from_slice ( header_bytes)
203
+ . map_err ( ChunksFileParseError :: InvalidFileHeader ) ?;
129
204
130
205
Ok ( Some ( Chunk {
131
206
chunk_header,
@@ -144,7 +219,7 @@ impl<'d> Chunk<'d> {
144
219
& self . chunk_header . present_sessions
145
220
}
146
221
147
- pub fn next_line ( & mut self ) -> Result < Option < Option < LineRecord > > , ParserError > {
222
+ pub fn next_line ( & mut self ) -> Result < Option < Option < LineRecord > > , ChunksFileParseError > {
148
223
let Some ( line) = next_line ( & mut self . input ) else {
149
224
return Ok ( None ) ;
150
225
} ;
@@ -154,7 +229,7 @@ impl<'d> Chunk<'d> {
154
229
}
155
230
156
231
let line_record: LineRecord =
157
- serde_json:: from_slice ( line) . map_err ( ParserError :: InvalidLineRecord ) ?;
232
+ serde_json:: from_slice ( line) . map_err ( ChunksFileParseError :: InvalidLineRecord ) ?;
158
233
return Ok ( Some ( Some ( line_record) ) ) ;
159
234
}
160
235
}
@@ -217,7 +292,7 @@ pub struct LineRecord(
217
292
#[ derive( Debug , Clone , PartialEq , Eq , Deserialize ) ]
218
293
pub struct LineSession (
219
294
/// session id
220
- u32 ,
295
+ usize ,
221
296
/// coverage
222
297
Coverage ,
223
298
/// TODO: branches
@@ -260,6 +335,18 @@ pub enum Coverage {
260
335
HitCount ( u32 ) ,
261
336
}
262
337
338
+ impl Into < PyreportCoverage > for Coverage {
339
+ fn into ( self ) -> PyreportCoverage {
340
+ match self {
341
+ Coverage :: Partial => PyreportCoverage :: Partial ( ) ,
342
+ Coverage :: BranchTaken ( covered, total) => {
343
+ PyreportCoverage :: BranchesTaken { covered, total }
344
+ }
345
+ Coverage :: HitCount ( hits) => PyreportCoverage :: HitCount ( hits) ,
346
+ }
347
+ }
348
+ }
349
+
263
350
impl < ' de > Deserialize < ' de > for Coverage {
264
351
fn deserialize < D > ( deserializer : D ) -> Result < Coverage , D :: Error >
265
352
where
0 commit comments