diff options
Diffstat (limited to 'crates/project_model/src/project_json.rs')
-rw-r--r-- | crates/project_model/src/project_json.rs | 143 |
1 files changed, 143 insertions, 0 deletions
diff --git a/crates/project_model/src/project_json.rs b/crates/project_model/src/project_json.rs new file mode 100644 index 000000000..060ea5b7d --- /dev/null +++ b/crates/project_model/src/project_json.rs | |||
@@ -0,0 +1,143 @@ | |||
1 | //! FIXME: write short doc here | ||
2 | |||
3 | use std::path::PathBuf; | ||
4 | |||
5 | use base_db::{CrateId, CrateName, Dependency, Edition}; | ||
6 | use paths::{AbsPath, AbsPathBuf}; | ||
7 | use rustc_hash::FxHashMap; | ||
8 | use serde::{de, Deserialize}; | ||
9 | |||
10 | use crate::cfg_flag::CfgFlag; | ||
11 | |||
12 | /// Roots and crates that compose this Rust project. | ||
13 | #[derive(Clone, Debug, Eq, PartialEq)] | ||
14 | pub struct ProjectJson { | ||
15 | pub(crate) crates: Vec<Crate>, | ||
16 | } | ||
17 | |||
18 | /// A crate points to the root module of a crate and lists the dependencies of the crate. This is | ||
19 | /// useful in creating the crate graph. | ||
20 | #[derive(Clone, Debug, Eq, PartialEq)] | ||
21 | pub struct Crate { | ||
22 | pub(crate) root_module: AbsPathBuf, | ||
23 | pub(crate) edition: Edition, | ||
24 | pub(crate) deps: Vec<Dependency>, | ||
25 | pub(crate) cfg: Vec<CfgFlag>, | ||
26 | pub(crate) target: Option<String>, | ||
27 | pub(crate) env: FxHashMap<String, String>, | ||
28 | pub(crate) proc_macro_dylib_path: Option<AbsPathBuf>, | ||
29 | pub(crate) is_workspace_member: bool, | ||
30 | pub(crate) include: Vec<AbsPathBuf>, | ||
31 | pub(crate) exclude: Vec<AbsPathBuf>, | ||
32 | } | ||
33 | |||
34 | impl ProjectJson { | ||
35 | pub fn new(base: &AbsPath, data: ProjectJsonData) -> ProjectJson { | ||
36 | ProjectJson { | ||
37 | crates: data | ||
38 | .crates | ||
39 | .into_iter() | ||
40 | .map(|crate_data| { | ||
41 | let is_workspace_member = crate_data.is_workspace_member.unwrap_or_else(|| { | ||
42 | crate_data.root_module.is_relative() | ||
43 | && !crate_data.root_module.starts_with("..") | ||
44 | || crate_data.root_module.starts_with(base) | ||
45 | }); | ||
46 | let root_module = base.join(crate_data.root_module); | ||
47 | let (include, exclude) = match crate_data.source { | ||
48 | Some(src) => { | ||
49 | let absolutize = |dirs: Vec<PathBuf>| { | ||
50 | dirs.into_iter().map(|it| base.join(it)).collect::<Vec<_>>() | ||
51 | }; | ||
52 | (absolutize(src.include_dirs), absolutize(src.exclude_dirs)) | ||
53 | } | ||
54 | None => (vec![root_module.parent().unwrap().to_path_buf()], Vec::new()), | ||
55 | }; | ||
56 | |||
57 | Crate { | ||
58 | root_module, | ||
59 | edition: crate_data.edition.into(), | ||
60 | deps: crate_data | ||
61 | .deps | ||
62 | .into_iter() | ||
63 | .map(|dep_data| Dependency { | ||
64 | crate_id: CrateId(dep_data.krate as u32), | ||
65 | name: dep_data.name, | ||
66 | }) | ||
67 | .collect::<Vec<_>>(), | ||
68 | cfg: crate_data.cfg, | ||
69 | target: crate_data.target, | ||
70 | env: crate_data.env, | ||
71 | proc_macro_dylib_path: crate_data | ||
72 | .proc_macro_dylib_path | ||
73 | .map(|it| base.join(it)), | ||
74 | is_workspace_member, | ||
75 | include, | ||
76 | exclude, | ||
77 | } | ||
78 | }) | ||
79 | .collect::<Vec<_>>(), | ||
80 | } | ||
81 | } | ||
82 | } | ||
83 | |||
84 | #[derive(Deserialize)] | ||
85 | pub struct ProjectJsonData { | ||
86 | crates: Vec<CrateData>, | ||
87 | } | ||
88 | |||
89 | #[derive(Deserialize)] | ||
90 | struct CrateData { | ||
91 | root_module: PathBuf, | ||
92 | edition: EditionData, | ||
93 | deps: Vec<DepData>, | ||
94 | #[serde(default)] | ||
95 | cfg: Vec<CfgFlag>, | ||
96 | target: Option<String>, | ||
97 | #[serde(default)] | ||
98 | env: FxHashMap<String, String>, | ||
99 | proc_macro_dylib_path: Option<PathBuf>, | ||
100 | is_workspace_member: Option<bool>, | ||
101 | source: Option<CrateSource>, | ||
102 | } | ||
103 | |||
104 | #[derive(Deserialize)] | ||
105 | #[serde(rename = "edition")] | ||
106 | enum EditionData { | ||
107 | #[serde(rename = "2015")] | ||
108 | Edition2015, | ||
109 | #[serde(rename = "2018")] | ||
110 | Edition2018, | ||
111 | } | ||
112 | |||
113 | impl From<EditionData> for Edition { | ||
114 | fn from(data: EditionData) -> Self { | ||
115 | match data { | ||
116 | EditionData::Edition2015 => Edition::Edition2015, | ||
117 | EditionData::Edition2018 => Edition::Edition2018, | ||
118 | } | ||
119 | } | ||
120 | } | ||
121 | |||
122 | #[derive(Deserialize)] | ||
123 | struct DepData { | ||
124 | /// Identifies a crate by position in the crates array. | ||
125 | #[serde(rename = "crate")] | ||
126 | krate: usize, | ||
127 | #[serde(deserialize_with = "deserialize_crate_name")] | ||
128 | name: CrateName, | ||
129 | } | ||
130 | |||
131 | #[derive(Deserialize)] | ||
132 | struct CrateSource { | ||
133 | include_dirs: Vec<PathBuf>, | ||
134 | exclude_dirs: Vec<PathBuf>, | ||
135 | } | ||
136 | |||
137 | fn deserialize_crate_name<'de, D>(de: D) -> Result<CrateName, D::Error> | ||
138 | where | ||
139 | D: de::Deserializer<'de>, | ||
140 | { | ||
141 | let name = String::deserialize(de)?; | ||
142 | CrateName::new(&name).map_err(|err| de::Error::custom(format!("invalid crate name: {:?}", err))) | ||
143 | } | ||