ipld_nostd/multihash/
serde.rs

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