wasmer_config/package/
package_hash.rs1use std::borrow::Cow;
2
3use crate::{hash::Sha256Hash, package::PackageParseError};
4
5#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
9#[non_exhaustive]
10pub enum PackageHash {
11 Sha256(Sha256Hash),
12}
13
14impl PackageHash {
15 const SHA256_STR_PREFIX: &'static str = "sha256:";
16
17 pub fn as_sha256(&self) -> Option<&Sha256Hash> {
18 match self {
19 PackageHash::Sha256(hash) => Some(hash),
20 }
21 }
22
23 pub fn from_sha256_bytes(bytes: [u8; 32]) -> Self {
24 Self::Sha256(Sha256Hash(bytes))
25 }
26}
27
28impl From<Sha256Hash> for PackageHash {
29 fn from(value: Sha256Hash) -> Self {
30 Self::Sha256(value)
31 }
32}
33
34impl std::fmt::Display for PackageHash {
35 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
36 match self {
37 Self::Sha256(hash) => write!(f, "sha256:{hash}"),
38 }
39 }
40}
41
42impl std::str::FromStr for PackageHash {
43 type Err = PackageParseError;
44
45 fn from_str(s: &str) -> Result<Self, Self::Err> {
46 if !s.starts_with(Self::SHA256_STR_PREFIX) {
47 return Err(PackageParseError::new(
48 s,
49 "package hashes must start with 'sha256:'",
50 ));
51 }
52 let hash = Sha256Hash::from_str(&s[Self::SHA256_STR_PREFIX.len()..])
53 .map_err(|e| PackageParseError::new(s, e.to_string()))?;
54
55 Ok(Self::Sha256(hash))
56 }
57}
58
59impl serde::Serialize for PackageHash {
60 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
61 where
62 S: serde::Serializer,
63 {
64 serializer.serialize_str(&self.to_string())
65 }
66}
67
68impl<'de> serde::Deserialize<'de> for PackageHash {
69 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
70 where
71 D: serde::Deserializer<'de>,
72 {
73 let s = String::deserialize(deserializer)?;
74 s.parse::<Self>()
75 .map_err(|e| serde::de::Error::custom(e.to_string()))
76 }
77}
78
79impl schemars::JsonSchema for PackageHash {
80 fn schema_name() -> Cow<'static, str> {
81 Cow::Borrowed("PackageHash")
82 }
83
84 fn json_schema(generator: &mut schemars::SchemaGenerator) -> schemars::Schema {
85 String::json_schema(generator)
86 }
87
88 fn inline_schema() -> bool {
89 false
90 }
91
92 fn schema_id() -> std::borrow::Cow<'static, str> {
93 Self::schema_name()
94 }
95}
96
97#[cfg(test)]
98mod tests {
99 use super::*;
100
101 #[test]
102 fn parse_package_hash_roundtrip() {
103 let input = "sha256:c355cd53795b9b481f7eb2b5f4f6c8cf73631bdc343723a579d671e32db70b3c";
104 let h1 = input
105 .parse::<PackageHash>()
106 .expect("string should parse to hash");
107
108 assert_eq!(
109 h1.as_sha256().unwrap().as_bytes(),
110 &[
111 195, 85, 205, 83, 121, 91, 155, 72, 31, 126, 178, 181, 244, 246, 200, 207, 115, 99,
112 27, 220, 52, 55, 35, 165, 121, 214, 113, 227, 45, 183, 11, 60
113 ],
114 );
115
116 assert_eq!(h1.to_string(), input);
117 }
118
119 #[test]
120 fn package_hash_serde_roundtrip() {
121 let input = "sha256:c355cd53795b9b481f7eb2b5f4f6c8cf73631bdc343723a579d671e32db70b3c";
122 let h1 = input
123 .parse::<PackageHash>()
124 .expect("string should parse to hash");
125
126 assert_eq!(
128 serde_json::to_value(&h1).unwrap(),
129 serde_json::Value::String(input.to_owned()),
130 );
131
132 let v = serde_json::to_string(&h1).unwrap();
134 let h2 = serde_json::from_str::<PackageHash>(&v).unwrap();
135
136 assert_eq!(h1, h2);
137 }
138}