diff options
Diffstat (limited to 'crates/ra_project_model/src/project_json.rs')
-rw-r--r-- | crates/ra_project_model/src/project_json.rs | 140 |
1 files changed, 81 insertions, 59 deletions
diff --git a/crates/ra_project_model/src/project_json.rs b/crates/ra_project_model/src/project_json.rs index e663bb4d7..4b5dcd634 100644 --- a/crates/ra_project_model/src/project_json.rs +++ b/crates/ra_project_model/src/project_json.rs | |||
@@ -2,11 +2,15 @@ | |||
2 | 2 | ||
3 | use std::path::PathBuf; | 3 | use std::path::PathBuf; |
4 | 4 | ||
5 | use paths::{AbsPath, AbsPathBuf}; | ||
6 | use ra_cfg::CfgOptions; | ||
7 | use ra_db::{CrateId, Dependency, Edition}; | ||
5 | use rustc_hash::FxHashSet; | 8 | use rustc_hash::FxHashSet; |
6 | use serde::Deserialize; | 9 | use serde::Deserialize; |
10 | use stdx::split_delim; | ||
7 | 11 | ||
8 | /// Roots and crates that compose this Rust project. | 12 | /// Roots and crates that compose this Rust project. |
9 | #[derive(Clone, Debug, Deserialize)] | 13 | #[derive(Clone, Debug)] |
10 | pub struct ProjectJson { | 14 | pub struct ProjectJson { |
11 | pub(crate) roots: Vec<Root>, | 15 | pub(crate) roots: Vec<Root>, |
12 | pub(crate) crates: Vec<Crate>, | 16 | pub(crate) crates: Vec<Crate>, |
@@ -14,82 +18,100 @@ pub struct ProjectJson { | |||
14 | 18 | ||
15 | /// A root points to the directory which contains Rust crates. rust-analyzer watches all files in | 19 | /// A root points to the directory which contains Rust crates. rust-analyzer watches all files in |
16 | /// all roots. Roots might be nested. | 20 | /// all roots. Roots might be nested. |
17 | #[derive(Clone, Debug, Deserialize)] | 21 | #[derive(Clone, Debug)] |
18 | #[serde(transparent)] | ||
19 | pub struct Root { | 22 | pub struct Root { |
20 | pub(crate) path: PathBuf, | 23 | pub(crate) path: AbsPathBuf, |
21 | } | 24 | } |
22 | 25 | ||
23 | /// A crate points to the root module of a crate and lists the dependencies of the crate. This is | 26 | /// A crate points to the root module of a crate and lists the dependencies of the crate. This is |
24 | /// useful in creating the crate graph. | 27 | /// useful in creating the crate graph. |
25 | #[derive(Clone, Debug, Deserialize)] | 28 | #[derive(Clone, Debug)] |
26 | pub struct Crate { | 29 | pub struct Crate { |
27 | pub(crate) root_module: PathBuf, | 30 | pub(crate) root_module: AbsPathBuf, |
28 | pub(crate) edition: Edition, | 31 | pub(crate) edition: Edition, |
29 | pub(crate) deps: Vec<Dep>, | 32 | pub(crate) deps: Vec<Dependency>, |
33 | pub(crate) cfg: CfgOptions, | ||
34 | pub(crate) out_dir: Option<AbsPathBuf>, | ||
35 | pub(crate) proc_macro_dylib_path: Option<AbsPathBuf>, | ||
36 | } | ||
30 | 37 | ||
31 | #[serde(default)] | 38 | impl ProjectJson { |
32 | pub(crate) cfg: FxHashSet<String>, | 39 | pub fn new(base: &AbsPath, data: ProjectJsonData) -> ProjectJson { |
40 | ProjectJson { | ||
41 | roots: data.roots.into_iter().map(|path| Root { path: base.join(path) }).collect(), | ||
42 | crates: data | ||
43 | .crates | ||
44 | .into_iter() | ||
45 | .map(|crate_data| Crate { | ||
46 | root_module: base.join(crate_data.root_module), | ||
47 | edition: crate_data.edition.into(), | ||
48 | deps: crate_data | ||
49 | .deps | ||
50 | .into_iter() | ||
51 | .map(|dep_data| Dependency { | ||
52 | crate_id: CrateId(dep_data.krate as u32), | ||
53 | name: dep_data.name.into(), | ||
54 | }) | ||
55 | .collect::<Vec<_>>(), | ||
56 | cfg: { | ||
57 | let mut cfg = CfgOptions::default(); | ||
58 | for entry in &crate_data.cfg { | ||
59 | match split_delim(entry, '=') { | ||
60 | Some((key, value)) => { | ||
61 | cfg.insert_key_value(key.into(), value.into()); | ||
62 | } | ||
63 | None => cfg.insert_atom(entry.into()), | ||
64 | } | ||
65 | } | ||
66 | cfg | ||
67 | }, | ||
68 | out_dir: crate_data.out_dir.map(|it| base.join(it)), | ||
69 | proc_macro_dylib_path: crate_data.proc_macro_dylib_path.map(|it| base.join(it)), | ||
70 | }) | ||
71 | .collect::<Vec<_>>(), | ||
72 | } | ||
73 | } | ||
74 | } | ||
33 | 75 | ||
34 | pub(crate) out_dir: Option<PathBuf>, | 76 | #[derive(Deserialize)] |
35 | pub(crate) proc_macro_dylib_path: Option<PathBuf>, | 77 | pub struct ProjectJsonData { |
78 | roots: Vec<PathBuf>, | ||
79 | crates: Vec<CrateData>, | ||
36 | } | 80 | } |
37 | 81 | ||
38 | #[derive(Clone, Copy, Debug, Deserialize)] | 82 | #[derive(Deserialize)] |
83 | struct CrateData { | ||
84 | root_module: PathBuf, | ||
85 | edition: EditionData, | ||
86 | deps: Vec<DepData>, | ||
87 | #[serde(default)] | ||
88 | cfg: FxHashSet<String>, | ||
89 | out_dir: Option<PathBuf>, | ||
90 | proc_macro_dylib_path: Option<PathBuf>, | ||
91 | } | ||
92 | |||
93 | #[derive(Deserialize)] | ||
39 | #[serde(rename = "edition")] | 94 | #[serde(rename = "edition")] |
40 | pub enum Edition { | 95 | enum EditionData { |
41 | #[serde(rename = "2015")] | 96 | #[serde(rename = "2015")] |
42 | Edition2015, | 97 | Edition2015, |
43 | #[serde(rename = "2018")] | 98 | #[serde(rename = "2018")] |
44 | Edition2018, | 99 | Edition2018, |
45 | } | 100 | } |
46 | 101 | ||
47 | /// Identifies a crate by position in the crates array. | 102 | impl From<EditionData> for Edition { |
48 | #[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, Ord, PartialEq, PartialOrd)] | 103 | fn from(data: EditionData) -> Self { |
49 | #[serde(transparent)] | 104 | match data { |
50 | pub struct CrateId(pub usize); | 105 | EditionData::Edition2015 => Edition::Edition2015, |
51 | 106 | EditionData::Edition2018 => Edition::Edition2018, | |
52 | /// A dependency of a crate, identified by its id in the crates array and name. | 107 | } |
53 | #[derive(Clone, Debug, Deserialize)] | 108 | } |
54 | pub struct Dep { | ||
55 | #[serde(rename = "crate")] | ||
56 | pub(crate) krate: CrateId, | ||
57 | pub(crate) name: String, | ||
58 | } | 109 | } |
59 | 110 | ||
60 | #[cfg(test)] | 111 | #[derive(Deserialize)] |
61 | mod tests { | 112 | struct DepData { |
62 | use super::*; | 113 | /// Identifies a crate by position in the crates array. |
63 | use serde_json::json; | 114 | #[serde(rename = "crate")] |
64 | 115 | krate: usize, | |
65 | #[test] | 116 | name: String, |
66 | fn test_crate_deserialization() { | ||
67 | let raw_json = json!( { | ||
68 | "crate_id": 2, | ||
69 | "root_module": "this/is/a/file/path.rs", | ||
70 | "deps": [ | ||
71 | { | ||
72 | "crate": 1, | ||
73 | "name": "some_dep_crate" | ||
74 | }, | ||
75 | ], | ||
76 | "edition": "2015", | ||
77 | "cfg": [ | ||
78 | "atom_1", | ||
79 | "atom_2", | ||
80 | "feature=feature_1", | ||
81 | "feature=feature_2", | ||
82 | "other=value", | ||
83 | ], | ||
84 | |||
85 | }); | ||
86 | |||
87 | let krate: Crate = serde_json::from_value(raw_json).unwrap(); | ||
88 | |||
89 | assert!(krate.cfg.contains(&"atom_1".to_string())); | ||
90 | assert!(krate.cfg.contains(&"atom_2".to_string())); | ||
91 | assert!(krate.cfg.contains(&"feature=feature_1".to_string())); | ||
92 | assert!(krate.cfg.contains(&"feature=feature_2".to_string())); | ||
93 | assert!(krate.cfg.contains(&"other=value".to_string())); | ||
94 | } | ||
95 | } | 117 | } |