serde_utils/
fixed_bytes_hex.rs

1//! Formats `[u8; n]` as a 0x-prefixed hex string.
2//!
3//! E.g., `[0, 1, 2, 3]` serializes as `"0x00010203"`.
4
5use crate::hex::PrefixedHexVisitor;
6use serde::de::Error;
7use serde::{Deserializer, Serializer};
8
9macro_rules! bytes_hex {
10    ($num_bytes: tt) => {
11        use super::*;
12
13        const BYTES_LEN: usize = $num_bytes;
14
15        pub fn serialize<S>(bytes: &[u8; BYTES_LEN], serializer: S) -> Result<S::Ok, S::Error>
16        where
17            S: Serializer,
18        {
19            let mut hex_string: String = "0x".to_string();
20            hex_string.push_str(&hex::encode(&bytes));
21
22            serializer.serialize_str(&hex_string)
23        }
24
25        pub fn deserialize<'de, D>(deserializer: D) -> Result<[u8; BYTES_LEN], D::Error>
26        where
27            D: Deserializer<'de>,
28        {
29            let decoded = deserializer.deserialize_str(PrefixedHexVisitor)?;
30
31            if decoded.len() != BYTES_LEN {
32                return Err(D::Error::custom(format!(
33                    "expected {} bytes for array, got {}",
34                    BYTES_LEN,
35                    decoded.len()
36                )));
37            }
38
39            let mut array = [0; BYTES_LEN];
40            array.copy_from_slice(&decoded);
41            Ok(array)
42        }
43
44        #[cfg(test)]
45        mod test {
46            use super::*;
47            use serde::{Deserialize, Serialize};
48
49            #[derive(Debug, PartialEq, Serialize, Deserialize)]
50            #[serde(transparent)]
51            struct Wrapper {
52                #[serde(with = "super")]
53                val: [u8; BYTES_LEN],
54            }
55
56            fn generate_string_value(v1: &str, v2: &str) -> String {
57                let mut i = 0;
58                let mut value = String::new();
59                while i < BYTES_LEN * 2 {
60                    if i % 2 == 0 {
61                        value.push_str(v1);
62                    } else {
63                        value.push_str(v2);
64                    }
65                    i += 1;
66                }
67                value
68            }
69
70            #[test]
71            fn encoding() {
72                let zero = "0".repeat(BYTES_LEN * 2);
73                assert_eq!(
74                    &serde_json::to_string(&Wrapper {
75                        val: [0; BYTES_LEN]
76                    })
77                    .unwrap(),
78                    &format!("\"0x{}\"", zero)
79                );
80
81                assert_eq!(
82                    &serde_json::to_string(&Wrapper {
83                        val: [123; BYTES_LEN]
84                    })
85                    .unwrap(),
86                    &format!("\"0x{}\"", generate_string_value("7", "b"))
87                );
88
89                let max = "f".repeat(BYTES_LEN * 2);
90                assert_eq!(
91                    &serde_json::to_string(&Wrapper {
92                        val: [u8::MAX; BYTES_LEN]
93                    })
94                    .unwrap(),
95                    &format!("\"0x{}\"", max)
96                );
97            }
98
99            #[test]
100            fn decoding() {
101                let zero = "0".repeat(BYTES_LEN * 2);
102                assert_eq!(
103                    serde_json::from_str::<Wrapper>(&format!("\"0x{}\"", zero)).unwrap(),
104                    Wrapper {
105                        val: [0; BYTES_LEN]
106                    },
107                );
108                assert_eq!(
109                    serde_json::from_str::<Wrapper>(&format!(
110                        "\"0x{}\"",
111                        generate_string_value("7", "b")
112                    ))
113                    .unwrap(),
114                    Wrapper {
115                        val: [123; BYTES_LEN]
116                    },
117                );
118
119                let max = "f".repeat(BYTES_LEN * 2);
120                assert_eq!(
121                    serde_json::from_str::<Wrapper>(&format!("\"0x{}\"", max)).unwrap(),
122                    Wrapper {
123                        val: [u8::MAX; BYTES_LEN]
124                    },
125                );
126
127                // Require 0x.
128                serde_json::from_str::<Wrapper>(&format!("\"{}\"", "0".repeat(BYTES_LEN * 2)))
129                    .unwrap_err();
130
131                let exceed_max = "f".repeat((BYTES_LEN * 2) + 1);
132                // Wrong length.
133                serde_json::from_str::<Wrapper>(&format!("\"0x{}\"", exceed_max)).unwrap_err();
134            }
135        }
136    };
137}
138
139pub mod bytes_4_hex {
140    bytes_hex!(4);
141}
142
143pub mod bytes_8_hex {
144    bytes_hex!(8);
145}