Skip to content

Commit c24810c

Browse files
committed
feat: create Multihash that matches the code table
Instead of only export the `Multihash` that is generic over the allocated size, also expose `Multihash` that is created by the `Multihash` derive. If the `multihash-impl` feature is enabled, also a `Multihash` with the corresponding size gets exported. BREAKING CHANGE: The `Multihash` which is generic over the size is now called `MultihashGeneric`.
1 parent 6b1d40f commit c24810c

File tree

7 files changed

+42
-35
lines changed

7 files changed

+42
-35
lines changed

derive/src/lib.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
//! This proc macro derives a custom Multihash code table from a list of hashers.
1+
//! This proc macro derives a custom Multihash code table from a list of hashers. It also
2+
//! generates a public type called `Multihash` which corresponds to the specified `alloc_size`.
23
//!
34
//! The digests are stack allocated with a fixed size. That size needs to be big enough to hold any
45
//! of the specified hash digests. This cannot be determined reliably on compile-time, hence it

derive/src/multihash.rs

Lines changed: 17 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,6 @@ impl Parse for DeriveAttr {
6060
}
6161

6262
struct Params {
63-
mh_crate: syn::Ident,
6463
code_enum: syn::Ident,
6564
}
6665

@@ -86,14 +85,13 @@ impl Hash {
8685
quote!(#code => Ok(Self::#ident))
8786
}
8887

89-
fn code_digest(&self, params: &Params) -> TokenStream {
88+
fn code_digest(&self) -> TokenStream {
9089
let ident = &self.ident;
9190
let hasher = &self.hasher;
9291
let code = &self.code;
93-
let mh_crate = &params.mh_crate;
9492
quote!(Self::#ident => {
9593
let digest = #hasher::digest(input);
96-
#mh_crate::Multihash::wrap(#code, &digest.as_ref()).unwrap()
94+
Multihash::wrap(#code, &digest.as_ref()).unwrap()
9795
})
9896
}
9997

@@ -328,34 +326,36 @@ pub fn multihash(s: Structure) -> TokenStream {
328326
}
329327

330328
let params = Params {
331-
mh_crate: mh_crate.clone(),
332329
code_enum: code_enum.clone(),
333330
};
334331

335332
let code_into_u64 = hashes.iter().map(|h| h.code_into_u64(&params));
336333
let code_from_u64 = hashes.iter().map(|h| h.code_from_u64());
337-
let code_digest = hashes.iter().map(|h| h.code_digest(&params));
334+
let code_digest = hashes.iter().map(|h| h.code_digest());
338335
let from_digest = hashes.iter().map(|h| h.from_digest(&params));
339336

340337
quote! {
338+
/// A Multihash with the same allocated size as the Multihashes produces by this derive.
339+
pub type Multihash = #mh_crate::MultihashGeneric::<#alloc_size>;
340+
341341
impl #mh_crate::MultihashDigest for #code_enum {
342342
type AllocSize = #alloc_size;
343343

344-
fn digest(&self, input: &[u8]) -> #mh_crate::Multihash<Self::AllocSize> {
344+
fn digest(&self, input: &[u8]) -> Multihash {
345345
use #mh_crate::Hasher;
346346
match self {
347347
#(#code_digest,)*
348348
}
349349
}
350350

351-
fn multihash_from_digest<'a, S, D>(digest: &'a D) -> #mh_crate::Multihash<Self::AllocSize>
351+
fn multihash_from_digest<'a, S, D>(digest: &'a D) -> Multihash
352352
where
353353
S: #mh_crate::Size,
354354
D: #mh_crate::Digest<S>,
355355
Self: From<&'a D>,
356356
{
357357
let code = Self::from(&digest);
358-
#mh_crate::Multihash::wrap(code.into(), &digest.as_ref()).unwrap()
358+
Multihash::wrap(code.into(), &digest.as_ref()).unwrap()
359359
}
360360
}
361361

@@ -400,31 +400,34 @@ mod tests {
400400
}
401401
};
402402
let expected = quote! {
403+
/// A Multihash with the same allocated size as the Multihashes produces by this derive.
404+
pub type Multihash = multihash::MultihashGeneric::<U32>;
405+
403406
impl multihash::MultihashDigest for Code {
404407
type AllocSize = U32;
405408

406-
fn digest(&self, input: &[u8]) -> multihash::Multihash<Self::AllocSize> {
409+
fn digest(&self, input: &[u8]) -> Multihash {
407410
use multihash::Hasher;
408411
match self {
409412
Self::Identity256 => {
410413
let digest = multihash::Identity256::digest(input);
411-
multihash::Multihash::wrap(multihash::IDENTITY, &digest.as_ref()).unwrap()
414+
Multihash::wrap(multihash::IDENTITY, &digest.as_ref()).unwrap()
412415
},
413416
Self::Strobe256 => {
414417
let digest = multihash::Strobe256::digest(input);
415-
multihash::Multihash::wrap(0x38b64f, &digest.as_ref()).unwrap()
418+
Multihash::wrap(0x38b64f, &digest.as_ref()).unwrap()
416419
},
417420
}
418421
}
419422

420-
fn multihash_from_digest<'a, S, D>(digest: &'a D) -> multihash::Multihash<Self::AllocSize>
423+
fn multihash_from_digest<'a, S, D>(digest: &'a D) -> Multihash
421424
where
422425
S: multihash::Size,
423426
D: multihash::Digest<S>,
424427
Self: From<&'a D>,
425428
{
426429
let code = Self::from(&digest);
427-
multihash::Multihash::wrap(code.into(), &digest.as_ref()).unwrap()
430+
Multihash::wrap(code.into(), &digest.as_ref()).unwrap()
428431
}
429432
}
430433

