alloy_primitives/bits/
serde.rs

1use super::FixedBytes;
2use core::fmt;
3use serde::{
4    de::{self, Visitor},
5    Deserialize, Deserializer, Serialize, Serializer,
6};
7
8impl<const N: usize> Serialize for FixedBytes<N> {
9    fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
10        if serializer.is_human_readable() {
11            let mut buf = hex::Buffer::<N, true>::new();
12            serializer.serialize_str(buf.format(&self.0))
13        } else {
14            serializer.serialize_bytes(self.as_slice())
15        }
16    }
17}
18
19impl<'de, const N: usize> Deserialize<'de> for FixedBytes<N> {
20    fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
21        struct FixedVisitor<const N: usize>;
22
23        impl<'de, const N: usize> Visitor<'de> for FixedVisitor<N> {
24            type Value = FixedBytes<N>;
25
26            fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
27                write!(
28                    formatter,
29                    "{} bytes, represented as a hex string of length {}, an array of u8, or raw bytes",
30                    N,
31                    N * 2
32                )
33            }
34
35            fn visit_bytes<E: de::Error>(self, v: &[u8]) -> Result<Self::Value, E> {
36                FixedBytes::try_from(v).map_err(de::Error::custom)
37            }
38
39            fn visit_seq<A: de::SeqAccess<'de>>(self, mut seq: A) -> Result<Self::Value, A::Error> {
40                let len_error =
41                    |i| de::Error::invalid_length(i, &format!("exactly {N} bytes").as_str());
42                let mut bytes = [0u8; N];
43
44                for (i, byte) in bytes.iter_mut().enumerate() {
45                    *byte = seq.next_element()?.ok_or_else(|| len_error(i))?;
46                }
47
48                if let Ok(Some(_)) = seq.next_element::<u8>() {
49                    return Err(len_error(N + 1));
50                }
51
52                Ok(FixedBytes(bytes))
53            }
54
55            fn visit_str<E: de::Error>(self, v: &str) -> Result<Self::Value, E> {
56                <FixedBytes<N> as hex::FromHex>::from_hex(v).map_err(de::Error::custom)
57            }
58        }
59
60        if deserializer.is_human_readable() {
61            deserializer.deserialize_any(FixedVisitor::<N>)
62        } else {
63            deserializer.deserialize_bytes(FixedVisitor::<N>)
64        }
65    }
66}
67
68#[cfg(test)]
69mod tests {
70    use super::*;
71    use alloc::string::ToString;
72    use serde::Deserialize;
73
74    #[derive(Debug, Deserialize)]
75    struct TestCase<const N: usize> {
76        fixed: FixedBytes<N>,
77    }
78
79    #[test]
80    fn serde() {
81        let bytes = FixedBytes([0, 0, 0, 0, 1, 35, 69, 103, 137, 171, 205, 239]);
82        let ser = serde_json::to_string(&bytes).unwrap();
83        assert_eq!(ser, "\"0x000000000123456789abcdef\"");
84        assert_eq!(serde_json::from_str::<FixedBytes<12>>(&ser).unwrap(), bytes);
85
86        let val = serde_json::to_value(bytes).unwrap();
87        assert_eq!(val, serde_json::json! {"0x000000000123456789abcdef"});
88        assert_eq!(serde_json::from_value::<FixedBytes<12>>(val).unwrap(), bytes);
89    }
90
91    #[test]
92    fn serde_num_array() {
93        let json = serde_json::json! {{"fixed": [0,1,2,3,4]}};
94
95        assert_eq!(
96            serde_json::from_value::<TestCase<5>>(json.clone()).unwrap().fixed,
97            FixedBytes([0, 1, 2, 3, 4])
98        );
99
100        let e = serde_json::from_value::<TestCase<4>>(json).unwrap_err();
101        let es = e.to_string();
102        assert!(es.contains("invalid length 5, expected exactly 4 bytes"), "{es}");
103    }
104
105    #[test]
106    fn test_bincode_roundtrip() {
107        let bytes = FixedBytes([0, 0, 0, 0, 1, 35, 69, 103, 137, 171, 205, 239]);
108
109        let bin = bincode::serialize(&bytes).unwrap();
110        assert_eq!(bincode::deserialize::<FixedBytes<12>>(&bin).unwrap(), bytes);
111    }
112}