1use crate::Error;
2#[cfg(feature = "alloc")]
3use alloc::vec::Vec;
4
5use core::convert::TryInto;
6use core::fmt::Debug;
7
8use unsigned_varint::encode as varint_encode;
9
10#[cfg(feature = "std")]
11use std::io;
12
13#[cfg(not(feature = "std"))]
14use core2::io;
15
16#[derive(Clone, Copy, Debug, Eq, Ord, PartialOrd)]
38pub struct Multihash<const S: usize> {
39 code: u64,
41 size: u8,
43 digest: [u8; S],
45}
46
47impl<const S: usize> Default for Multihash<S> {
48 fn default() -> Self {
49 Self {
50 code: 0,
51 size: 0,
52 digest: [0; S],
53 }
54 }
55}
56
57impl<const S: usize> Multihash<S> {
58 pub const fn wrap(code: u64, input_digest: &[u8]) -> Result<Self, Error> {
60 if input_digest.len() > S {
61 return Err(Error::invalid_size(input_digest.len() as _));
62 }
63 let size = input_digest.len();
64 let mut digest = [0; S];
65 let mut i = 0;
66 while i < size {
67 digest[i] = input_digest[i];
68 i += 1;
69 }
70 Ok(Self {
71 code,
72 size: size as u8,
73 digest,
74 })
75 }
76
77 pub const fn code(&self) -> u64 {
79 self.code
80 }
81
82 pub const fn size(&self) -> u8 {
84 self.size
85 }
86
87 pub fn digest(&self) -> &[u8] {
89 &self.digest[..self.size as usize]
90 }
91
92 pub fn read<R: io::Read>(r: R) -> Result<Self, Error>
94 where
95 Self: Sized,
96 {
97 let (code, size, digest) = read_multihash(r)?;
98 Ok(Self { code, size, digest })
99 }
100
101 pub fn from_bytes(mut bytes: &[u8]) -> Result<Self, Error>
106 where
107 Self: Sized,
108 {
109 let result = Self::read(&mut bytes)?;
110 if !bytes.is_empty() {
112 return Err(Error::invalid_size(bytes.len().try_into().expect(
113 "Currently the maximum size is 255, therefore always fits into usize",
114 )));
115 }
116
117 Ok(result)
118 }
119
120 pub fn write<W: io::Write>(&self, w: W) -> Result<usize, Error> {
122 write_multihash(w, self.code(), self.size(), self.digest())
123 }
124
125 pub fn encoded_len(&self) -> usize {
127 let mut code_buf = varint_encode::u64_buffer();
128 let code = varint_encode::u64(self.code, &mut code_buf);
129
130 let mut size_buf = varint_encode::u8_buffer();
131 let size = varint_encode::u8(self.size, &mut size_buf);
132
133 code.len() + size.len() + usize::from(self.size)
134 }
135
136 #[cfg(feature = "alloc")]
137 pub fn to_bytes(&self) -> Vec<u8> {
139 let mut bytes = Vec::with_capacity(self.size().into());
140 let written = self
141 .write(&mut bytes)
142 .expect("writing to a vec should never fail");
143 debug_assert_eq!(written, bytes.len());
144 bytes
145 }
146
147 pub fn truncate(&self, size: u8) -> Self {
152 let mut mh = *self;
153 mh.size = mh.size.min(size);
154 mh
155 }
156
157 pub fn resize<const R: usize>(&self) -> Result<Multihash<R>, Error> {
161 let size = self.size as usize;
162 if size > R {
163 return Err(Error::invalid_size(self.size as u64));
164 }
165 let mut mh = Multihash {
166 code: self.code,
167 size: self.size,
168 digest: [0; R],
169 };
170 mh.digest[..size].copy_from_slice(&self.digest[..size]);
171 Ok(mh)
172 }
173
174 pub fn into_inner(self) -> (u64, [u8; S], u8) {
178 let Self { code, digest, size } = self;
179 (code, digest, size)
180 }
181}
182
183#[allow(clippy::derived_hash_with_manual_eq)]
185impl<const S: usize> core::hash::Hash for Multihash<S> {
186 fn hash<T: core::hash::Hasher>(&self, state: &mut T) {
187 self.code.hash(state);
188 self.digest().hash(state);
189 }
190}
191
192#[cfg(feature = "alloc")]
193impl<const S: usize> From<Multihash<S>> for Vec<u8> {
194 fn from(multihash: Multihash<S>) -> Self {
195 multihash.to_bytes()
196 }
197}
198
199impl<const A: usize, const B: usize> PartialEq<Multihash<B>> for Multihash<A> {
200 fn eq(&self, other: &Multihash<B>) -> bool {
201 self.code == other.code && self.digest() == other.digest()
203 }
204}
205
206#[cfg(feature = "scale-codec")]
207impl<const S: usize> parity_scale_codec::Encode for Multihash<S> {
208 fn encode_to<EncOut: parity_scale_codec::Output + ?Sized>(&self, dest: &mut EncOut) {
209 self.code.encode_to(dest);
210 self.size.encode_to(dest);
211 dest.write(self.digest());
217 }
218}
219
220#[cfg(feature = "scale-codec")]
221impl<const S: usize> parity_scale_codec::EncodeLike for Multihash<S> {}
222
223#[cfg(feature = "scale-codec")]
224impl<const S: usize> parity_scale_codec::Decode for Multihash<S> {
225 fn decode<DecIn: parity_scale_codec::Input>(
226 input: &mut DecIn,
227 ) -> Result<Self, parity_scale_codec::Error> {
228 let mut mh = Multihash {
229 code: parity_scale_codec::Decode::decode(input)?,
230 size: parity_scale_codec::Decode::decode(input)?,
231 digest: [0; S],
232 };
233 if mh.size as usize > S {
234 return Err(parity_scale_codec::Error::from("invalid size"));
235 }
236 input.read(&mut mh.digest[..mh.size as usize])?;
238 Ok(mh)
239 }
240}
241
242fn write_multihash<W>(mut w: W, code: u64, size: u8, digest: &[u8]) -> Result<usize, Error>
244where
245 W: io::Write,
246{
247 let mut code_buf = varint_encode::u64_buffer();
248 let code = varint_encode::u64(code, &mut code_buf);
249
250 let mut size_buf = varint_encode::u8_buffer();
251 let size = varint_encode::u8(size, &mut size_buf);
252
253 let written = code.len() + size.len() + digest.len();
254
255 w.write_all(code)
256 .map_err(crate::error::io_to_multihash_error)?;
257 w.write_all(size)
258 .map_err(crate::error::io_to_multihash_error)?;
259 w.write_all(digest)
260 .map_err(crate::error::io_to_multihash_error)?;
261
262 Ok(written)
263}
264
265fn read_multihash<R, const S: usize>(mut r: R) -> Result<(u64, u8, [u8; S]), Error>
272where
273 R: io::Read,
274{
275 let code = read_u64(&mut r)?;
276 let size = read_u64(&mut r)?;
277
278 if size > S as u64 || size > u8::MAX as u64 {
279 return Err(Error::invalid_size(size));
280 }
281
282 let mut digest = [0; S];
283 r.read_exact(&mut digest[..size as usize])
284 .map_err(crate::error::io_to_multihash_error)?;
285 Ok((code, size as u8, digest))
286}
287
288#[cfg(feature = "std")]
289pub(crate) fn read_u64<R: io::Read>(r: R) -> Result<u64, Error> {
290 unsigned_varint::io::read_u64(r).map_err(crate::error::unsigned_varint_to_multihash_error)
291}
292
293#[cfg(not(feature = "std"))]
297pub(crate) fn read_u64<R: io::Read>(mut r: R) -> Result<u64, Error> {
298 use unsigned_varint::decode;
299 let mut b = varint_encode::u64_buffer();
300 for i in 0..b.len() {
301 let n = r
302 .read(&mut (b[i..i + 1]))
303 .map_err(crate::error::io_to_multihash_error)?;
304 if n == 0 {
305 return Err(Error::insufficient_varint_bytes());
306 } else if decode::is_last(b[i]) {
307 return decode::u64(&b[..=i])
308 .map(|decoded| decoded.0)
309 .map_err(crate::error::unsigned_varint_decode_to_multihash_error);
310 }
311 }
312 Err(Error::varint_overflow())
313}
314
315#[cfg(test)]
316mod tests {
317 use super::*;
318
319 #[test]
320 #[cfg(feature = "scale-codec")]
321 fn test_scale() {
322 use parity_scale_codec::{Decode, Encode};
323
324 let mh1 = Multihash::<32>::wrap(0, b"hello world").unwrap();
325 let mh1_bytes = mh1.encode();
327 let mh2: Multihash<32> = Decode::decode(&mut &mh1_bytes[..]).unwrap();
329 assert_eq!(mh1, mh2);
330
331 let mh3 = Multihash::<64>::wrap(0, b"hello world").unwrap();
332 let mh3_bytes = mh3.encode();
334 let mh4: Multihash<64> = Decode::decode(&mut &mh3_bytes[..]).unwrap();
336 assert_eq!(mh3, mh4);
337
338 assert_eq!(mh1_bytes, mh3_bytes);
339 }
340
341 #[test]
342 fn test_eq_sizes() {
343 let mh1 = Multihash::<32>::default();
344 let mh2 = Multihash::<64>::default();
345 assert_eq!(mh1, mh2);
346 }
347
348 #[test]
349 fn decode_non_minimal_error() {
350 let data = [241, 0, 0, 0, 0, 0, 128, 132, 132, 132, 58];
352 let result = read_u64(&data[..]);
353 assert!(result.is_err());
354 }
355}