Skip to content

Commit aab78df

Browse files
Introduce multihash-derive-impl crate
1 parent 2a96940 commit aab78df

File tree

18 files changed

+170
-110
lines changed

18 files changed

+170
-110
lines changed

Cargo.toml

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
[workspace]
2-
members = ["derive", ".", "codetable"]
2+
members = ["derive", "derive-impl", ".", "codetable"]
33

44
[package]
55
name = "multihash"
@@ -38,3 +38,4 @@ hex = "0.4.2"
3838
serde_json = "1.0.58"
3939
quickcheck = "1.0.3"
4040
arbitrary = "1.1.0"
41+
rand = { version = "0.8.5", features = ["small_rng"] }

codetable/Cargo.toml

-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@ sha-3 = { version = "0.10.0", default-features = false, package = "sha3" }
1616
strobe-rs = { version = "0.7.0", default-features = false }
1717
ripemd-rs = { package = "ripemd", version = "0.1.1"}
1818
multihash-derive = { version = "0.8.0", path = "../derive", default-features = false }
19-
multihash = { version = "0.18.0", path = "../" }
2019

2120
[dev-dependencies]
2221
hex = "0.4.2"

codetable/benches/multihash.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
use criterion::{black_box, criterion_group, criterion_main, Criterion};
2-
use multihash::Hasher;
32
use multihash_codetable::{
43
Blake2b256, Blake2b512, Blake2s128, Blake2s256, Blake3_256, Keccak224, Keccak256, Keccak384,
54
Keccak512, Sha1, Sha2_256, Sha2_512, Sha3_224, Sha3_256, Sha3_384, Sha3_512, Strobe256,
65
Strobe512,
76
};
7+
use multihash_derive::Hasher;
88
use rand::Rng;
99

