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