From 4604f46ce8fa5b80b2e47f845c8ed669e8e714ba Mon Sep 17 00:00:00 2001 From: Igor Matuszewski Date: Tue, 14 Aug 2018 13:33:58 +0200 Subject: [PATCH 1/3] Expose FileLines JSON representation --- src/config/file_lines.rs | 82 ++++++++++++++++++++++++++++++++++------ 1 file changed, 70 insertions(+), 12 deletions(-) diff --git a/src/config/file_lines.rs b/src/config/file_lines.rs index 436c7a83b81..962a4bb9a41 100644 --- a/src/config/file_lines.rs +++ b/src/config/file_lines.rs @@ -15,6 +15,7 @@ use std::path::PathBuf; use std::rc::Rc; use std::{cmp, fmt, iter, str}; +use serde::ser::{self, Serialize, Serializer}; use serde::de::{Deserialize, Deserializer}; use serde_json as json; @@ -53,6 +54,35 @@ impl fmt::Display for FileName { } } +impl<'de> Deserialize<'de> for FileName { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + let s = String::deserialize(deserializer)?; + if s == "stdin" { + Ok(FileName::Stdin) + } else { + Ok(FileName::Real(s.into())) + } + } +} + +impl Serialize for FileName { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + let s = match self { + FileName::Stdin => Ok("stdin"), + FileName::Real(path) => path.to_str().ok_or_else(|| + ser::Error::custom("path can't be serialized as UTF-8 string")) + }; + + s.and_then(|s| serializer.serialize_str(s)) + } +} + impl LineRange { pub fn file_name(&self) -> FileName { self.file.name.clone().into() @@ -175,6 +205,20 @@ impl FileLines { Files(self.0.as_ref().map(|m| m.keys())) } + /// Returns JSON representation as accepted by the `--file-lines JSON` arg. + pub fn to_json_spans(&self) -> Vec { + match &self.0 { + None => vec![], + Some(file_ranges) => file_ranges + .iter() + .flat_map(|(file, ranges)| ranges.iter().map(move |r| (file, r))) + .map(|(file, range)| JsonSpan { + file: file.to_owned(), + range: (range.lo, range.hi), + }).collect(), + } + } + /// Returns true if `self` includes all lines in all files. Otherwise runs `f` on all ranges in /// the designated file (if any) and returns true if `f` ever does. fn file_range_matches(&self, file_name: &FileName, f: F) -> bool @@ -249,22 +293,12 @@ impl str::FromStr for FileLines { } // For JSON decoding. -#[derive(Clone, Debug, Deserialize)] -struct JsonSpan { - #[serde(deserialize_with = "deserialize_filename")] +#[derive(Clone, Debug, Deserialize, Serialize)] +pub struct JsonSpan { file: FileName, range: (usize, usize), } -fn deserialize_filename<'de, D: Deserializer<'de>>(d: D) -> Result { - let s = String::deserialize(d)?; - if s == "stdin" { - Ok(FileName::Stdin) - } else { - Ok(FileName::Real(s.into())) - } -} - impl JsonSpan { fn into_tuple(self) -> Result<(FileName, Range), String> { let (lo, hi) = self.range; @@ -350,4 +384,28 @@ mod test { Range::new(3, 7).merge(Range::new(4, 5)) ); } + + use std::{collections::HashMap, path::PathBuf}; + use super::{FileName, FileLines}; + use super::json::{self, json, json_internal}; + + #[test] + fn file_lines_to_json() { + let ranges: HashMap> = [ + (FileName::Real(PathBuf::from("src/main.rs")), vec![ + Range::new(1, 3), + Range::new(5, 7) + ]), + (FileName::Real(PathBuf::from("src/lib.rs")), vec![ + Range::new(1, 7) + ])].iter().cloned().collect(); + + let file_lines = FileLines::from_ranges(ranges); + let json = json::to_value(&file_lines.to_json_spans()).unwrap(); + assert_eq!(json, json! {[ + {"file": "src/main.rs", "range": [1, 3]}, + {"file": "src/main.rs", "range": [5, 7]}, + {"file": "src/lib.rs", "range": [1, 7]}, + ]}); + } } From 38361c05bc48f0634501a8ad5bfb973388a777a2 Mon Sep 17 00:00:00 2001 From: Igor Matuszewski Date: Tue, 14 Aug 2018 23:22:09 +0200 Subject: [PATCH 2/3] Make file_lines_to_json test deterministic --- src/config/file_lines.rs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/config/file_lines.rs b/src/config/file_lines.rs index 962a4bb9a41..bc0974e11f4 100644 --- a/src/config/file_lines.rs +++ b/src/config/file_lines.rs @@ -293,7 +293,7 @@ impl str::FromStr for FileLines { } // For JSON decoding. -#[derive(Clone, Debug, Deserialize, Serialize)] +#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Deserialize, Serialize)] pub struct JsonSpan { file: FileName, range: (usize, usize), @@ -401,11 +401,13 @@ mod test { ])].iter().cloned().collect(); let file_lines = FileLines::from_ranges(ranges); - let json = json::to_value(&file_lines.to_json_spans()).unwrap(); + let mut spans = file_lines.to_json_spans(); + spans.sort(); + let json = json::to_value(&spans).unwrap(); assert_eq!(json, json! {[ + {"file": "src/lib.rs", "range": [1, 7]}, {"file": "src/main.rs", "range": [1, 3]}, {"file": "src/main.rs", "range": [5, 7]}, - {"file": "src/lib.rs", "range": [1, 7]}, ]}); } } From 9d52940dbeb2a099675f2d66c2a8cc173ea00059 Mon Sep 17 00:00:00 2001 From: Igor Matuszewski Date: Tue, 14 Aug 2018 23:23:00 +0200 Subject: [PATCH 3/3] Run `cargo fmt` --- src/config/file_lines.rs | 43 ++++++++++++++++++++++++---------------- 1 file changed, 26 insertions(+), 17 deletions(-) diff --git a/src/config/file_lines.rs b/src/config/file_lines.rs index bc0974e11f4..58f65b3c1b6 100644 --- a/src/config/file_lines.rs +++ b/src/config/file_lines.rs @@ -15,8 +15,8 @@ use std::path::PathBuf; use std::rc::Rc; use std::{cmp, fmt, iter, str}; -use serde::ser::{self, Serialize, Serializer}; use serde::de::{Deserialize, Deserializer}; +use serde::ser::{self, Serialize, Serializer}; use serde_json as json; use syntax::codemap::{self, FileMap}; @@ -75,8 +75,9 @@ impl Serialize for FileName { { let s = match self { FileName::Stdin => Ok("stdin"), - FileName::Real(path) => path.to_str().ok_or_else(|| - ser::Error::custom("path can't be serialized as UTF-8 string")) + FileName::Real(path) => path + .to_str() + .ok_or_else(|| ser::Error::custom("path can't be serialized as UTF-8 string")), }; s.and_then(|s| serializer.serialize_str(s)) @@ -385,29 +386,37 @@ mod test { ); } - use std::{collections::HashMap, path::PathBuf}; - use super::{FileName, FileLines}; use super::json::{self, json, json_internal}; + use super::{FileLines, FileName}; + use std::{collections::HashMap, path::PathBuf}; #[test] fn file_lines_to_json() { let ranges: HashMap> = [ - (FileName::Real(PathBuf::from("src/main.rs")), vec![ - Range::new(1, 3), - Range::new(5, 7) - ]), - (FileName::Real(PathBuf::from("src/lib.rs")), vec![ - Range::new(1, 7) - ])].iter().cloned().collect(); + ( + FileName::Real(PathBuf::from("src/main.rs")), + vec![Range::new(1, 3), Range::new(5, 7)], + ), + ( + FileName::Real(PathBuf::from("src/lib.rs")), + vec![Range::new(1, 7)], + ), + ] + .iter() + .cloned() + .collect(); let file_lines = FileLines::from_ranges(ranges); let mut spans = file_lines.to_json_spans(); spans.sort(); let json = json::to_value(&spans).unwrap(); - assert_eq!(json, json! {[ - {"file": "src/lib.rs", "range": [1, 7]}, - {"file": "src/main.rs", "range": [1, 3]}, - {"file": "src/main.rs", "range": [5, 7]}, - ]}); + assert_eq!( + json, + json! {[ + {"file": "src/lib.rs", "range": [1, 7]}, + {"file": "src/main.rs", "range": [1, 3]}, + {"file": "src/main.rs", "range": [5, 7]}, + ]} + ); } }