diff --git a/ethereum-types/src/uint.rs b/ethereum-types/src/uint.rs index 7b9b8f07e..57fd8577b 100644 --- a/ethereum-types/src/uint.rs +++ b/ethereum-types/src/uint.rs @@ -6,32 +6,12 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#[cfg(feature = "codec")] -use impl_codec::impl_uint_codec; -#[cfg(feature = "rlp")] -use impl_rlp::impl_uint_rlp; -#[cfg(feature = "serialize")] -use impl_serde::impl_uint_serde; -use uint_crate::*; - pub use uint_crate::{FromDecStrErr, FromStrRadixErr, FromStrRadixErrKind}; - -construct_uint! { - /// Unsigned 64-bit integer. - pub struct U64(1); -} -#[cfg(feature = "rlp")] -impl_uint_rlp!(U64, 1); -#[cfg(feature = "serialize")] -impl_uint_serde!(U64, 1); -#[cfg(feature = "codec")] -impl_uint_codec!(U64, 1); - -pub use primitive_types::{U128, U256, U512}; +pub use primitive_types::{U64, U128, U256, U512}; #[cfg(test)] mod tests { - use super::{U256, U512}; + use super::{U64, U256, U512}; use serde_json as ser; use std::u64::MAX; @@ -99,6 +79,17 @@ mod tests { .is_data()); } + #[test] + fn test_serialize_u64() { + assert_eq!( + ser::to_string_pretty(&!U64::zero()).unwrap(), + "\"0xffffffffffffffff\"" + ); + assert!(ser::from_str::("\"0x1ffffffffffffffff\"") + .unwrap_err() + .is_data()); + } + #[test] fn fixed_arrays_roundtrip() { let raw: U256 = "7094875209347850239487502394881".into(); diff --git a/primitive-types/src/lib.rs b/primitive-types/src/lib.rs index dd372a9eb..6e1a431e0 100644 --- a/primitive-types/src/lib.rs +++ b/primitive-types/src/lib.rs @@ -30,6 +30,11 @@ pub enum Error { Overflow, } +construct_uint! { + /// 64-bit unsigned integer. + #[cfg_attr(feature = "scale-info", derive(TypeInfo))] + pub struct U64(1); +} construct_uint! { /// 128-bit unsigned integer. #[cfg_attr(feature = "scale-info", derive(TypeInfo))] @@ -83,6 +88,7 @@ mod num_traits { use super::*; use impl_num_traits::impl_uint_num_traits; + impl_uint_num_traits!(U64, 1); impl_uint_num_traits!(U128, 2); impl_uint_num_traits!(U256, 4); impl_uint_num_traits!(U512, 8); @@ -93,6 +99,7 @@ mod serde { use super::*; use impl_serde::{impl_fixed_hash_serde, impl_uint_serde}; + impl_uint_serde!(U64, 1); impl_uint_serde!(U128, 2); impl_uint_serde!(U256, 4); impl_uint_serde!(U512, 8); @@ -110,6 +117,7 @@ mod codec { use super::*; use impl_codec::{impl_fixed_hash_codec, impl_uint_codec}; + impl_uint_codec!(U64, 1); impl_uint_codec!(U128, 2); impl_uint_codec!(U256, 4); impl_uint_codec!(U512, 8); @@ -127,6 +135,7 @@ mod rlp { use super::*; use impl_rlp::{impl_fixed_hash_rlp, impl_uint_rlp}; + impl_uint_rlp!(U64, 1); impl_uint_rlp!(U128, 2); impl_uint_rlp!(U256, 4); impl_uint_rlp!(U512, 8); @@ -141,6 +150,15 @@ mod rlp { impl_fixed_hash_conversions!(H256, H160); +impl U64 { + /// Multiplies two 64-bit integers to produce full 128-bit integer. + /// Overflow is not possible. + #[inline(always)] + pub fn full_mul(self, other: Self) -> U128 { + U128(uint_full_mul_reg!(Self, 1, self, other)) + } +} + impl U128 { /// Multiplies two 128-bit integers to produce full 256-bit integer. /// Overflow is not possible. @@ -159,6 +177,24 @@ impl U256 { } } +impl From for U128 { + fn from(value: U64) -> Self { + Self([value.0[0], 0]) + } +} + +impl From for U256 { + fn from(value: U64) -> Self { + Self([value.0[0], 0, 0, 0]) + } +} + +impl From for U512 { + fn from(value: U64) -> Self { + Self([value.0[0], 0, 0, 0, 0, 0, 0, 0]) + } +} + impl From for U512 { fn from(value: U256) -> U512 { let U256(ref arr) = value; @@ -171,6 +207,42 @@ impl From for U512 { } } +impl TryFrom for U64 { + type Error = Error; + + fn try_from(value: U128) -> Result { + let U128(ref arr) = value; + if arr[1] != 0 { + return Err(Error::Overflow) + } + Ok(Self([arr[0]])) + } +} + +impl TryFrom for U64 { + type Error = Error; + + fn try_from(value: U256) -> Result { + let U256(ref arr) = value; + if arr[1] | arr[2]| arr[3] != 0 { + return Err(Error::Overflow) + } + Ok(Self([arr[0]])) + } +} + +impl TryFrom for U64 { + type Error = Error; + + fn try_from(value: U512) -> Result { + let U512(ref arr) = value; + if arr[1] | arr[2]| arr[3]| arr[4] | arr[5] | arr[6] | arr[7] != 0 { + return Err(Error::Overflow) + } + Ok(Self([arr[0]])) + } +} + impl TryFrom for U128 { type Error = Error; diff --git a/primitive-types/tests/cast.rs b/primitive-types/tests/cast.rs new file mode 100644 index 000000000..693dc4bab --- /dev/null +++ b/primitive-types/tests/cast.rs @@ -0,0 +1,44 @@ +use primitive_types::{Error, U128, U256, U512, U64}; + + +#[test] +#[allow(non_snake_case)] +fn from_U64() { + let a = U64::from(222); + + assert_eq!(U128::from(a), U128::from(222), "U64 -> U128"); + assert_eq!(U256::from(a), U256::from(222), "U64 -> U256"); + assert_eq!(U512::from(a), U512::from(222), "U64 -> U512"); +} + +#[test] +#[allow(non_snake_case)] +fn to_U64() { + // U128 -> U64 + assert_eq!(U64::try_from(U128([222, 0])), Ok(U64::from(222)), "U128 -> U64"); + assert_eq!(U64::try_from(U128([222, 1])), Err(Error::Overflow), "U128 -> U64 :: Overflow"); + + // U256 -> U64 + assert_eq!(U64::try_from(U256([222, 0, 0, 0])), Ok(U64::from(222)), "U256 -> U64"); + for i in 1..4 { + let mut arr = [222, 0, 0, 0]; + arr[i] = 1; + assert_eq!(U64::try_from(U256(arr)), Err(Error::Overflow), "U256 -> U64 :: Overflow"); + } + + // U512 -> U64 + assert_eq!(U64::try_from(U512([222, 0, 0, 0, 0, 0, 0, 0])),Ok(U64::from(222)), "U512 -> U64"); + for i in 1..8 { + let mut arr = [222, 0, 0, 0, 0, 0, 0, 0]; + arr[i] = 1; + assert_eq!(U64::try_from(U512(arr)), Err(Error::Overflow), "U512 -> U64"); + } +} + +#[test] +#[allow(non_snake_case)] +fn full_mul_U64() { + let a = U64::MAX; + let b = U64::from(2); + assert_eq!(a.full_mul(b), U128::from(a)*U128::from(b)) +} \ No newline at end of file diff --git a/primitive-types/tests/num_traits.rs b/primitive-types/tests/num_traits.rs index 1d6c8e8a5..440477659 100644 --- a/primitive-types/tests/num_traits.rs +++ b/primitive-types/tests/num_traits.rs @@ -7,7 +7,7 @@ // except according to those terms. use impl_num_traits::integer_sqrt::IntegerSquareRoot; -use primitive_types::U256; +use primitive_types::{U64, U256}; #[test] fn u256_isqrt() { @@ -15,3 +15,10 @@ fn u256_isqrt() { let s = x.integer_sqrt_checked().unwrap(); assert_eq!(x.integer_sqrt(), s); } + +#[test] +fn u64_isqrt() { + let x = U64::MAX; + let s = x.integer_sqrt_checked().unwrap(); + assert_eq!(x.integer_sqrt(), s); +}