Skip to content
This repository has been archived by the owner on Nov 30, 2022. It is now read-only.

Commit

Permalink
Make it easy to access the contents of any hash (newtype)
Browse files Browse the repository at this point in the history
Hashes can be represented as fixed length arrays. That is in fact
what they are internally.
There is value in using Rust's visibility rules to enforce that
no every byte array is a valid hash.
However, every hash is certainly a valid byte array, hence it
should be easy to access their contents as such.

We add a `From` impl for any hash newtype for the inner byte array.
This makes it possible to pass hash-newtypes the way they are to
any function that needs a byte-array.

We also add a `From` impl for any inner hash type that allows us
to convert to the inner representation.

Both of these changes are especially useful from a broader ecosystem
perspective:

Because `From` and `Into` are part of the standard library, any
application or crate depends on them and can write functions that
support a form of method overloading by accepting anything that is
`Into<[u8; 32]>`.

Implementing these conversion traits on our types makes them
compatible with this pattern which results in less verbose APIs.
  • Loading branch information
thomaseizinger committed Aug 30, 2020
1 parent 6a89226 commit 2a0ced0
Show file tree
Hide file tree
Showing 10 changed files with 40 additions and 0 deletions.
1 change: 1 addition & 0 deletions src/hash160.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ hex_fmt_impl!(LowerHex, Hash);
index_impl!(Hash);
serde_impl!(Hash, 20);
borrow_slice_impl!(Hash);
from_hash_for_inner_impl!(Hash);

impl str::FromStr for Hash {
type Err = ::hex::Error;
Expand Down
17 changes: 17 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,12 @@ macro_rules! hash_newtype {
}
}

impl ::std::convert::From<$newtype> for <$hash as $crate::Hash>::Inner {
fn from(hashtype: $newtype) -> <$hash as $crate::Hash>::Inner {
hashtype.0.into_inner()
}
}

impl $crate::Hash for $newtype {
type Engine = <$hash as $crate::Hash>::Engine;
type Inner = <$hash as $crate::Hash>::Inner;
Expand Down Expand Up @@ -238,5 +244,16 @@ mod test {
let h2: TestNewtype = h.to_string().parse().unwrap();
assert_eq!(h2.as_hash(), h);
}

#[test]
fn convert_using_std_into() {
fn i_accept_plain_arrays<T: Into<[u8; 32]>>(whatever: T) {
let _x = whatever.into();
}

let h1 = TestNewtype::hash(&[]);

i_accept_plain_arrays(h1);
}
}

1 change: 1 addition & 0 deletions src/ripemd160.rs
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ hex_fmt_impl!(LowerHex, Hash);
index_impl!(Hash);
serde_impl!(Hash, 20);
borrow_slice_impl!(Hash);
from_hash_for_inner_impl!(Hash);

impl str::FromStr for Hash {
type Err = ::hex::Error;
Expand Down
1 change: 1 addition & 0 deletions src/sha1.rs
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ hex_fmt_impl!(LowerHex, Hash);
index_impl!(Hash);
serde_impl!(Hash, 20);
borrow_slice_impl!(Hash);
from_hash_for_inner_impl!(Hash);

impl str::FromStr for Hash {
type Err = ::hex::Error;
Expand Down
1 change: 1 addition & 0 deletions src/sha256.rs
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ hex_fmt_impl!(LowerHex, Hash);
index_impl!(Hash);
serde_impl!(Hash, 32);
borrow_slice_impl!(Hash);
from_hash_for_inner_impl!(Hash);

impl HashTrait for Hash {
type Engine = HashEngine;
Expand Down
1 change: 1 addition & 0 deletions src/sha256d.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ hex_fmt_impl!(LowerHex, Hash);
index_impl!(Hash);
serde_impl!(Hash, 32);
borrow_slice_impl!(Hash);
from_hash_for_inner_impl!(Hash);

impl str::FromStr for Hash {
type Err = ::hex::Error;
Expand Down
6 changes: 6 additions & 0 deletions src/sha256t.rs
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,12 @@ impl<T: Tag> HashTrait for Hash<T> {
}
}

impl<T> From<Hash<T>> for <Hash<T> as HashTrait>::Inner where T: Tag {
fn from(hash: Hash<T>) -> Self {
hash.into_inner()
}
}

#[cfg(feature="serde")]
impl<T: Tag> ::serde::Serialize for Hash<T> {
fn serialize<S: ::serde::Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
Expand Down
1 change: 1 addition & 0 deletions src/sha512.rs
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,7 @@ hex_fmt_impl!(LowerHex, Hash);
index_impl!(Hash);
serde_impl!(Hash, 64);
borrow_slice_impl!(Hash);
from_hash_for_inner_impl!(Hash);

impl HashTrait for Hash {
type Engine = HashEngine;
Expand Down
1 change: 1 addition & 0 deletions src/siphash24.rs
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,7 @@ hex_fmt_impl!(LowerHex, Hash);
index_impl!(Hash);
serde_impl!(Hash, 8);
borrow_slice_impl!(Hash);
from_hash_for_inner_impl!(Hash);

impl str::FromStr for Hash {
type Err = ::hex::Error;
Expand Down
10 changes: 10 additions & 0 deletions src/util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,16 @@ macro_rules! engine_input_impl(
)
);

macro_rules! from_hash_for_inner_impl(
($hash:ty) => (
impl From<$hash> for <$hash as HashTrait>::Inner {
fn from(hash: $hash) -> Self {
hash.into_inner()
}
}
)
);



macro_rules! define_slice_to_be {
Expand Down

0 comments on commit 2a0ced0

Please sign in to comment.