multihash/
serde.rs

1//! Multihash Serde (de)serialization
2
3use core::{fmt, mem, slice};
4
5use serde::{
6    de::{self, SeqAccess, Visitor},
7    ser, Deserialize, Deserializer, Serialize, Serializer,
8};
9
10use crate::Multihash;
11
12/// The maximum serialization size of `code` is 9 bytes (a large varint encoded u64) and for `size`
13/// is 2 bytes  (a large varint encoded u8), this makes a total of 11 bytes.
14const MAXIMUM_PREFIX_SIZE: usize = 11;
15
16/// The is currently no way to allocate an array that is some constant size bigger then a given
17/// const generic. Once `generic_const_exprs` are a thing, this struct will no longer be needed.
18/// Until then we introduce a hack. We allocate a struct, which contains two independent arrays,
19/// which can be specified with const generics. We then treat the whole struct as a slice of
20/// continuous memory.
21#[repr(C, packed)]
22struct Buffer<const SIZE_FIRST: usize, const SIZE_SECOND: usize> {
23    first: [u8; SIZE_FIRST],
24    second: [u8; SIZE_SECOND],
25}
26
27#[allow(unsafe_code)]
28impl<const SIZE_FIRST: usize, const SIZE_SECOND: usize> Buffer<SIZE_FIRST, SIZE_SECOND> {
29    fn new() -> Self {
30        Self {
31            first: [0; SIZE_FIRST],
32            second: [0; SIZE_SECOND],
33        }
34    }
35
36    fn as_slice(&self) -> &[u8] {
37        unsafe { slice::from_raw_parts(self as *const _ as _, mem::size_of::<Self>()) }
38    }
39
40    fn as_mut_slice(&mut self) -> &mut [u8] {
41        unsafe { slice::from_raw_parts_mut(self as *mut _ as _, mem::size_of::<Self>()) }
42    }
43}
44
45impl<const SIZE: usize> Serialize for Multihash<SIZE> {
46    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
47    where
48        S: Serializer,
49    {
50        let mut buffer = Buffer::<MAXIMUM_PREFIX_SIZE, SIZE>::new();
51        let bytes_written = self
52            .write(buffer.as_mut_slice())
53            .map_err(|_| ser::Error::custom("Failed to serialize Multihash"))?;
54        serializer.serialize_bytes(&buffer.as_slice()[..bytes_written])
55    }
56}
57
58struct BytesVisitor<const SIZE: usize>;
59
60impl<'de, const SIZE: usize> Visitor<'de> for BytesVisitor<SIZE> {
61    type Value = Multihash<SIZE>;
62
63    fn expecting(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
64        write!(fmt, "a valid Multihash in bytes")
65    }
66
67    fn visit_bytes<E>(self, bytes: &[u8]) -> Result<Self::Value, E>
68    where
69        E: de::Error,
70    {
71        Multihash::<SIZE>::from_bytes(bytes)
72            .map_err(|_| de::Error::custom("Failed to deserialize Multihash"))
73    }
74
75    // Some Serde data formats interpret a byte stream as a sequence of bytes (e.g. `serde_json`).
76    fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
77    where
78        A: SeqAccess<'de>,
79    {
80        let mut buffer = Buffer::<MAXIMUM_PREFIX_SIZE, SIZE>::new();
81        let bytes = buffer.as_mut_slice();
82
83        // Fill the bytes slices with the given sequence
84        let mut pos = 0;
85        while let Some(byte) = seq.next_element()? {
86            bytes[pos] = byte;
87            pos += 1;
88            if pos >= bytes.len() {
89                return Err(de::Error::custom("Failed to deserialize Multihash"));
90            }
91        }
92
93        Multihash::<SIZE>::from_bytes(&bytes[..pos])
94            .map_err(|_| de::Error::custom("Failed to deserialize Multihash"))
95    }
96}
97
98impl<'de, const SIZE: usize> Deserialize<'de> for Multihash<SIZE> {
99    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
100    where
101        D: Deserializer<'de>,
102    {
103        deserializer.deserialize_bytes(BytesVisitor)
104    }
105}
106
107#[cfg(test)]
108mod tests {
109    use super::*;
110
111    use std::ptr;
112
113    use serde_test::{assert_tokens, Token};
114
115    const SHA2_256_CODE: u64 = 0x12;
116    const DIGEST: [u8; 32] = [
117        159, 228, 204, 198, 222, 22, 114, 79, 58, 48, 199, 232, 242, 84, 243, 198, 71, 25, 134,
118        172, 177, 248, 216, 207, 142, 150, 206, 42, 215, 219, 231, 251,
119    ];
120
121    #[test]
122    fn test_serde_json() {
123        // This is a concatenation of `SHA2_256_CODE + DIGEST_LENGTH + DIGEST`.
124        let expected_json = format!("[{},{},159,228,204,198,222,22,114,79,58,48,199,232,242,84,243,198,71,25,134,172,177,248,216,207,142,150,206,42,215,219,231,251]", SHA2_256_CODE as u8, DIGEST.len() as u8);
125
126        let mh = Multihash::<32>::wrap(SHA2_256_CODE, &DIGEST).unwrap();
127
128        let json = serde_json::to_string(&mh).unwrap();
129        assert_eq!(json, expected_json);
130
131        let mh_decoded: Multihash<32> = serde_json::from_str(&json).unwrap();
132        assert_eq!(mh, mh_decoded);
133    }
134
135    #[test]
136    fn test_serde_test() {
137        // This is a concatenation of `SHA2_256_CODE + DIGEST_LENGTH + DIGEST`.
138        const ENCODED_MULTIHASH_BYTES: [u8; 34] = [
139            SHA2_256_CODE as u8,
140            DIGEST.len() as u8,
141            159,
142            228,
143            204,
144            198,
145            222,
146            22,
147            114,
148            79,
149            58,
150            48,
151            199,
152            232,
153            242,
154            84,
155            243,
156            198,
157            71,
158            25,
159            134,
160            172,
161            177,
162            248,
163            216,
164            207,
165            142,
166            150,
167            206,
168            42,
169            215,
170            219,
171            231,
172            251,
173        ];
174
175        let mh = Multihash::<32>::wrap(SHA2_256_CODE, &DIGEST).unwrap();
176
177        // As bytes.
178        assert_tokens(&mh, &[Token::Bytes(&ENCODED_MULTIHASH_BYTES)]);
179
180        // As sequence.
181        serde_test::assert_de_tokens(
182            &mh,
183            &[
184                Token::Seq { len: Some(34) },
185                Token::U8(SHA2_256_CODE as u8),
186                Token::U8(DIGEST.len() as u8),
187                Token::U8(159),
188                Token::U8(228),
189                Token::U8(204),
190                Token::U8(198),
191                Token::U8(222),
192                Token::U8(22),
193                Token::U8(114),
194                Token::U8(79),
195                Token::U8(58),
196                Token::U8(48),
197                Token::U8(199),
198                Token::U8(232),
199                Token::U8(242),
200                Token::U8(84),
201                Token::U8(243),
202                Token::U8(198),
203                Token::U8(71),
204                Token::U8(25),
205                Token::U8(134),
206                Token::U8(172),
207                Token::U8(177),
208                Token::U8(248),
209                Token::U8(216),
210                Token::U8(207),
211                Token::U8(142),
212                Token::U8(150),
213                Token::U8(206),
214                Token::U8(42),
215                Token::U8(215),
216                Token::U8(219),
217                Token::U8(231),
218                Token::U8(251),
219                Token::SeqEnd,
220            ],
221        );
222    }
223
224    #[test]
225    fn test_buffer_alignment() {
226        const SIZE_FIRST: usize = 11;
227        const SIZE_SECOND: usize = 13;
228        let buffer = Buffer::<SIZE_FIRST, SIZE_SECOND>::new();
229
230        // Make sure that the struct allocated continuous memory, as we exploit that fact with the
231        // `as_slice` and `as_mut_slice()` methods.
232        let start_first = ptr::addr_of!(buffer.first) as *const u8;
233        let start_second = ptr::addr_of!(buffer.second) as *const u8;
234        #[allow(unsafe_code)]
235        unsafe {
236            assert_eq!(start_second.offset_from(start_first), SIZE_FIRST as isize);
237        };
238    }
239
240    #[test]
241    fn test_buffer() {
242        const SIZE_FIRST: usize = 3;
243        const SIZE_SECOND: usize = 8;
244        let mut buffer = Buffer::<SIZE_FIRST, SIZE_SECOND>::new();
245
246        let data: [u8; SIZE_FIRST + SIZE_SECOND] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
247        buffer.as_mut_slice().copy_from_slice(&data);
248        assert_eq!(buffer.as_slice(), data);
249    }
250}