1use crate::Registry;
4use serde::{Deserialize, Serialize};
5
6#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
9#[serde(tag = "kind", rename_all = "kebab-case")]
10pub enum PackageSource {
11 Registry {
13 registry: Registry,
14 registry_name: String,
17 integrity_hash: Option<String>,
20 },
21 Git {
23 url: String,
24 rev: String,
27 #[serde(default)]
30 subdir: Option<String>,
31 },
32 Path { path: String },
34 Local { path: String, overrides: String },
39}
40
41impl PackageSource {
42 #[must_use]
44 pub const fn kind_str(&self) -> &'static str {
45 match self {
46 Self::Registry { .. } => "registry",
47 Self::Git { .. } => "git",
48 Self::Path { .. } => "path",
49 Self::Local { .. } => "local",
50 }
51 }
52
53 #[must_use]
58 pub fn is_content_addressed(&self) -> bool {
59 match self {
60 Self::Registry { integrity_hash, .. } => integrity_hash.is_some(),
61 Self::Git { .. } => true,
62 Self::Path { .. } | Self::Local { .. } => false,
63 }
64 }
65}
66
67#[cfg(test)]
68mod tests {
69 use super::*;
70
71 #[test]
72 fn registry_with_hash_is_content_addressed() {
73 let s = PackageSource::Registry {
74 registry: Registry::CratesIo,
75 registry_name: "serde".into(),
76 integrity_hash: Some("sha256:abc".into()),
77 };
78 assert!(s.is_content_addressed());
79 }
80
81 #[test]
82 fn registry_without_hash_is_not_content_addressed() {
83 let s = PackageSource::Registry {
84 registry: Registry::CratesIo,
85 registry_name: "serde".into(),
86 integrity_hash: None,
87 };
88 assert!(!s.is_content_addressed());
89 }
90
91 #[test]
92 fn git_is_always_content_addressed() {
93 let s = PackageSource::Git {
94 url: "https://github.com/x/y".into(),
95 rev: "abc123".into(),
96 subdir: None,
97 };
98 assert!(s.is_content_addressed());
99 }
100
101 #[test]
102 fn path_and_local_are_not_content_addressed() {
103 assert!(!PackageSource::Path { path: "../foo".into() }.is_content_addressed());
104 assert!(
105 !PackageSource::Local {
106 path: "../foo".into(),
107 overrides: "crates-io.serde".into(),
108 }
109 .is_content_addressed()
110 );
111 }
112
113 #[test]
114 fn round_trip_through_serde() {
115 let s = PackageSource::Git {
116 url: "https://github.com/x/y".into(),
117 rev: "abc123".into(),
118 subdir: Some("crates/foo".into()),
119 };
120 let j = serde_json::to_string(&s).unwrap();
121 let parsed: PackageSource = serde_json::from_str(&j).unwrap();
122 assert_eq!(s, parsed);
123 }
124}