1use serde::{Deserialize, Serialize};
2use sha2::{Digest, Sha256};
3use std::collections::HashMap;
4use std::hash::Hash;
5
6#[derive(Clone, Debug, Default, Deserialize)]
7pub struct Dependency {
8 pub name: String,
9 pub version_req: String,
10 pub features: Vec<String>,
11 pub optional: bool,
12 pub default_features: bool,
13 pub target: Option<String>,
14 pub kind: String,
15 pub registry: Option<String>,
16 pub package: Option<String>,
17}
18
19#[derive(Clone, Debug, Default, Deserialize)]
20pub struct MetaData {
21 pub name: String,
22 pub vers: String,
23 pub deps: Vec<Dependency>,
24 pub features: HashMap<String, Vec<String>>,
25 pub authors: Vec<String>,
26 pub description: Option<String>,
27 pub documentation: Option<String>,
28 pub homepage: Option<String>,
29 pub readme: Option<String>,
30 pub readme_file: Option<String>,
31 pub keywords: Vec<String>,
32 pub categories: Vec<String>,
33 pub license: Option<String>,
34 pub license_file: Option<String>,
35 pub repository: Option<String>,
36 pub badges: HashMap<String, HashMap<String, String>>,
37 pub links: Option<String>,
38}
39
40#[derive(Debug, Default)]
41pub struct PublishRequest {
42 pub meta: MetaData,
43 pub data: Vec<u8>,
44}
45
46impl MetaData {
47 pub fn crate_file_path(&self) -> String {
48 crate::get_crate_file_path(&self.name)
49 }
50}
51
52#[derive(Debug, Serialize, Deserialize, Eq, PartialEq)]
53pub struct PublishedDependency {
54 pub name: String,
55 pub req: String,
56 pub features: Vec<String>,
57 pub optional: bool,
58 pub default_features: bool,
59 pub target: Option<String>,
60 pub kind: String,
61 pub registry: Option<String>,
62 pub package: Option<String>,
63}
64
65impl std::convert::From<Dependency> for PublishedDependency {
66 fn from(dep: Dependency) -> Self {
67 Self {
68 name: dep.name,
69 req: dep.version_req,
70 features: dep.features,
71 optional: dep.optional,
72 default_features: dep.default_features,
73 target: dep.target,
74 kind: dep.kind,
75 registry: dep.registry,
76 package: dep.package,
77 }
78 }
79}
80
81#[derive(Debug, Serialize, Deserialize, Eq)]
82pub struct PublishedVersion {
83 pub name: String,
84 pub vers: String,
85 pub deps: Vec<PublishedDependency>,
86 pub cksum: String,
87 pub features: HashMap<String, Vec<String>>,
88 pub yanked: bool,
89 pub links: Option<String>,
90}
91
92impl std::convert::From<&PublishRequest> for PublishedVersion {
93 fn from(req: &PublishRequest) -> Self {
94 let cksum = Sha256::digest(&req.data);
95
96 Self {
97 name: req.meta.name.clone(),
98 vers: req.meta.vers.clone(),
99 deps: req
100 .meta
101 .deps
102 .clone()
103 .into_iter()
104 .map(|dep| dep.into())
105 .collect(),
106 cksum: hex::encode(cksum),
107 features: req.meta.features.clone(),
108 yanked: false,
109 links: req.meta.links.clone(),
110 }
111 }
112}
113
114impl std::cmp::PartialEq for PublishedVersion {
115 fn eq(&self, other: &Self) -> bool {
116 self.vers == other.vers && self.name == other.name
117 }
118}
119
120impl Hash for PublishedVersion {
121 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
122 self.name.hash(state);
123 self.vers.hash(state);
124 }
125}
126
127#[cfg(test)]
128mod tests {
129 #[test]
130 fn test_crate_file_path_1() {
131 let meta = super::MetaData {
132 name: "A".into(),
133 ..Default::default()
134 };
135 assert_eq!("1/A", meta.crate_file_path());
136 }
137
138 #[test]
139 fn test_crate_file_path_2() {
140 let meta = super::MetaData {
141 name: "AB".into(),
142 ..Default::default()
143 };
144 assert_eq!("2/AB", meta.crate_file_path());
145 }
146
147 #[test]
148 fn test_crate_file_path_3() {
149 let meta = super::MetaData {
150 name: "ABC".into(),
151 ..Default::default()
152 };
153 assert_eq!("3/A/ABC", meta.crate_file_path());
154 }
155
156 #[test]
157 fn test_crate_file_path_more() {
158 let meta = super::MetaData {
159 name: "ABCDE".into(),
160 ..Default::default()
161 };
162 assert_eq!("AB/CD/ABCDE", meta.crate_file_path());
163 }
164}