wasmer_config/
hash.rs

1use std::borrow::Cow;
2
3/// Sha256 hash, represented as bytes.
4#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
5pub struct Sha256Hash(pub [u8; 32]);
6
7impl Sha256Hash {
8    pub fn as_bytes(&self) -> &[u8; 32] {
9        &self.0
10    }
11
12    pub fn from_bytes(bytes: [u8; 32]) -> Self {
13        Self(bytes)
14    }
15}
16
17impl std::str::FromStr for Sha256Hash {
18    type Err = Sha256HashParseError;
19
20    fn from_str(s: &str) -> Result<Self, Self::Err> {
21        if s.len() != 64 {
22            return Err(Sha256HashParseError {
23                value: s.to_string(),
24                message: "invalid hash length - hash must have 64 hex-encoded characters "
25                    .to_string(),
26            });
27        }
28
29        let bytes = hex::decode(s).map_err(|e| Sha256HashParseError {
30            value: s.to_string(),
31            message: e.to_string(),
32        })?;
33
34        Ok(Sha256Hash(bytes.try_into().unwrap()))
35    }
36}
37
38impl std::fmt::Debug for Sha256Hash {
39    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
40        write!(f, "Sha256({})", hex::encode(self.0))
41    }
42}
43
44impl std::fmt::Display for Sha256Hash {
45    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
46        write!(f, "{}", hex::encode(self.0))
47    }
48}
49
50impl schemars::JsonSchema for Sha256Hash {
51    fn schema_name() -> Cow<'static, str> {
52        Cow::Borrowed("Sha256Hash")
53    }
54
55    fn json_schema(generator: &mut schemars::SchemaGenerator) -> schemars::Schema {
56        String::json_schema(generator)
57    }
58
59    fn inline_schema() -> bool {
60        false
61    }
62
63    fn schema_id() -> std::borrow::Cow<'static, str> {
64        Self::schema_name()
65    }
66}
67
68#[derive(Clone, Debug)]
69pub struct Sha256HashParseError {
70    value: String,
71    message: String,
72}
73
74impl std::fmt::Display for Sha256HashParseError {
75    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
76        write!(
77            f,
78            "could not parse value as sha256 hash: {} (value: '{}')",
79            self.message, self.value
80        )
81    }
82}
83
84impl std::error::Error for Sha256HashParseError {}
85
86#[cfg(test)]
87mod tests {
88    use super::*;
89
90    #[test]
91    fn hash_sha256_parse_roundtrip() {
92        let input = "c355cd53795b9b481f7eb2b5f4f6c8cf73631bdc343723a579d671e32db70b3c";
93        let h1 = input
94            .parse::<Sha256Hash>()
95            .expect("string should parse to hash");
96
97        assert_eq!(
98            h1.0,
99            [
100                195, 85, 205, 83, 121, 91, 155, 72, 31, 126, 178, 181, 244, 246, 200, 207, 115, 99,
101                27, 220, 52, 55, 35, 165, 121, 214, 113, 227, 45, 183, 11, 60
102            ],
103        );
104
105        assert_eq!(h1.to_string(), input);
106    }
107
108    #[test]
109    fn hash_sha256_parse_fails() {
110        let res1 =
111            "c355cd53795b9b481f7eb2b5f4f6c8cf73631bdc343723a579d671e32db70b3".parse::<Sha256Hash>();
112        assert!(res1.is_err());
113
114        let res2 = "".parse::<Sha256Hash>();
115        assert!(res2.is_err());
116
117        let res3 = "öööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööööö"
118            .parse::<Sha256Hash>();
119        assert!(res3.is_err());
120    }
121}