1use crate::directory::Directory;
2use crate::error::Error;
3use crate::inherit::InheritEdition;
4use crate::manifest::Edition;
5use serde::de::value::MapAccessDeserializer;
6use serde::de::value::StrDeserializer;
7use serde::de::{self, Deserialize, Deserializer, Visitor};
8use serde::ser::{Serialize, Serializer};
9use serde_derive::{Deserialize, Serialize};
10use serde_json::Value;
11use std::collections::BTreeMap as Map;
12use std::fmt;
13use std::fs;
14use std::path::PathBuf;
15
16pub fn get_manifest(manifest_dir: &Directory) -> Result<Manifest, Error> {
17 let cargo_toml_path = manifest_dir.join("Cargo.toml");
18 let mut manifest = (|| {
19 let manifest_str = fs::read_to_string(&cargo_toml_path)?;
20 let manifest: Manifest = basic_toml::from_str(&manifest_str)?;
21 Ok(manifest)
22 })()
23 .map_err(|err| Error::GetManifest(cargo_toml_path, Box::new(err)))?;
24
25 fix_dependencies(&mut manifest.dependencies, manifest_dir);
26 fix_dependencies(&mut manifest.dev_dependencies, manifest_dir);
27 for target in manifest.target.values_mut() {
28 fix_dependencies(&mut target.dependencies, manifest_dir);
29 fix_dependencies(&mut target.dev_dependencies, manifest_dir);
30 }
31
32 Ok(manifest)
33}
34
35pub fn get_workspace_manifest(manifest_dir: &Directory) -> WorkspaceManifest {
36 try_get_workspace_manifest(manifest_dir).unwrap_or_default()
37}
38
39pub fn try_get_workspace_manifest(manifest_dir: &Directory) -> Result<WorkspaceManifest, Error> {
40 let cargo_toml_path = manifest_dir.join("Cargo.toml");
41 let manifest_str = fs::read_to_string(cargo_toml_path)?;
42 let mut manifest: WorkspaceManifest = basic_toml::from_str(&manifest_str)?;
43
44 fix_dependencies(&mut manifest.workspace.dependencies, manifest_dir);
45 fix_patches(&mut manifest.patch, manifest_dir);
46 fix_replacements(&mut manifest.replace, manifest_dir);
47
48 Ok(manifest)
49}
50
51fn fix_dependencies(dependencies: &mut Map<String, Dependency>, dir: &Directory) {
52 dependencies.remove("trybuild");
53 for dep in dependencies.values_mut() {
54 dep.path = dep.path.as_ref().map(|path| Directory::new(dir.join(path)));
55 }
56}
57
58fn fix_patches(patches: &mut Map<String, RegistryPatch>, dir: &Directory) {
59 for registry in patches.values_mut() {
60 registry.crates.remove("trybuild");
61 for patch in registry.crates.values_mut() {
62 patch.path = patch.path.as_ref().map(|path| dir.join(path));
63 }
64 }
65}
66
67fn fix_replacements(replacements: &mut Map<String, Patch>, dir: &Directory) {
68 replacements.remove("trybuild");
69 for replacement in replacements.values_mut() {
70 replacement.path = replacement.path.as_ref().map(|path| dir.join(path));
71 }
72}
73
74#[derive(Deserialize, Default, Debug)]
75pub struct WorkspaceManifest {
76 #[serde(default)]
77 pub workspace: WorkspaceWorkspace,
78 #[serde(default)]
79 pub patch: Map<String, RegistryPatch>,
80 #[serde(default)]
81 pub replace: Map<String, Patch>,
82}
83
84#[derive(Deserialize, Default, Debug)]
85pub struct WorkspaceWorkspace {
86 #[serde(default)]
87 pub package: WorkspacePackage,
88 #[serde(default)]
89 pub dependencies: Map<String, Dependency>,
90}
91
92#[derive(Deserialize, Default, Debug)]
93pub struct WorkspacePackage {
94 pub edition: Option<Edition>,
95}
96
97#[derive(Deserialize, Default, Debug)]
98pub struct Manifest {
99 #[serde(default)]
100 pub package: Package,
101 #[serde(default)]
102 pub features: Map<String, Vec<String>>,
103 #[serde(default)]
104 pub dependencies: Map<String, Dependency>,
105 #[serde(default, alias = "dev-dependencies")]
106 pub dev_dependencies: Map<String, Dependency>,
107 #[serde(default)]
108 pub target: Map<String, TargetDependencies>,
109}
110
111#[derive(Deserialize, Default, Debug)]
112pub struct Package {
113 pub name: String,
114 #[serde(default)]
115 pub edition: EditionOrInherit,
116 pub resolver: Option<String>,
117}
118
119#[derive(Debug)]
120pub enum EditionOrInherit {
121 Edition(Edition),
122 Inherit,
123}
124
125#[derive(Serialize, Deserialize, Clone, Debug)]
126#[serde(remote = "Self")]
127pub struct Dependency {
128 #[serde(skip_serializing_if = "Option::is_none")]
129 pub version: Option<String>,
130 #[serde(skip_serializing_if = "Option::is_none")]
131 pub path: Option<Directory>,
132 #[serde(default, skip_serializing_if = "is_false")]
133 pub optional: bool,
134 #[serde(
135 rename = "default-features",
136 default = "get_true",
137 skip_serializing_if = "is_true"
138 )]
139 pub default_features: bool,
140 #[serde(default, skip_serializing_if = "Vec::is_empty")]
141 pub features: Vec<String>,
142 #[serde(skip_serializing_if = "Option::is_none")]
143 pub git: Option<String>,
144 #[serde(skip_serializing_if = "Option::is_none")]
145 pub branch: Option<String>,
146 #[serde(skip_serializing_if = "Option::is_none")]
147 pub tag: Option<String>,
148 #[serde(skip_serializing_if = "Option::is_none")]
149 pub rev: Option<String>,
150 #[serde(default, skip_serializing_if = "is_false")]
151 pub workspace: bool,
152 #[serde(flatten)]
153 pub rest: Map<String, Value>,
154}
155
156#[derive(Serialize, Deserialize, Clone, Debug)]
157pub struct TargetDependencies {
158 #[serde(default, skip_serializing_if = "Map::is_empty")]
159 pub dependencies: Map<String, Dependency>,
160 #[serde(
161 default,
162 alias = "dev-dependencies",
163 skip_serializing_if = "Map::is_empty"
164 )]
165 pub dev_dependencies: Map<String, Dependency>,
166}
167
168#[derive(Serialize, Deserialize, Clone, Debug)]
169#[serde(transparent)]
170pub struct RegistryPatch {
171 pub crates: Map<String, Patch>,
172}
173
174#[derive(Serialize, Deserialize, Clone, Debug)]
175pub struct Patch {
176 #[serde(skip_serializing_if = "Option::is_none")]
177 pub path: Option<PathBuf>,
178 #[serde(skip_serializing_if = "Option::is_none")]
179 pub git: Option<String>,
180 #[serde(skip_serializing_if = "Option::is_none")]
181 pub branch: Option<String>,
182 #[serde(skip_serializing_if = "Option::is_none")]
183 pub tag: Option<String>,
184 #[serde(skip_serializing_if = "Option::is_none")]
185 pub rev: Option<String>,
186 #[serde(flatten)]
187 pub rest: Map<String, Value>,
188}
189
190fn get_true() -> bool {
191 true
192}
193
194fn is_true(boolean: &bool) -> bool {
195 *boolean
196}
197
198fn is_false(boolean: &bool) -> bool {
199 !*boolean
200}
201
202impl Default for EditionOrInherit {
203 fn default() -> Self {
204 EditionOrInherit::Edition(Edition::default())
205 }
206}
207
208impl<'de> Deserialize<'de> for EditionOrInherit {
209 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
210 where
211 D: Deserializer<'de>,
212 {
213 struct EditionOrInheritVisitor;
214
215 impl<'de> Visitor<'de> for EditionOrInheritVisitor {
216 type Value = EditionOrInherit;
217
218 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
219 formatter.write_str("edition")
220 }
221
222 fn visit_str<E>(self, s: &str) -> Result<Self::Value, E>
223 where
224 E: de::Error,
225 {
226 Edition::deserialize(StrDeserializer::new(s)).map(EditionOrInherit::Edition)
227 }
228
229 fn visit_map<M>(self, map: M) -> Result<Self::Value, M::Error>
230 where
231 M: de::MapAccess<'de>,
232 {
233 InheritEdition::deserialize(MapAccessDeserializer::new(map))?;
234 Ok(EditionOrInherit::Inherit)
235 }
236 }
237
238 deserializer.deserialize_any(EditionOrInheritVisitor)
239 }
240}
241
242impl Serialize for Dependency {
243 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
244 where
245 S: Serializer,
246 {
247 Dependency::serialize(self, serializer)
248 }
249}
250
251impl<'de> Deserialize<'de> for Dependency {
252 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
253 where
254 D: Deserializer<'de>,
255 {
256 struct DependencyVisitor;
257
258 impl<'de> Visitor<'de> for DependencyVisitor {
259 type Value = Dependency;
260
261 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
262 formatter.write_str(
263 "a version string like \"0.9.8\" or a \
264 dependency like { version = \"0.9.8\" }",
265 )
266 }
267
268 fn visit_str<E>(self, s: &str) -> Result<Self::Value, E>
269 where
270 E: de::Error,
271 {
272 Ok(Dependency {
273 version: Some(s.to_owned()),
274 path: None,
275 optional: false,
276 default_features: true,
277 features: Vec::new(),
278 git: None,
279 branch: None,
280 tag: None,
281 rev: None,
282 workspace: false,
283 rest: Map::new(),
284 })
285 }
286
287 fn visit_map<M>(self, map: M) -> Result<Self::Value, M::Error>
288 where
289 M: de::MapAccess<'de>,
290 {
291 Dependency::deserialize(MapAccessDeserializer::new(map))
292 }
293 }
294
295 deserializer.deserialize_any(DependencyVisitor)
296 }
297}
298