@@ -16,6 +16,7 @@ use std::rc::Rc;
16
16
use std:: { cmp, fmt, iter, str} ;
17
17
18
18
use serde:: de:: { Deserialize , Deserializer } ;
19
+ use serde:: ser:: { self , Serialize , Serializer } ;
19
20
use serde_json as json;
20
21
21
22
use syntax:: codemap:: { self , FileMap } ;
@@ -53,6 +54,36 @@ impl fmt::Display for FileName {
53
54
}
54
55
}
55
56
57
+ impl < ' de > Deserialize < ' de > for FileName {
58
+ fn deserialize < D > ( deserializer : D ) -> Result < FileName , D :: Error >
59
+ where
60
+ D : Deserializer < ' de > ,
61
+ {
62
+ let s = String :: deserialize ( deserializer) ?;
63
+ if s == "stdin" {
64
+ Ok ( FileName :: Stdin )
65
+ } else {
66
+ Ok ( FileName :: Real ( s. into ( ) ) )
67
+ }
68
+ }
69
+ }
70
+
71
+ impl Serialize for FileName {
72
+ fn serialize < S > ( & self , serializer : S ) -> Result < S :: Ok , S :: Error >
73
+ where
74
+ S : Serializer ,
75
+ {
76
+ let s = match self {
77
+ FileName :: Stdin => Ok ( "stdin" ) ,
78
+ FileName :: Real ( path) => path
79
+ . to_str ( )
80
+ . ok_or_else ( || ser:: Error :: custom ( "path can't be serialized as UTF-8 string" ) ) ,
81
+ } ;
82
+
83
+ s. and_then ( |s| serializer. serialize_str ( s) )
84
+ }
85
+ }
86
+
56
87
impl LineRange {
57
88
pub fn file_name ( & self ) -> FileName {
58
89
self . file . name . clone ( ) . into ( )
@@ -175,6 +206,20 @@ impl FileLines {
175
206
Files ( self . 0 . as_ref ( ) . map ( |m| m. keys ( ) ) )
176
207
}
177
208
209
+ /// Returns JSON representation as accepted by the `--file-lines JSON` arg.
210
+ pub fn to_json_spans ( & self ) -> Vec < JsonSpan > {
211
+ match & self . 0 {
212
+ None => vec ! [ ] ,
213
+ Some ( file_ranges) => file_ranges
214
+ . iter ( )
215
+ . flat_map ( |( file, ranges) | ranges. iter ( ) . map ( move |r| ( file, r) ) )
216
+ . map ( |( file, range) | JsonSpan {
217
+ file : file. to_owned ( ) ,
218
+ range : ( range. lo , range. hi ) ,
219
+ } ) . collect ( ) ,
220
+ }
221
+ }
222
+
178
223
/// Returns true if `self` includes all lines in all files. Otherwise runs `f` on all ranges in
179
224
/// the designated file (if any) and returns true if `f` ever does.
180
225
fn file_range_matches < F > ( & self , file_name : & FileName , f : F ) -> bool
@@ -249,22 +294,12 @@ impl str::FromStr for FileLines {
249
294
}
250
295
251
296
// For JSON decoding.
252
- #[ derive( Clone , Debug , Deserialize ) ]
253
- struct JsonSpan {
254
- #[ serde( deserialize_with = "deserialize_filename" ) ]
297
+ #[ derive( Clone , PartialEq , Eq , PartialOrd , Ord , Debug , Deserialize , Serialize ) ]
298
+ pub struct JsonSpan {
255
299
file : FileName ,
256
300
range : ( usize , usize ) ,
257
301
}
258
302
259
- fn deserialize_filename < ' de , D : Deserializer < ' de > > ( d : D ) -> Result < FileName , D :: Error > {
260
- let s = String :: deserialize ( d) ?;
261
- if s == "stdin" {
262
- Ok ( FileName :: Stdin )
263
- } else {
264
- Ok ( FileName :: Real ( s. into ( ) ) )
265
- }
266
- }
267
-
268
303
impl JsonSpan {
269
304
fn into_tuple ( self ) -> Result < ( FileName , Range ) , String > {
270
305
let ( lo, hi) = self . range ;
@@ -350,4 +385,38 @@ mod test {
350
385
Range :: new( 3 , 7 ) . merge( Range :: new( 4 , 5 ) )
351
386
) ;
352
387
}
388
+
389
+ use super :: json:: { self , json, json_internal} ;
390
+ use super :: { FileLines , FileName } ;
391
+ use std:: { collections:: HashMap , path:: PathBuf } ;
392
+
393
+ #[ test]
394
+ fn file_lines_to_json ( ) {
395
+ let ranges: HashMap < FileName , Vec < Range > > = [
396
+ (
397
+ FileName :: Real ( PathBuf :: from ( "src/main.rs" ) ) ,
398
+ vec ! [ Range :: new( 1 , 3 ) , Range :: new( 5 , 7 ) ] ,
399
+ ) ,
400
+ (
401
+ FileName :: Real ( PathBuf :: from ( "src/lib.rs" ) ) ,
402
+ vec ! [ Range :: new( 1 , 7 ) ] ,
403
+ ) ,
404
+ ]
405
+ . iter ( )
406
+ . cloned ( )
407
+ . collect ( ) ;
408
+
409
+ let file_lines = FileLines :: from_ranges ( ranges) ;
410
+ let mut spans = file_lines. to_json_spans ( ) ;
411
+ spans. sort ( ) ;
412
+ let json = json:: to_value ( & spans) . unwrap ( ) ;
413
+ assert_eq ! (
414
+ json,
415
+ json! { [
416
+ { "file" : "src/lib.rs" , "range" : [ 1 , 7 ] } ,
417
+ { "file" : "src/main.rs" , "range" : [ 1 , 3 ] } ,
418
+ { "file" : "src/main.rs" , "range" : [ 5 , 7 ] } ,
419
+ ] }
420
+ ) ;
421
+ }
353
422
}
0 commit comments