Skip to content

Commit

Permalink
Introduce multihash-derive-impl crate
Browse files Browse the repository at this point in the history
  • Loading branch information
thomaseizinger committed Mar 21, 2023
1 parent 2a96940 commit aab78df
Show file tree
Hide file tree
Showing 18 changed files with 170 additions and 110 deletions.
3 changes: 2 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
[workspace]
members = ["derive", ".", "codetable"]
members = ["derive", "derive-impl", ".", "codetable"]

[package]
name = "multihash"
Expand Down Expand Up @@ -38,3 +38,4 @@ hex = "0.4.2"
serde_json = "1.0.58"
quickcheck = "1.0.3"
arbitrary = "1.1.0"
rand = { version = "0.8.5", features = ["small_rng"] }
1 change: 0 additions & 1 deletion codetable/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ sha-3 = { version = "0.10.0", default-features = false, package = "sha3" }
strobe-rs = { version = "0.7.0", default-features = false }
ripemd-rs = { package = "ripemd", version = "0.1.1"}
multihash-derive = { version = "0.8.0", path = "../derive", default-features = false }
multihash = { version = "0.18.0", path = "../" }

[dev-dependencies]
hex = "0.4.2"
Expand Down
2 changes: 1 addition & 1 deletion codetable/benches/multihash.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
use criterion::{black_box, criterion_group, criterion_main, Criterion};
use multihash::Hasher;
use multihash_codetable::{
Blake2b256, Blake2b512, Blake2s128, Blake2s256, Blake3_256, Keccak224, Keccak256, Keccak384,
Keccak512, Sha1, Sha2_256, Sha2_512, Sha3_224, Sha3_256, Sha3_384, Sha3_512, Strobe256,
Strobe512,
};
use multihash_derive::Hasher;
use rand::Rng;

