pallas_crypto/hash/
serde.rs

1use std::fmt;
2use std::str::FromStr;
3
4use serde::de::{Error, Unexpected, Visitor};
5use serde::{Deserialize, Deserializer, Serialize};
6
7use super::Hash;
8
9impl<const BYTES: usize> Serialize for Hash<BYTES> {
10    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
11    where
12        S: serde::Serializer,
13    {
14        serializer.serialize_str(&self.to_string())
15    }
16}
17
18struct HashVisitor<const BYTES: usize> {}
19
20impl<const BYTES: usize> Visitor<'_> for HashVisitor<BYTES> {
21    type Value = Hash<BYTES>;
22
23    fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
24        write!(formatter, "a hex string representing {BYTES} bytes")
25    }
26
27    fn visit_str<E>(self, s: &str) -> Result<Self::Value, E>
28    where
29        E: Error,
30    {
31        match Hash::<BYTES>::from_str(s) {
32            Ok(x) => Ok(x),
33            Err(_) => Err(Error::invalid_value(Unexpected::Str(s), &self)),
34        }
35    }
36}
37
38impl<'de, const BYTES: usize> Deserialize<'de> for Hash<BYTES> {
39    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
40    where
41        D: Deserializer<'de>,
42    {
43        deserializer.deserialize_str(HashVisitor::<BYTES> {})
44    }
45}
46
47#[cfg(test)]
48mod tests {
49    use serde_test::{assert_de_tokens_error, assert_tokens, Token};
50
51    use super::*;
52
53    #[derive(Debug, Deserialize, Serialize, PartialEq, Eq)]
54    struct Dummy {
55        hash1: Hash<28>,
56        hash2: Hash<32>,
57    }
58
59    #[test]
60    fn output_tokens() {
61        let dummy = Dummy {
62            hash1: "276fd18711931e2c0e21430192dbeac0e458093cd9d1fcd7210f64b3"
63                .parse()
64                .unwrap(),
65            hash2: "0d8d00cdd4657ac84d82f0a56067634a7adfdf43da41cb534bcaa45060973d21"
66                .parse()
67                .unwrap(),
68        };
69
70        assert_tokens(
71            &dummy,
72            &[
73                Token::Struct {
74                    name: "Dummy",
75                    len: 2,
76                },
77                Token::Str("hash1"),
78                Token::Str("276fd18711931e2c0e21430192dbeac0e458093cd9d1fcd7210f64b3"),
79                Token::Str("hash2"),
80                Token::Str("0d8d00cdd4657ac84d82f0a56067634a7adfdf43da41cb534bcaa45060973d21"),
81                Token::StructEnd,
82            ],
83        );
84    }
85
86    #[test]
87    fn invalid_str() {
88        assert_de_tokens_error::<Dummy>(
89            &[
90                Token::Map { len: Some(2) },
91                Token::Str("hash1"),
92                Token::Str("27"),
93            ],
94            "invalid value: string \"27\", expected a hex string representing 28 bytes",
95        );
96    }
97}