1use semver::{Version, VersionReq};
2use serde::{Deserialize, Serialize};
3use std::{collections::HashMap, fmt};
4use url::Url;
5
6#[derive(Debug, Serialize, Deserialize)]
10pub struct Metadata {
11 name: String,
12
13 vers: Version,
14
15 #[serde(skip_serializing_if = "Vec::is_empty", default)]
16 deps: Vec<Dependency>,
17
18 cksum: String,
19
20 #[serde(skip_serializing_if = "HashMap::is_empty", default)]
21 features: HashMap<String, Vec<String>>,
22
23 yanked: bool,
24
25 #[serde(skip_serializing_if = "Option::is_none", default)]
26 links: Option<String>,
27}
28
29impl Metadata {
30 pub fn new(name: impl Into<String>, version: Version, check_sum: impl Into<String>) -> Self {
35 let name = name.into();
36 let vers = version;
37 let deps = Vec::new();
38 let cksum = check_sum.into();
39 let features = HashMap::new();
40 let yanked = false;
41 let links = None;
42
43 Self {
44 name,
45 vers,
46 deps,
47 cksum,
48 features,
49 yanked,
50 links,
51 }
52 }
53
54 #[must_use]
56 pub fn name(&self) -> &String {
57 &self.name
58 }
59
60 #[must_use]
62 pub fn version(&self) -> &Version {
63 &self.vers
64 }
65
66 #[must_use]
68 pub fn dependencies(&self) -> &Vec<Dependency> {
69 &self.deps
70 }
71
72 #[must_use]
74 pub fn check_sum(&self) -> &String {
75 &self.cksum
76 }
77
78 #[must_use]
82 pub fn features(&self) -> &HashMap<String, Vec<String>> {
83 &self.features
84 }
85
86 #[must_use]
88 pub fn yanked(&self) -> bool {
89 self.yanked
90 }
91
92 #[must_use]
94 pub fn links(&self) -> Option<&String> {
95 self.links.as_ref()
96 }
97
98 pub fn yank(&mut self) {
100 self.yanked = true;
101 }
102
103 pub fn unyank(&mut self) {
105 self.yanked = false;
106 }
107}
108
109impl fmt::Display for Metadata {
110 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
111 write!(f, "{}", &serde_json::to_string(self).unwrap())
112 }
113}
114
115#[derive(Debug, Serialize, Deserialize)]
116pub struct Dependency {
117 name: String,
122
123 req: VersionReq,
125
126 #[serde(skip_serializing_if = "Vec::is_empty", default)]
128 features: Vec<String>,
129
130 optional: bool,
132
133 default_features: bool,
135
136 #[serde(skip_serializing_if = "Option::is_none", default)]
140 target: Option<String>,
141
142 kind: DependencyKind,
145
146 #[serde(skip_serializing_if = "Option::is_none", default)]
150 registry: Option<Url>,
151
152 #[serde(skip_serializing_if = "Option::is_none", default)]
156 package: Option<String>,
157}
158
159#[derive(Debug, Serialize, Deserialize)]
160#[serde(rename_all = "snake_case")]
161enum DependencyKind {
162 Dev,
164
165 Build,
167
168 Normal,
170}
171
172#[cfg(test)]
173mod tests {
174 use super::Metadata;
175 use semver::Version;
176
177 #[test]
178 fn serialize() {
179 let name = "foo";
180 let version = Version::parse("0.1.0").unwrap();
181 let check_sum = "d867001db0e2b6e0496f9fac96930e2d42233ecd3ca0413e0753d4c7695d289c";
182
183 let metadata = Metadata::new(name, version, check_sum);
184
185 let expected = r#"{"name":"foo","vers":"0.1.0","cksum":"d867001db0e2b6e0496f9fac96930e2d42233ecd3ca0413e0753d4c7695d289c","yanked":false}"#.to_string();
186 let actual = metadata.to_string();
187
188 assert_eq!(expected, actual)
189 }
190
191 #[test]
192 fn deserialize() {
193 let example1 = r#"
194 {
195 "name": "foo",
196 "vers": "0.1.0",
197 "deps": [
198 {
199 "name": "rand",
200 "req": "^0.6",
201 "features": ["i128_support"],
202 "optional": false,
203 "default_features": true,
204 "target": null,
205 "kind": "normal",
206 "registry": null,
207 "package": null
208 }
209 ],
210 "cksum": "d867001db0e2b6e0496f9fac96930e2d42233ecd3ca0413e0753d4c7695d289c",
211 "features": {
212 "extras": ["rand/simd_support"]
213 },
214 "yanked": false,
215 "links": null
216 }
217 "#;
218
219 let _: Metadata = serde_json::from_str(example1).unwrap();
220
221 let example2 = r#"
222 {
223 "name": "my_serde",
224 "vers": "1.0.11",
225 "deps": [
226 {
227 "name": "serde",
228 "req": "^1.0",
229 "registry": "https://github.com/rust-lang/crates.io-index",
230 "features": [],
231 "optional": true,
232 "default_features": true,
233 "target": null,
234 "kind": "normal"
235 }
236 ],
237 "cksum": "f7726f29ddf9731b17ff113c461e362c381d9d69433f79de4f3dd572488823e9",
238 "features": {
239 "default": [
240 "std"
241 ],
242 "derive": [
243 "serde_derive"
244 ],
245 "std": [
246
247 ]
248 },
249 "yanked": false
250 }
251 "#;
252
253 let _: Metadata = serde_json::from_str(example2).unwrap();
254 }
255
256 #[test]
257 fn yank() {
258 let name = "foo";
259 let version = Version::parse("0.1.0").unwrap();
260 let check_sum = "CHECK_SUM";
261
262 let mut metadata = Metadata::new(name, version, check_sum);
263
264 assert!(!metadata.yanked());
265
266 metadata.yank();
267 assert!(metadata.yanked());
268
269 metadata.unyank();
270 assert!(!metadata.yanked());
271 }
272}