macro_rules! group_digest {
Expand Down
3 changes: 1 addition & 2 deletions codetable/examples/custom_table.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
use std::convert::TryFrom;

use multihash::{Hasher, MultihashDigest as _};
use multihash_codetable::Sha2_256;
use multihash_derive::MultihashDigest;
use multihash_derive::{Hasher, MultihashDigest};

// You can implement a custom hasher. This is a SHA2 256-bit hasher that returns a hash that is
// truncated to 160 bits.
Expand Down
2 changes: 1 addition & 1 deletion codetable/examples/manual_mh.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use multihash::MultihashDigest;
use multihash_codetable::Code;
use multihash_derive::MultihashDigest;

/// prefix/multihash generating tool to aid when adding new tests
fn prefix_util() {
Expand Down
4 changes: 2 additions & 2 deletions codetable/src/hasher_impl.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use multihash::Hasher;
use multihash_derive::Hasher;

use std::io;

Expand Down Expand Up @@ -153,7 +153,7 @@ macro_rules! derive_rustcrypto_hasher {
}
}

impl ::multihash::Hasher for $name {
impl ::multihash_derive::Hasher for $name {
fn update(&mut self, input: &[u8]) {
use digest::Digest;
self.state.update(input)
Expand Down
4 changes: 2 additions & 2 deletions codetable/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -88,8 +88,8 @@ pub enum Code {
mod tests {
use super::*;
use crate::hasher_impl::sha3::{Sha3_256, Sha3_512};
use multihash::MultihashDigest;
use multihash::{Hasher, Multihash};
use multihash_derive::MultihashDigest;
use multihash_derive::{Hasher, Multihash};

#[test]
fn test_hasher_256() {
Expand Down
4 changes: 2 additions & 2 deletions codetable/tests/lib.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
use std::io::{Cursor, Write};

use multihash::{Hasher, MultihashDigest};
use multihash_codetable::{
Blake2b256, Blake2b512, Blake2s128, Blake2s256, Blake3_256, Identity256, Keccak224, Keccak256,
Keccak384, Keccak512, Sha1, Sha2_256, Sha2_512, Sha3_224, Sha3_256, Sha3_384, Sha3_512,
Strobe256, Strobe512,
};
use multihash_derive::{Hasher, MultihashDigest};

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

#[test]
fn blak3_non_default_digest() {
use multihash::MultihashDigest;
use multihash_codetable::Blake3Hasher;
use multihash_derive::MultihashDigest;
const DIGEST_SIZE: usize = 16;
pub struct ContentHasher(Blake3Hasher<DIGEST_SIZE>);

Expand Down
28 changes: 28 additions & 0 deletions derive-impl/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
[package]
name = "multihash-derive-impl"
version = "0.1.0"
authors = ["David Craven <david@craven.ch>"]
edition = "2018"
description = "Proc macro for deriving custom multihash tables."
license = "MIT"
repository = "https://github.com/multiformats/multihash"
resolver = "2"

[lib]
proc-macro = true

[dependencies]
proc-macro2 = { version = "1.0.24", features = ["span-locations"] }
proc-macro-crate = "~1.1.0"
proc-macro-error = "1.0.4"
quote = "1.0.7"
syn = "1.0.42"
synstructure = "0.12.4"

[features]
default = ["std"]
std = []

[dev-dependencies]
pretty_assertions = "1.0.0"
#multihash = { path = "..", default-features = false, features = ["derive", "sha2"] }
66 changes: 66 additions & 0 deletions derive-impl/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
//! This proc macro derives a custom Multihash code table from a list of hashers. It also
//! generates a public type called `Multihash` which corresponds to the specified `alloc_size`.
//!
//! The digests are stack allocated with a fixed size. That size needs to be big enough to hold any
//! of the specified hash digests. This cannot be determined reliably on compile-time, hence it
//! needs to set manually via the `alloc_size` attribute. Also you might want to set it to bigger
//! sizes then necessarily needed for backwards/forward compatibility.
//!
//! If you set `#mh(alloc_size = …)` to a too low value, you will get compiler errors. Please note
//! the the sizes are checked only on a syntactic level and *not* on the type level. This means
//! that digest need to have a size const generic, which is a valid `usize`, for example `32` or
//! `64`.
//!
//! You can disable those compiler errors with setting the `no_alloc_size_errors` attribute. This
//! can be useful if you e.g. have specified type aliases for your hash digests and you are sure
//! you use the correct value for `alloc_size`.
//!
//! # Example
//!
//! ```
//! use multihash::derive::Multihash;
//! use multihash::MultihashDigest;
//!
//! #[derive(Clone, Copy, Debug, Eq, Multihash, PartialEq)]
//! #[mh(alloc_size = 64)]
//! pub enum Code {
//! #[mh(code = 0x01, hasher = multihash::Sha2_256)]
//! Foo,
//! #[mh(code = 0x02, hasher = multihash::Sha2_512)]
//! Bar,
//! }
//!
//! let hash = Code::Foo.digest(b"hello world!");
//! println!("{:02x?}", hash);
//! ```
extern crate proc_macro;

mod multihash;
mod utils;

use proc_macro::TokenStream;
use proc_macro_error::proc_macro_error;
use synstructure::macros::{parse, DeriveInput};
use synstructure::{MacroResult, Structure};

#[proc_macro_derive(Multihash, attributes(mh))]
#[allow(non_snake_case)]
#[proc_macro_error]
#[deprecated(since = "0.8.1", note = "Use `MultihashDigest` derive instead.")]
pub fn Multihash(i: TokenStream) -> TokenStream {
match parse::<DeriveInput>(i) {
Ok(p) => match Structure::try_new(&p) {
Ok(s) => multihash::multihash(s).into_stream(),
Err(e) => e.to_compile_error().into(),
},
Err(e) => e.to_compile_error().into(),
}
}

#[proc_macro_derive(MultihashDigest, attributes(mh))]
#[allow(non_snake_case)]
#[proc_macro_error]
pub fn MultihashDigest(i: TokenStream) -> TokenStream {
#[allow(deprecated)]
Multihash(i)
}
6 changes: 3 additions & 3 deletions derive/src/multihash.rs → derive-impl/src/multihash.rs
Original file line number Diff line number Diff line change
Expand Up @@ -198,7 +198,7 @@ fn error_code_duplicates(hashes: &[Hash]) {
struct ParseError(Span);

pub fn multihash(s: Structure) -> TokenStream {
let mh_crate = match utils::use_crate("multihash") {
let mh_crate = match utils::use_crate("multihash-derive") {
Ok(ident) => ident,
Err(e) => {
let err = syn::Error::new(Span::call_site(), e).to_compile_error();
Expand Down Expand Up @@ -247,12 +247,12 @@ pub fn multihash(s: Structure) -> TokenStream {
}

impl core::convert::TryFrom<u64> for #code_enum {
type Error = #mh_crate::Error;
type Error = #mh_crate::UnsupportedCode;

fn try_from(code: u64) -> Result<Self, Self::Error> {
match code {
#(#code_from_u64,)*
_ => Err(#mh_crate::Error::unsupported_code(code))
_ => Err(#mh_crate::UnsupportedCode(code))
}
}
}
Expand Down
File renamed without changes.
19 changes: 2 additions & 17 deletions derive/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,21 +8,6 @@ license = "MIT"
repository = "https://github.com/multiformats/multihash"
resolver = "2"

[lib]
proc-macro = true

[dependencies]
proc-macro2 = { version = "1.0.24", features = ["span-locations"] }
proc-macro-crate = "~1.1.0"
proc-macro-error = "1.0.4"
quote = "1.0.7"
syn = "1.0.42"
synstructure = "0.12.4"

[features]
default = ["std"]
std = []

[dev-dependencies]
pretty_assertions = "1.0.0"
#multihash = { path = "..", default-features = false, features = ["derive", "sha2"] }
multihash-derive-impl = { version = "0.1.0", path = "../derive-impl" }
multihash = { version = "0.18.0", path = "../" }
File renamed without changes.
83 changes: 59 additions & 24 deletions derive/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,34 +33,69 @@
//! let hash = Code::Foo.digest(b"hello world!");
//! println!("{:02x?}", hash);
//! ```
extern crate proc_macro;
mod multihash;
mod utils;
mod hasher;

use proc_macro::TokenStream;
use proc_macro_error::proc_macro_error;
use synstructure::macros::{parse, DeriveInput};
use synstructure::{MacroResult, Structure};
use std::convert::TryFrom;
use std::fmt;

#[proc_macro_derive(Multihash, attributes(mh))]
#[allow(non_snake_case)]
#[proc_macro_error]
#[deprecated(since = "0.8.1", note = "Use `MultihashDigest` derive instead.")]
pub fn Multihash(i: TokenStream) -> TokenStream {
match parse::<DeriveInput>(i) {
Ok(p) => match Structure::try_new(&p) {
Ok(s) => multihash::multihash(s).into_stream(),
Err(e) => e.to_compile_error().into(),
},
Err(e) => e.to_compile_error().into(),
pub use hasher::Hasher;
pub use multihash_derive_impl::MultihashDigest;

pub use multihash::*;

/// The given code is not supported by this codetable.
#[derive(Debug)]
pub struct UnsupportedCode(pub u64);

impl fmt::Display for UnsupportedCode {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "the code {} is not supported by this codetable", self.0)
}
}

#[proc_macro_derive(MultihashDigest, attributes(mh))]
#[allow(non_snake_case)]
#[proc_macro_error]
pub fn MultihashDigest(i: TokenStream) -> TokenStream {
#[allow(deprecated)]
Multihash(i)
impl std::error::Error for UnsupportedCode {}

/// Trait that implements hashing.
///
/// It is usually implemented by a custom code table enum that derives the [`Multihash` derive].
///
/// [`Multihash` derive]: crate::derive
pub trait MultihashDigest<const S: usize>:
TryFrom<u64, Error = UnsupportedCode>
+ Into<u64>
+ Send
+ Sync
+ Unpin
+ Copy
+ Eq
+ fmt::Debug
+ 'static
{
/// Calculate the hash of some input data.
///
/// # Example
///
/// ```
/// // `Code` implements `MultihashDigest`
/// use multihash::{Code, MultihashDigest};
///
/// let hash = Code::Sha3_256.digest(b"Hello world!");
/// println!("{:02x?}", hash);
/// ```
fn digest(&self, input: &[u8]) -> Multihash<S>;

/// Create a multihash from an existing multihash digest.
///
/// # Example
///
/// ```
/// use multihash::{Code, Hasher, MultihashDigest, Sha3_256};
///
/// let mut hasher = Sha3_256::default();
/// hasher.update(b"Hello world!");
/// let hash = Code::Sha3_256.wrap(&hasher.finalize()).unwrap();
/// println!("{:02x?}", hash);
/// ```
fn wrap(&self, digest: &[u8]) -> std::result::Result<Multihash<S>, multihash::Error>;
}
12 changes: 0 additions & 12 deletions src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,6 @@ pub struct Error {
}

impl Error {
/// The specified code is not supported by code table.
/// 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.
pub fn unsupported_code(code: u64) -> Self {
Self {
kind: Kind::UnsupportedCode(code),
}
}

pub(crate) const fn invalid_size(size: u64) -> Self {
Self {
kind: Kind::InvalidSize(size),
Expand Down Expand Up @@ -51,8 +43,6 @@ impl core::fmt::Display for Error {
enum Kind {
/// Io error.
Io(io::Error),
/// Unsupported multihash code.
UnsupportedCode(u64),
/// Invalid multihash size.
InvalidSize(u64),
/// Invalid varint.
Expand Down Expand Up @@ -80,7 +70,6 @@ impl core::fmt::Display for Kind {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
match self {
Self::Io(err) => write!(f, "{err}"),
Self::UnsupportedCode(code) => write!(f, "Unsupported multihash code {code}."),
Self::InvalidSize(size) => write!(f, "Invalid multihash size {size}."),
Self::Varint(err) => write!(f, "{err}"),
}
Expand All @@ -91,7 +80,6 @@ impl StdError for Error {
fn source(&self) -> Option<&(dyn StdError + 'static)> {
match &self.kind {
Kind::Io(inner) => Some(inner),
Kind::UnsupportedCode(_) => None,
Kind::InvalidSize(_) => None,
Kind::Varint(_) => None, // FIXME: Does not implement `core2::Error`.
}
Expand Down
6 changes: 1 addition & 5 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,18 +59,14 @@ extern crate core;
#[cfg(any(test, feature = "arb"))]
mod arb;
mod error;
mod hasher;
mod multihash;

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

pub use crate::error::Error;
pub use crate::multihash::{Multihash, MultihashDigest};
pub use hasher::Hasher;
#[cfg(feature = "derive")]
pub use multihash_derive as derive;
pub use crate::multihash::Multihash;

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

0 comments on commit aab78df

Please sign in to comment.