Merge pull request #92 from paritytech/td-u128

Expose U128, add u128 conversions.
This commit is contained in:
Wei Tang 2019-01-15 17:41:36 +01:00 committed by GitHub
commit 5b56003075
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 127 additions and 57 deletions

View File

@ -8,7 +8,7 @@
//! Primitive types shared by Substrate and Parity Ethereum.
//!
//! Those are uint types `U256` and `U512`, and fixed hash types `H160`,
//! Those are uint types `U128`, `U256` and `U512`, and fixed hash types `H160`,
//! `H256` and `H512`, with optional serde serialization, parity-codec and
//! rlp encoding.
@ -32,16 +32,73 @@ extern crate impl_codec;
#[macro_use]
extern crate impl_rlp;
construct_uint! {
/// 128-bit unsigned integer.
pub struct U128(2);
}
construct_uint! {
/// 256-bit unsigned integer.
pub struct U256(4);
}
construct_uint! {
/// 512-bits unsigned integer.
pub struct U512(8);
}
construct_fixed_hash! {
/// Fixed-size uninterpreted hash type with 20 bytes (160 bits) size.
pub struct H160(20);
}
construct_fixed_hash! {
/// Fixed-size uninterpreted hash type with 32 bytes (256 bits) size.
pub struct H256(32);
}
construct_fixed_hash! {
/// Fixed-size uninterpreted hash type with 64 bytes (512 bits) size.
pub struct H512(64);
}
#[cfg(feature = "impl-serde")]
impl_uint_serde!(U256, 4);
mod serde {
use super::*;
impl_uint_serde!(U128, 2);
impl_uint_serde!(U256, 4);
impl_uint_serde!(U512, 8);
impl_fixed_hash_serde!(H160, 20);
impl_fixed_hash_serde!(H256, 32);
impl_fixed_hash_serde!(H512, 64);
}
#[cfg(feature = "impl-codec")]
impl_uint_codec!(U256, 4);
mod codec {
use super::*;
impl_uint_codec!(U128, 2);
impl_uint_codec!(U256, 4);
impl_uint_codec!(U512, 8);
impl_fixed_hash_codec!(H160, 20);
impl_fixed_hash_codec!(H256, 32);
impl_fixed_hash_codec!(H512, 64);
}
#[cfg(feature = "impl-rlp")]
impl_uint_rlp!(U256, 4);
mod rlp {
use super::*;
impl_uint_rlp!(U128, 2);
impl_uint_rlp!(U256, 4);
impl_uint_rlp!(U512, 8);
impl_fixed_hash_rlp!(H160, 20);
impl_fixed_hash_rlp!(H256, 32);
impl_fixed_hash_rlp!(H512, 64);
}
impl_fixed_hash_conversions!(H256, H160);
impl U256 {
/// Multiplies two 256-bit integers to produce full 512-bit integer
@ -105,49 +162,3 @@ impl<'a> From<&'a U512> for U256 {
U256(ret)
}
}
construct_uint! {
/// 512-bits unsigned integer.
pub struct U512(8);
}
#[cfg(feature = "impl-serde")]
impl_uint_serde!(U512, 8);
#[cfg(feature = "impl-codec")]
impl_uint_codec!(U512, 8);
#[cfg(feature = "impl-rlp")]
impl_uint_rlp!(U512, 8);
construct_fixed_hash! {
/// Fixed-size uninterpreted hash type with 20 bytes (160 bits) size.
pub struct H160(20);
}
#[cfg(feature = "impl-serde")]
impl_fixed_hash_serde!(H160, 20);
#[cfg(feature = "impl-codec")]
impl_fixed_hash_codec!(H160, 20);
#[cfg(feature = "impl-rlp")]
impl_fixed_hash_rlp!(H160, 20);
impl_fixed_hash_conversions!(H256, H160);
construct_fixed_hash! {
/// Fixed-size uninterpreted hash type with 32 bytes (256 bits) size.
pub struct H256(32);
}
#[cfg(feature = "impl-serde")]
impl_fixed_hash_serde!(H256, 32);
#[cfg(feature = "impl-codec")]
impl_fixed_hash_codec!(H256, 32);
#[cfg(feature = "impl-rlp")]
impl_fixed_hash_rlp!(H256, 32);
construct_fixed_hash! {
/// Fixed-size uninterpreted hash type with 64 bytes (512 bits) size.
pub struct H512(64);
}
#[cfg(feature = "impl-serde")]
impl_fixed_hash_serde!(H512, 64);
#[cfg(feature = "impl-codec")]
impl_fixed_hash_codec!(H512, 64);
#[cfg(feature = "impl-rlp")]
impl_fixed_hash_rlp!(H512, 64);

