diff --git a/uint/CHANGELOG.md b/uint/CHANGELOG.md index 386475612..3445abef3 100644 --- a/uint/CHANGELOG.md +++ b/uint/CHANGELOG.md @@ -5,6 +5,7 @@ The format is based on [Keep a Changelog]. [Keep a Changelog]: http://keepachangelog.com/en/1.0.0/ ## [Unreleased] +- Added a manual impl of `Eq` and `Hash`. [#390](https://github.com/paritytech/parity-common/pull/390) ## [0.8.3] - 2020-04-27 - Added `arbitrary` feature. [#378](https://github.com/paritytech/parity-common/pull/378) diff --git a/uint/src/uint.rs b/uint/src/uint.rs index 2811d7d6c..6e98b0a59 100644 --- a/uint/src/uint.rs +++ b/uint/src/uint.rs @@ -445,7 +445,7 @@ macro_rules! construct_uint { /// Little-endian large integer type #[repr(C)] $(#[$attr])* - #[derive(Copy, Clone, Eq, PartialEq, Hash)] + #[derive(Copy, Clone)] $visibility struct $name (pub [u64; $n_words]); /// Get a reference to the underlying little-endian words. @@ -1462,6 +1462,23 @@ macro_rules! construct_uint { } } + // We implement `Eq` and `Hash` manually to workaround + // https://github.com/rust-lang/rust/issues/61415 + impl $crate::core_::cmp::PartialEq for $name { + fn eq(&self, other: &$name) -> bool { + self.as_ref() == other.as_ref() + } + } + + impl $crate::core_::cmp::Eq for $name {} + + impl $crate::core_::hash::Hash for $name { + fn hash(&self, state: &mut H) { + // use the impl as slice &[u64] + self.as_ref().hash(state); + } + } + impl $crate::core_::cmp::Ord for $name { fn cmp(&self, other: &$name) -> $crate::core_::cmp::Ordering { let &$name(ref me) = self; diff --git a/uint/tests/uint_tests.rs b/uint/tests/uint_tests.rs index 32a14c728..f01051586 100644 --- a/uint/tests/uint_tests.rs +++ b/uint/tests/uint_tests.rs @@ -20,6 +20,26 @@ construct_uint! { pub struct U512(8); } +#[cfg(feature = "std")] +#[test] +fn hash_impl_is_the_same_as_for_a_slice() { + use core::hash::{Hash, Hasher as _}; + use std::collections::hash_map::DefaultHasher; + + let uint_hash = { + let mut h = DefaultHasher::new(); + let uint = U256::from(123u64); + Hash::hash(&uint, &mut h); + h.finish() + }; + let slice_hash = { + let mut h = DefaultHasher::new(); + Hash::hash(&[123u64, 0, 0, 0], &mut h); + h.finish() + }; + assert_eq!(uint_hash, slice_hash); +} + #[test] fn u128_conversions() { let mut a = U256::from(u128::max_value()); @@ -281,7 +301,6 @@ fn uint256_bits_test() { } #[test] -#[cfg_attr(feature = "dev", allow(eq_op))] fn uint256_comp_test() { let small = U256([10u64, 0, 0, 0]); let big = U256([0x8C8C3EE70C644118u64, 0x0209E7378231E632, 0, 0]); @@ -296,6 +315,10 @@ fn uint256_comp_test() { assert!(bigger >= big); assert!(bigger >= small); assert!(small <= small); + assert_eq!(small, small); + assert_eq!(biggest, biggest); + assert_ne!(big, biggest); + assert_ne!(big, bigger); } #[test] @@ -1010,10 +1033,10 @@ fn into_fixed_array() { fn test_u256_from_fixed_array() { let ary = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 123]; let num: U256 = ary.into(); - assert_eq!(num, U256::from(std::u64::MAX) + 1 + 123); + assert_eq!(num, U256::from(core::u64::MAX) + 1 + 123); let a_ref: &U256 = &ary.into(); - assert_eq!(a_ref, &(U256::from(std::u64::MAX) + 1 + 123)); + assert_eq!(a_ref, &(U256::from(core::u64::MAX) + 1 + 123)); } #[test]