multihash_derive/lib.rs
1#![cfg_attr(not(feature = "std"), no_std)]
2
3//! A procedural macro for custom Multihash code tables.
4//!
5//! This proc macro derives a custom Multihash code table from a list of hashers. It also
6//! generates a public type called `Multihash` which corresponds to the specified `alloc_size`.
7//!
8//! The digests are stack allocated with a fixed size. That size needs to be big enough to hold any
9//! of the specified hash digests. This cannot be determined reliably on compile-time, hence it
10//! needs to set manually via the `alloc_size` attribute. Also you might want to set it to bigger
11//! sizes then necessarily needed for backwards/forward compatibility.
12//!
13//! If you set `#mh(alloc_size = …)` to a too low value, you will get compiler errors. Please note
14//! the the sizes are checked only on a syntactic level and *not* on the type level. This means
15//! that digest need to have a size const generic, which is a valid `usize`, for example `32` or
16//! `64`.
17//!
18//! You can disable those compiler errors with setting the `no_alloc_size_errors` attribute. This
19//! can be useful if you e.g. have specified type aliases for your hash digests and you are sure
20//! you use the correct value for `alloc_size`.
21//!
22//! When you want to define your own codetable, you should only depend on `multihash-derive`.
23//! It re-exports the `multihash` crate for you.
24//!
25//! # Example
26//!
27//! ```ignore : `proc-macro-crate` does not work in docs, see https://github.com/bkchr/proc-macro-crate/issues/14
28//! use multihash_derive::{Hasher, MultihashDigest};
29//!
30//! struct FooHasher;
31//!
32//! impl Hasher for FooHasher {
33//! // Implement hasher ...
34//! # fn update(&mut self, input: &[u8]) {
35//! #
36//! # }
37//! #
38//! # fn finalize(&mut self) -> &[u8] {
39//! # &[]
40//! # }
41//! #
42//! # fn reset(&mut self) {
43//! #
44//! # }
45//! }
46//!
47//! #[derive(Clone, Copy, Debug, Eq, MultihashDigest, PartialEq)]
48//! #[mh(alloc_size = 64)]
49//! pub enum Code {
50//! #[mh(code = 0x01, hasher = FooHasher)]
51//! Foo
52//! }
53//!
54//! let hash = Code::Foo.digest(b"hello world!");
55//!
56//! println!("{:02x?}", hash);
57//! ```
58
59mod hasher;
60
61use core::convert::TryFrom;
62use core::fmt;
63
64pub use hasher::Hasher;
65pub use multihash::Error;
66pub use multihash::Multihash;
67#[doc(inline)]
68pub use multihash_derive_impl::Multihash; // This one is deprecated.
69pub use multihash_derive_impl::MultihashDigest;
70
71/// The given code is not supported by this codetable.
72#[derive(Debug)]
73pub struct UnsupportedCode(pub u64);
74
75impl fmt::Display for UnsupportedCode {
76 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
77 write!(f, "the code {} is not supported by this codetable", self.0)
78 }
79}
80
81impl core2::error::Error for UnsupportedCode {}
82
83/// Trait that implements hashing.
84///
85/// Typically, you won't implement this yourself but use the [`MultihashDigest`](multihash_derive_impl::MultihashDigest) custom-derive.
86pub trait MultihashDigest<const S: usize>:
87 TryFrom<u64, Error = UnsupportedCode>
88 + Into<u64>
89 + Send
90 + Sync
91 + Unpin
92 + Copy
93 + Eq
94 + fmt::Debug
95 + 'static
96{
97 /// Calculate the hash of some input data.
98 fn digest(&self, input: &[u8]) -> Multihash<S>;
99
100 /// Create a multihash from an existing multihash digest.
101 fn wrap(&self, digest: &[u8]) -> Result<Multihash<S>, Error>;
102}