View File

@ -346,7 +346,58 @@ pub fn split_u128(a: u128) -> (u64, u64) {
#[macro_export]
macro_rules! construct_uint {
( $(#[$attr:meta])* $visibility:vis struct $name:ident (1); ) => {
construct_uint!{ @construct $(#[$attr])* $visibility struct $name (1); }
};
( $(#[$attr:meta])* $visibility:vis struct $name:ident ( $n_words:tt ); ) => {
construct_uint! { @construct $(#[$attr])* $visibility struct $name ($n_words); }
impl $crate::core_::convert::From<u128> for $name {
fn from(value: u128) -> $name {
let mut ret = [0; $n_words];
ret[0] = value as u64;
ret[1] = (value >> 64) as u64;
$name(ret)
}
}
impl $crate::core_::convert::From<i128> for $name {
fn from(value: i128) -> $name {
match value >= 0 {
true => From::from(value as u128),
false => { panic!("Unsigned integer can't be created from negative value"); }
}
}
}
impl $name {
/// Low 2 words (u128)
#[inline]
pub fn low_u128(&self) -> u128 {
let &$name(ref arr) = self;
((arr[1] as u128) << 64) + arr[0] as u128
}
/// Conversion to u128 with overflow checking
///
/// # Panics
///
/// Panics if the number is larger than 2^128.
#[inline]
pub fn as_u128(&self) -> u128 {
let &$name(ref arr) = self;
for i in 2..$n_words {
if arr[i] != 0 {
panic!("Integer overflow when casting to u128")
}
}
self.low_u128()
}
}
};
( @construct $(#[$attr:meta])* $visibility:vis struct $name:ident ( $n_words:tt ); ) => {
/// Little-endian large integer type
#[repr(C)]
$(#[$attr])*
@ -366,7 +417,6 @@ macro_rules! construct_uint {
}
impl $name {
/// Maximum value.
pub const MAX: $name = $name([u64::max_value(); $n_words]);
@ -414,7 +464,7 @@ macro_rules! construct_uint {
pub fn as_u32(&self) -> u32 {
let &$name(ref arr) = self;
if (arr[0] & (0xffffffffu64 << 32)) != 0 {
panic!("Integer overflow when casting U256")
panic!("Integer overflow when casting to u32")
}
self.as_u64() as u32
}
@ -429,7 +479,7 @@ macro_rules! construct_uint {
let &$name(ref arr) = self;
for i in 1..$n_words {
if arr[i] != 0 {
panic!("Integer overflow when casting U256")
panic!("Integer overflow when casting to u64")
}
}
arr[0]
@ -445,11 +495,11 @@ macro_rules! construct_uint {
let &$name(ref arr) = self;
for i in 1..$n_words {
if arr[i] != 0 {
panic!("Integer overflow when casting U256")
panic!("Integer overflow when casting to usize")
}
}
if arr[0] > usize::max_value() as u64 {
panic!("Integer overflow when casting U256")
panic!("Integer overflow when casting to usize")
}
arr[0] as usize
}
@ -821,7 +871,6 @@ macro_rules! construct_uint {
}
}
impl_map_from!($name, u8, u64);
impl_map_from!($name, u16, u64);
impl_map_from!($name, u32, u64);
@ -841,7 +890,7 @@ macro_rules! construct_uint {
impl_map_from!($name, i32, i64);
impl_map_from!($name, isize, i64);
// Converts from big endian representation of U256
// Converts from big endian representation.
impl<'a> $crate::core_::convert::From<&'a [u8]> for $name {
fn from(bytes: &[u8]) -> $name {
Self::from_big_endian(bytes)

View File

@ -22,6 +22,16 @@ construct_uint! {
pub struct U512(8);
}
#[test]
fn u128_conversions() {
let mut a = U256::from(u128::max_value());
assert_eq!(a.low_u128(), u128::max_value());
a += 2u128.into();
assert_eq!(a.low_u128(), 1u128);
a -= 3u128.into();
assert_eq!(a.low_u128(), u128::max_value() - 1);
}
#[test]
fn uint256_checked_ops() {
let z = U256::from(0);