examples/custom_table.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@ use std::convert::TryFrom;
33
use multihash::derive::Multihash;
44
use multihash::typenum::{U20, U25, U64};
55
use multihash::{
6-
Digest, Error, Hasher, Multihash, MultihashDigest, Sha2Digest, Sha2_256, Size, StatefulHasher,
6+
Digest, Error, Hasher, MultihashDigest, MultihashGeneric, Sha2Digest, Sha2_256, Size,
7+
StatefulHasher,
78
};
89

910
// You can implement a custom hasher. This is a SHA2 256-bit hasher that returns a hash that is
@@ -48,7 +49,7 @@ fn main() {
4849
// Sometimes you might not need to hash new data, you just want to get the information about
4950
// a Multihash.
5051
let truncated_sha2_bytes = truncated_sha2_hash.to_bytes();
51-
let unknown_hash = Multihash::<U64>::from_bytes(&truncated_sha2_bytes).unwrap();
52+
let unknown_hash = Multihash::from_bytes(&truncated_sha2_bytes).unwrap();
5253
println!("SHA2 256-bit hash truncated to 160 bits:");
5354
println!(" code: {:x?}", unknown_hash.code());
5455
println!(" size: {}", unknown_hash.size());

src/arb.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,10 @@ use rand::{
44
Rng,
55
};
66

7-
use crate::{Multihash, U64};
7+
use crate::{MultihashGeneric, U64};
88

99
/// Generates a random valid multihash.
10-
impl Arbitrary for Multihash<U64> {
10+
impl Arbitrary for MultihashGeneric<U64> {
1111
fn arbitrary<G: Gen>(g: &mut G) -> Self {
1212
// In real world lower multihash codes are more likely to happen, hence distribute them
1313
// with bias towards smaller values.
@@ -29,6 +29,6 @@ impl Arbitrary for Multihash<U64> {
2929
let size = g.gen_range(0, 64);
3030
let mut data = [0; 64];
3131
g.fill_bytes(&mut data);
32-
Multihash::wrap(code, &data[..size]).unwrap()
32+
MultihashGeneric::wrap(code, &data[..size]).unwrap()
3333
}
3434
}

src/lib.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -65,13 +65,13 @@ pub use crate::error::{Error, Result};
6565
#[cfg(feature = "std")]
6666
pub use crate::hasher::WriteHasher;
6767
pub use crate::hasher::{Digest, Hasher, Size, StatefulHasher};
68-
pub use crate::multihash::{Multihash, MultihashDigest};
68+
pub use crate::multihash::{Multihash as MultihashGeneric, MultihashDigest};
6969
pub use generic_array::typenum::{self, U128, U16, U20, U28, U32, U48, U64};
7070
#[cfg(feature = "derive")]
7171
pub use multihash_derive as derive;
7272

7373
#[cfg(feature = "multihash-impl")]
74-
pub use crate::multihash_impl::Code;
74+
pub use crate::multihash_impl::{Code, Multihash};
7575

7676
#[cfg(feature = "blake2b")]
7777
pub use crate::hasher_impl::blake2b::{Blake2b256, Blake2b512, Blake2bDigest, Blake2bHasher};

src/multihash.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ pub trait MultihashDigest:
4242
/// let hash = Code::multihash_from_digest(&hasher.finalize());
4343
/// println!("{:02x?}", hash);
4444
/// ```
45+
#[allow(clippy::needless_lifetimes)]
4546
fn multihash_from_digest<'a, S, D>(digest: &'a D) -> Multihash<Self::AllocSize>
4647
where
4748
S: Size,
@@ -57,15 +58,15 @@ pub trait MultihashDigest:
5758
/// # Example
5859
///
5960
/// ```
60-
/// use multihash::{Multihash, U64};
61+
/// use multihash::Multihash;
6162
///
6263
/// const Sha3_256: u64 = 0x16;
6364
/// let digest_bytes = [
6465
/// 0x16, 0x20, 0x64, 0x4b, 0xcc, 0x7e, 0x56, 0x43, 0x73, 0x04, 0x09, 0x99, 0xaa, 0xc8, 0x9e,
6566
/// 0x76, 0x22, 0xf3, 0xca, 0x71, 0xfb, 0xa1, 0xd9, 0x72, 0xfd, 0x94, 0xa3, 0x1c, 0x3b, 0xfb,
6667
/// 0xf2, 0x4e, 0x39, 0x38,
6768
/// ];
68-
/// let mh = Multihash::<U64>::from_bytes(&digest_bytes).unwrap();
69+
/// let mh = Multihash::from_bytes(&digest_bytes).unwrap();
6970
/// assert_eq!(mh.code(), Sha3_256);
7071
/// assert_eq!(mh.size(), 32);
7172
/// assert_eq!(mh.digest(), &digest_bytes[2..]);

tests/lib.rs

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,10 @@ use std::io::Cursor;
33
use multihash::{
44
derive::Multihash, Blake2b256, Blake2b512, Blake2bDigest, Blake2s128, Blake2s256,
55
Blake2sDigest, Blake3Digest, Blake3_256, Digest, Error, Hasher, Identity256, IdentityDigest,
6-
Keccak224, Keccak256, Keccak384, Keccak512, KeccakDigest, Multihash, MultihashDigest, Sha1,
7-
Sha1Digest, Sha2Digest, Sha2_256, Sha2_512, Sha3Digest, Sha3_224, Sha3_256, Sha3_384, Sha3_512,
8-
Size, StatefulHasher, Strobe256, Strobe512, StrobeDigest, U16, U20, U28, U32, U48, U64,
6+
Keccak224, Keccak256, Keccak384, Keccak512, KeccakDigest, MultihashDigest, MultihashGeneric,
7+
Sha1, Sha1Digest, Sha2Digest, Sha2_256, Sha2_512, Sha3Digest, Sha3_224, Sha3_256, Sha3_384,
8+
Sha3_512, Size, StatefulHasher, Strobe256, Strobe512, StrobeDigest, U16, U20, U28, U32, U48,
9+
U64,
910
};
1011

1112
#[derive(Clone, Copy, Debug, Eq, Multihash, PartialEq)]
@@ -113,7 +114,7 @@ macro_rules! assert_decode {
113114
$(
114115
let hash = hex::decode($hash).unwrap();
115116
assert_eq!(
116-
Multihash::<U64>::from_bytes(&hash).unwrap().code(),
117+
Multihash::from_bytes(&hash).unwrap().code(),
117118
u64::from($code),
118119
"{:?} decodes correctly", stringify!($code)
119120
);
@@ -152,7 +153,7 @@ macro_rules! assert_roundtrip {
152153
{
153154
let hash = $code.digest(b"helloworld");
154155
assert_eq!(
155-
Multihash::<U64>::from_bytes(&hash.to_bytes()).unwrap().code(),
156+
Multihash::from_bytes(&hash.to_bytes()).unwrap().code(),
156157
hash.code()
157158
);
158159
}
@@ -162,7 +163,7 @@ macro_rules! assert_roundtrip {
162163
hasher.update(b"helloworld");
163164
let hash = Code::multihash_from_digest(&hasher.finalize());
164165
assert_eq!(
165-
Multihash::<U64>::from_bytes(&hash.to_bytes()).unwrap().code(),
166+
Multihash::from_bytes(&hash.to_bytes()).unwrap().code(),
166167
hash.code()
167168
);
168169
}
@@ -313,25 +314,25 @@ fn test_long_identity_hash() {
313314
#[test]
314315
fn multihash_errors() {
315316
assert!(
316-
Multihash::<U64>::from_bytes(&[]).is_err(),
317+
Multihash::from_bytes(&[]).is_err(),
317318
"Should error on empty data"
318319
);
319320
assert!(
320-
Multihash::<U64>::from_bytes(&[1, 2, 3]).is_err(),
321+
Multihash::from_bytes(&[1, 2, 3]).is_err(),
321322
"Should error on invalid multihash"
322323
);
323324
assert!(
324-
Multihash::<U64>::from_bytes(&[1, 2, 3]).is_err(),
325+
Multihash::from_bytes(&[1, 2, 3]).is_err(),
325326
"Should error on invalid prefix"
326327
);
327328
assert!(
328-
Multihash::<U64>::from_bytes(&[0x12, 0x20, 0xff]).is_err(),
329+
Multihash::from_bytes(&[0x12, 0x20, 0xff]).is_err(),
329330
"Should error on correct prefix with wrong digest"
330331
);
331332
let identity_code: u8 = 0x00;
332333
let identity_length = 3;
333334
assert!(
334-
Multihash::<U64>::from_bytes(&[identity_code, identity_length, 1, 2, 3, 4]).is_err(),
335+
Multihash::from_bytes(&[identity_code, identity_length, 1, 2, 3, 4]).is_err(),
335336
"Should error on wrong hash length"
336337
);
337338
}

0 commit comments

Comments
 (0)