1use crate::{BuildStep, Dependency, Feature, PackageSource, Registry, Version};
4use serde::{Deserialize, Serialize};
5
6#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
10pub struct PackageId {
11 pub name: String,
12 pub version: Version,
13 pub registry: Registry,
14}
15
16impl PackageId {
17 #[must_use]
20 pub fn dotted(&self) -> String {
21 format!("{}/{}/{}", self.registry.as_str(), self.name, self.version)
22 }
23}
24
25#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
28pub struct Package {
29 pub name: String,
30 pub version: Version,
31 pub source: PackageSource,
32 pub registry: Registry,
33 #[serde(default)]
34 pub dependencies: Vec<Dependency>,
35 #[serde(default)]
36 pub features: Vec<Feature>,
37 #[serde(default)]
38 pub build_steps: Vec<BuildStep>,
39 #[serde(default)]
41 pub license: Option<String>,
42 #[serde(default)]
44 pub description: Option<String>,
45 #[serde(default)]
47 pub authors: Vec<String>,
48 #[serde(default)]
50 pub homepage: Option<String>,
51 #[serde(default)]
53 pub repository: Option<String>,
54}
55
56impl Package {
57 #[must_use]
59 pub fn id(&self) -> PackageId {
60 PackageId {
61 name: self.name.clone(),
62 version: self.version.clone(),
63 registry: self.registry.clone(),
64 }
65 }
66}
67
68#[cfg(test)]
69mod tests {
70 use super::*;
71 use crate::ConstraintSpec;
72
73 #[test]
74 fn id_dotted_form_is_stable() {
75 let p = Package {
76 name: "serde".into(),
77 version: Version::new(1, 0, 228),
78 source: PackageSource::Registry {
79 registry: Registry::CratesIo,
80 registry_name: "serde".into(),
81 integrity_hash: None,
82 },
83 registry: Registry::CratesIo,
84 dependencies: vec![],
85 features: vec![],
86 build_steps: vec![],
87 license: Some("MIT OR Apache-2.0".into()),
88 description: None,
89 authors: vec![],
90 homepage: None,
91 repository: None,
92 };
93 assert_eq!(p.id().dotted(), "crates-io/serde/1.0.228");
94 }
95
96 #[test]
97 fn package_id_used_as_hash_key() {
98 let id_a = PackageId {
99 name: "serde".into(),
100 version: Version::new(1, 0, 0),
101 registry: Registry::CratesIo,
102 };
103 let id_b = id_a.clone();
104 let mut m = std::collections::HashMap::new();
105 m.insert(id_a, "x");
106 assert_eq!(m.get(&id_b), Some(&"x"));
107 }
108
109 #[test]
110 fn round_trip_through_serde() {
111 let p = Package {
112 name: "serde".into(),
113 version: Version::new(1, 0, 228),
114 source: PackageSource::Registry {
115 registry: Registry::CratesIo,
116 registry_name: "serde".into(),
117 integrity_hash: Some("sha256:abc".into()),
118 },
119 registry: Registry::CratesIo,
120 dependencies: vec![Dependency {
121 name: "serde_derive".into(),
122 constraint: crate::VersionConstraint::from_spec(ConstraintSpec::Caret(
123 Version::new(1, 0, 228),
124 )),
125 kind: crate::DependencyKind::Direct,
126 features_enabled: vec![],
127 default_features: true,
128 target_predicate: None,
129 source_override: None,
130 }],
131 features: vec![],
132 build_steps: vec![],
133 license: Some("MIT".into()),
134 description: Some("Serialization framework".into()),
135 authors: vec![],
136 homepage: None,
137 repository: Some("https://github.com/serde-rs/serde".into()),
138 };
139 let j = serde_json::to_string(&p).unwrap();
140 let parsed: Package = serde_json::from_str(&j).unwrap();
141 assert_eq!(p, parsed);
142 }
143}