1010
macro_rules! group_digest {

codetable/examples/custom_table.rs

+1-2
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
11
use std::convert::TryFrom;
22

3-
use multihash::{Hasher, MultihashDigest as _};
43
use multihash_codetable::Sha2_256;
5-
use multihash_derive::MultihashDigest;
4+
use multihash_derive::{Hasher, MultihashDigest};
65

76
// You can implement a custom hasher. This is a SHA2 256-bit hasher that returns a hash that is
87
// truncated to 160 bits.

codetable/examples/manual_mh.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
use multihash::MultihashDigest;
21
use multihash_codetable::Code;
2+
use multihash_derive::MultihashDigest;
33

44
/// prefix/multihash generating tool to aid when adding new tests
55
fn prefix_util() {

codetable/src/hasher_impl.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use multihash::Hasher;
1+
use multihash_derive::Hasher;
22

33
use std::io;
44

@@ -153,7 +153,7 @@ macro_rules! derive_rustcrypto_hasher {
153153
}
154154
}
155155

156-
impl ::multihash::Hasher for $name {
156+
impl ::multihash_derive::Hasher for $name {
157157
fn update(&mut self, input: &[u8]) {
158158
use digest::Digest;
159159
self.state.update(input)

codetable/src/lib.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -88,8 +88,8 @@ pub enum Code {
8888
mod tests {
8989
use super::*;
9090
use crate::hasher_impl::sha3::{Sha3_256, Sha3_512};
91-
use multihash::MultihashDigest;
92-
use multihash::{Hasher, Multihash};
91+
use multihash_derive::MultihashDigest;
92+
use multihash_derive::{Hasher, Multihash};
9393

9494
#[test]
9595
fn test_hasher_256() {

codetable/tests/lib.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
use std::io::{Cursor, Write};
22

3-
use multihash::{Hasher, MultihashDigest};
43
use multihash_codetable::{
54
Blake2b256, Blake2b512, Blake2s128, Blake2s256, Blake3_256, Identity256, Keccak224, Keccak256,
65
Keccak384, Keccak512, Sha1, Sha2_256, Sha2_512, Sha3_224, Sha3_256, Sha3_384, Sha3_512,
76
Strobe256, Strobe512,
87
};
8+
use multihash_derive::{Hasher, MultihashDigest};
99

1010
#[derive(Clone, Copy, Debug, Eq, multihash_derive::MultihashDigest, PartialEq)]
1111
#[mh(alloc_size = 64)]
@@ -386,8 +386,8 @@ fn multihash_errors() {
386386

387387
#[test]
388388
fn blak3_non_default_digest() {
389-
use multihash::MultihashDigest;
390389
use multihash_codetable::Blake3Hasher;
390+
use multihash_derive::MultihashDigest;
391391
const DIGEST_SIZE: usize = 16;
392392
pub struct ContentHasher(Blake3Hasher<DIGEST_SIZE>);
393393

derive-impl/Cargo.toml

+28
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
[package]
2+
name = "multihash-derive-impl"
3+
version = "0.1.0"
4+
authors = ["David Craven <[email protected]>"]
5+
edition = "2018"
6+
description = "Proc macro for deriving custom multihash tables."
7+
license = "MIT"
8+
repository = "https://github.com/multiformats/multihash"
9+
resolver = "2"
10+
11+
[lib]
12+
proc-macro = true
13+
14+
[dependencies]
15+
proc-macro2 = { version = "1.0.24", features = ["span-locations"] }
16+
proc-macro-crate = "~1.1.0"
17+
proc-macro-error = "1.0.4"
18+
quote = "1.0.7"
19+
syn = "1.0.42"
20+
synstructure = "0.12.4"
21+
22+
[features]
23+
default = ["std"]
24+
std = []
25+
26+
[dev-dependencies]
27+
pretty_assertions = "1.0.0"
28+
#multihash = { path = "..", default-features = false, features = ["derive", "sha2"] }

derive-impl/src/lib.rs

+66
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
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`.
3+
//!
4+
//! The digests are stack allocated with a fixed size. That size needs to be big enough to hold any
5+
//! of the specified hash digests. This cannot be determined reliably on compile-time, hence it
6+
//! needs to set manually via the `alloc_size` attribute. Also you might want to set it to bigger
7+
//! sizes then necessarily needed for backwards/forward compatibility.
8+
//!
9+
//! If you set `#mh(alloc_size = …)` to a too low value, you will get compiler errors. Please note
10+
//! the the sizes are checked only on a syntactic level and *not* on the type level. This means
11+
//! that digest need to have a size const generic, which is a valid `usize`, for example `32` or
12+
//! `64`.
13+
//!
14+
//! You can disable those compiler errors with setting the `no_alloc_size_errors` attribute. This
15+
//! can be useful if you e.g. have specified type aliases for your hash digests and you are sure
16+
//! you use the correct value for `alloc_size`.
17+
//!
18+
//! # Example
19+
//!
20+
//! ```
21+
//! use multihash::derive::Multihash;
22+
//! use multihash::MultihashDigest;
23+
//!
24+
//! #[derive(Clone, Copy, Debug, Eq, Multihash, PartialEq)]
25+
//! #[mh(alloc_size = 64)]
26+
//! pub enum Code {
27+
//! #[mh(code = 0x01, hasher = multihash::Sha2_256)]
28+
//! Foo,
29+
//! #[mh(code = 0x02, hasher = multihash::Sha2_512)]
30+
//! Bar,
31+
//! }
32+
//!
33+
//! let hash = Code::Foo.digest(b"hello world!");
34+
//! println!("{:02x?}", hash);
35+
//! ```
36+
extern crate proc_macro;
37+
38+
mod multihash;
39+
mod utils;
40+
41+
use proc_macro::TokenStream;
42+
use proc_macro_error::proc_macro_error;
43+
use synstructure::macros::{parse, DeriveInput};
44+
use synstructure::{MacroResult, Structure};
45+
46+
#[proc_macro_derive(Multihash, attributes(mh))]
47+
#[allow(non_snake_case)]
48+
#[proc_macro_error]
49+
#[deprecated(since = "0.8.1", note = "Use `MultihashDigest` derive instead.")]
50+
pub fn Multihash(i: TokenStream) -> TokenStream {
51+
match parse::<DeriveInput>(i) {
52+
Ok(p) => match Structure::try_new(&p) {
53+
Ok(s) => multihash::multihash(s).into_stream(),
54+
Err(e) => e.to_compile_error().into(),
55+
},
56+
Err(e) => e.to_compile_error().into(),
57+
}
58+
}
59+
60+
#[proc_macro_derive(MultihashDigest, attributes(mh))]
61+
#[allow(non_snake_case)]
62+
#[proc_macro_error]
63+
pub fn MultihashDigest(i: TokenStream) -> TokenStream {
64+
#[allow(deprecated)]
65+
Multihash(i)
66+
}

derive/src/multihash.rs renamed to derive-impl/src/multihash.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -198,7 +198,7 @@ fn error_code_duplicates(hashes: &[Hash]) {
198198
struct ParseError(Span);
199199

200200
pub fn multihash(s: Structure) -> TokenStream {
201-
let mh_crate = match utils::use_crate("multihash") {
201+
let mh_crate = match utils::use_crate("multihash-derive") {
202202
Ok(ident) => ident,
203203
Err(e) => {
204204
let err = syn::Error::new(Span::call_site(), e).to_compile_error();
@@ -247,12 +247,12 @@ pub fn multihash(s: Structure) -> TokenStream {
247247
}
248248

249249
impl core::convert::TryFrom<u64> for #code_enum {
250-
type Error = #mh_crate::Error;
250+
type Error = #mh_crate::UnsupportedCode;
251251

252252
fn try_from(code: u64) -> Result<Self, Self::Error> {
253253
match code {
254254
#(#code_from_u64,)*
255-
_ => Err(#mh_crate::Error::unsupported_code(code))
255+
_ => Err(#mh_crate::UnsupportedCode(code))
256256
}
257257
}
258258
}
File renamed without changes.

derive/Cargo.toml

+2-17
Original file line numberDiff line numberDiff line change
@@ -8,21 +8,6 @@ license = "MIT"
88
repository = "https://github.com/multiformats/multihash"
99
resolver = "2"
1010

11-
[lib]
12-
proc-macro = true
13-
1411
[dependencies]
15-
proc-macro2 = { version = "1.0.24", features = ["span-locations"] }
16-
proc-macro-crate = "~1.1.0"
17-
proc-macro-error = "1.0.4"
18-
quote = "1.0.7"
19-
syn = "1.0.42"
20-
synstructure = "0.12.4"
21-
22-
[features]
23-
default = ["std"]
24-
std = []
25-
26-
[dev-dependencies]
27-
pretty_assertions = "1.0.0"
28-
#multihash = { path = "..", default-features = false, features = ["derive", "sha2"] }
12+
multihash-derive-impl = { version = "0.1.0", path = "../derive-impl" }
13+
multihash = { version = "0.18.0", path = "../" }
File renamed without changes.

derive/src/lib.rs

+59-24
Original file line numberDiff line numberDiff line change
@@ -33,34 +33,69 @@
3333
//! let hash = Code::Foo.digest(b"hello world!");
3434
//! println!("{:02x?}", hash);
3535
//! ```
36-
extern crate proc_macro;
3736
38-
mod multihash;
39-
mod utils;
37+
mod hasher;
4038

41-
use proc_macro::TokenStream;
42-
use proc_macro_error::proc_macro_error;
43-
use synstructure::macros::{parse, DeriveInput};
44-
use synstructure::{MacroResult, Structure};
39+
use std::convert::TryFrom;
40+
use std::fmt;
4541

46-
#[proc_macro_derive(Multihash, attributes(mh))]
47-
#[allow(non_snake_case)]
48-
#[proc_macro_error]
49-
#[deprecated(since = "0.8.1", note = "Use `MultihashDigest` derive instead.")]
50-
pub fn Multihash(i: TokenStream) -> TokenStream {
51-
match parse::<DeriveInput>(i) {
52-
Ok(p) => match Structure::try_new(&p) {
53-
Ok(s) => multihash::multihash(s).into_stream(),
54-
Err(e) => e.to_compile_error().into(),
55-
},
56-
Err(e) => e.to_compile_error().into(),
42+
pub use hasher::Hasher;
43+
pub use multihash_derive_impl::MultihashDigest;
44+
45+
pub use multihash::*;
46+
47+
/// The given code is not supported by this codetable.
48+
#[derive(Debug)]
49+
pub struct UnsupportedCode(pub u64);
50+
51+
impl fmt::Display for UnsupportedCode {
52+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
53+
write!(f, "the code {} is not supported by this codetable", self.0)
5754
}
5855
}
5956

60-
#[proc_macro_derive(MultihashDigest, attributes(mh))]
61-
#[allow(non_snake_case)]
62-
#[proc_macro_error]
63-
pub fn MultihashDigest(i: TokenStream) -> TokenStream {
64-
#[allow(deprecated)]
65-
Multihash(i)
57+
impl std::error::Error for UnsupportedCode {}
58+
59+
/// Trait that implements hashing.
60+
///
61+
/// It is usually implemented by a custom code table enum that derives the [`Multihash` derive].
62+
///
63+
/// [`Multihash` derive]: crate::derive
64+
pub trait MultihashDigest<const S: usize>:
65+
TryFrom<u64, Error = UnsupportedCode>
66+
+ Into<u64>
67+
+ Send
68+
+ Sync
69+
+ Unpin
70+
+ Copy
71+
+ Eq
72+
+ fmt::Debug
73+
+ 'static
74+
{
75+
/// Calculate the hash of some input data.
76+
///
77+
/// # Example
78+
///
79+
/// ```
80+
/// // `Code` implements `MultihashDigest`
81+
/// use multihash::{Code, MultihashDigest};
82+
///
83+
/// let hash = Code::Sha3_256.digest(b"Hello world!");
84+
/// println!("{:02x?}", hash);
85+
/// ```
86+
fn digest(&self, input: &[u8]) -> Multihash<S>;
87+
88+
/// Create a multihash from an existing multihash digest.
89+
///
90+
/// # Example
91+
///
92+
/// ```
93+
/// use multihash::{Code, Hasher, MultihashDigest, Sha3_256};
94+
///
95+
/// let mut hasher = Sha3_256::default();
96+
/// hasher.update(b"Hello world!");
97+
/// let hash = Code::Sha3_256.wrap(&hasher.finalize()).unwrap();
98+
/// println!("{:02x?}", hash);
99+
/// ```
100+
fn wrap(&self, digest: &[u8]) -> std::result::Result<Multihash<S>, multihash::Error>;
66101
}

src/error.rs

-12
Original file line numberDiff line numberDiff line change
@@ -12,14 +12,6 @@ pub struct Error {
1212
}
1313

1414
impl Error {
15-
/// The specified code is not supported by code table.
16-
/// FIXME: This should not be in our public API because it is only needed by the custom derive which we have no knowledge of in this crate.
17-
pub fn unsupported_code(code: u64) -> Self {
18-
Self {
19-
kind: Kind::UnsupportedCode(code),
20-
}
21-
}
22-
2315
pub(crate) const fn invalid_size(size: u64) -> Self {
2416
Self {
2517
kind: Kind::InvalidSize(size),
@@ -51,8 +43,6 @@ impl core::fmt::Display for Error {
5143
enum Kind {
5244
/// Io error.
5345
Io(io::Error),
54-
/// Unsupported multihash code.
55-
UnsupportedCode(u64),
5646
/// Invalid multihash size.
5747
InvalidSize(u64),
5848
/// Invalid varint.
@@ -80,7 +70,6 @@ impl core::fmt::Display for Kind {
8070
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
8171
match self {
8272
Self::Io(err) => write!(f, "{err}"),
83-
Self::UnsupportedCode(code) => write!(f, "Unsupported multihash code {code}."),
8473
Self::InvalidSize(size) => write!(f, "Invalid multihash size {size}."),
8574
Self::Varint(err) => write!(f, "{err}"),
8675
}
@@ -91,7 +80,6 @@ impl StdError for Error {
9180
fn source(&self) -> Option<&(dyn StdError + 'static)> {
9281
match &self.kind {
9382
Kind::Io(inner) => Some(inner),
94-
Kind::UnsupportedCode(_) => None,
9583
Kind::InvalidSize(_) => None,
9684
Kind::Varint(_) => None, // FIXME: Does not implement `core2::Error`.
9785
}

src/lib.rs

+1-5
Original file line numberDiff line numberDiff line change
@@ -59,18 +59,14 @@ extern crate core;
5959
#[cfg(any(test, feature = "arb"))]
6060
mod arb;
6161
mod error;
62-
mod hasher;
6362
mod multihash;
6463

6564
/// Multihash result.
6665
#[deprecated(note = "Use `Result<T, multihash::Error>` instead")]
6766
pub type Result<T> = core::result::Result<T, Error>;
6867

6968
pub use crate::error::Error;
70-
pub use crate::multihash::{Multihash, MultihashDigest};
71-
pub use hasher::Hasher;
72-
#[cfg(feature = "derive")]
73-
pub use multihash_derive as derive;
69+
pub use crate::multihash::Multihash;
7470

7571
/// Deprecated type-alias for the [`Multihash`] type.
7672
#[deprecated(since = "0.18.0", note = "Use `multihash::Multihash instead.")]

0 commit comments

Comments
 (0)