Merge pull request #25 from paritytech/chore/pick-changes-from-bigint

Port over relevant changes from bigint
This commit is contained in:
David 2018-08-14 17:37:03 +02:00 committed by GitHub
commit 22209e1480
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 358 additions and 353 deletions

View File

@ -8,6 +8,6 @@ matrix:
script:
- cargo build
- cargo test --all --exclude uint
- cd uint/ && cargo test --features=std,impl_quickcheck_arbitrary && cd ..
- cd uint/ && cargo test --features=std,impl_quickcheck_arbitrary --release && cd ..
- cd hashdb/ && cargo test --no-default-features && cd ..
- cd plain_hasher/ && cargo test --no-default-features && cd ..

View File

@ -1,30 +1,26 @@
[package]
description = "Large fixed-size integers arithmetics"
homepage = "http://parity.io"
repository = "https://github.com/paritytech/primitives"
repository = "https://github.com/paritytech/parity-common"
license = "MIT/Apache-2.0"
name = "uint"
version = "0.2.2"
version = "0.3.0"
authors = ["Parity Technologies <admin@parity.io>"]
build = "build.rs"
[build-dependencies]
rustc_version = "0.2"
[dependencies]
byteorder = { version = "1", default-features = false }
heapsize = { version = "0.4.2", optional = true }
rustc-hex = { version = "1.0", optional = true }
rustc-hex = { version = "2.0", default-features = false }
quickcheck = { version = "0.6", optional = true }
crunchy = "0.1"
[dev-dependencies]
crunchy = "0.1.5"
quickcheck = "0.6"
rustc-hex = "2.0"
[features]
std = ["rustc-hex", "byteorder/std"]
std = ["byteorder/std", "rustc-hex/std"]
heapsizeof = ["heapsize"]
use_asm = []
impl_quickcheck_arbitrary = ["quickcheck"]
[[example]]

View File

@ -1,8 +1,8 @@
# Big unsigned integer types
Implementation of a various large-but-fixed sized unsigned integer types.
The functions here are designed to be fast. There are optional `x86_64`
implementations for even more speed, hidden behind the `x64_arithmetic`
feature flag.
The functions here are designed to be fast.
The crate exports two commonly used types: `U256` and `U512`. Other sizes can be constructed with `construct_uint!(NAME, SIZE_IN_WORDS)`, e.g. `construct_uint!(U128, 2);`.
Run tests with `cargo test --features=std,impl_quickcheck_arbitrary`.

230
uint/benches/bigint.rs Normal file
View File

@ -0,0 +1,230 @@
// Copyright 2015-2017 Parity Technologies
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//! benchmarking for bigint
//! should be started with:
//! ```bash
//! rustup run nightly cargo bench
//! ```
#![feature(test)]
extern crate core;
extern crate test;
#[macro_use]
extern crate crunchy;
#[macro_use]
extern crate uint;
construct_uint!(U128, 2);
construct_uint!(U256, 4);
construct_uint!(U512, 8);
use test::{Bencher, black_box};
impl U256 {
/// Multiplies two 256-bit integers to produce full 512-bit integer
/// No overflow possible
#[inline(always)]
pub fn full_mul(self, other: U256) -> U512 {
U512(uint_full_mul_reg!(U256, 4, self, other))
}
}
#[bench]
fn u256_add(b: &mut Bencher) {
b.iter(|| {
let n = black_box(10000);
let zero = black_box(U256::zero());
(0..n).fold(zero, |old, new| {
old.overflowing_add(U256::from(black_box(new))).0
})
});
}
#[bench]
fn u256_sub(b: &mut Bencher) {
b.iter(|| {
let n = black_box(10000);
let max = black_box(U256::max_value());
(0..n).fold(max, |old, new| {
old.overflowing_sub(U256::from(black_box(new))).0
})
});
}
#[bench]
fn u512_sub(b: &mut Bencher) {
b.iter(|| {
let n = black_box(10000);
let max = black_box(U512::max_value());
(0..n).fold(max, |old, new| {
let new = black_box(new);
let p = new % 2;
old.overflowing_sub(U512([p, p, p, p, p, p, p, new])).0
})
});
}
#[bench]
fn u512_add(b: &mut Bencher) {
b.iter(|| {
let n = black_box(10000);
let zero = black_box(U512::zero());
(0..n).fold(zero, |old, new| {
let new = black_box(new);
old.overflowing_add(U512([new, new, new, new, new, new, new, new]))
.0
})
});
}
#[bench]
fn u512_mul(b: &mut Bencher) {
b.iter(|| {
(1..10000).fold(black_box(U512::one()), |old, new| {
old.overflowing_mul(U512::from(black_box(new | 1))).0
})
});
}
#[bench]
fn u512_mul_small(b: &mut Bencher) {
b.iter(|| {
(1..153).fold(black_box(U512::one()), |old, _| {
old.overflowing_mul(U512::from(black_box(10))).0
})
});
}
#[bench]
fn u256_mul(b: &mut Bencher) {
b.iter(|| {
(1..10000).fold(black_box(U256::one()), |old, new| {
old.overflowing_mul(U256::from(black_box(new | 1))).0
})
});
}
#[bench]
fn u256_mul_small(b: &mut Bencher) {
b.iter(|| {
(1..77).fold(black_box(U256::one()), |old, _| {
old.overflowing_mul(U256::from(black_box(10))).0
})
});
}
#[bench]
fn u256_full_mul(b: &mut Bencher) {
b.iter(|| {
let n = black_box(10000);
let one = black_box(U256::one());
(1..n).map(|n| n | 1).fold(one, |old, new| {
let new = black_box(new);
let U512(ref u512words) = old.full_mul(U256([new, new, new, new]));
U256([u512words[0], u512words[2], u512words[2], u512words[3]])
})
});
}
#[bench]
fn u128_mul(b: &mut Bencher) {
b.iter(|| {
let n = black_box(10000);
(1..n).fold(U128([12345u64, 0u64]), |old, new| {
old.overflowing_mul(U128::from(new | 1)).0
})
});
}
#[bench]
fn u256_from_le(b: &mut Bencher) {
b.iter(|| {
let raw = black_box(
[
1u8,
2,
3,
5,
7,
11,
13,
17,
19,
23,
29,
31,
37,
41,
43,
47,
53,
59,
61,
67,
71,
73,
79,
83,
89,
97,
101,
103,
107,
109,
113,
127,
],
);
let _ = U256::from_little_endian(&raw[..]);
});
}
#[bench]
fn u256_from_be(b: &mut Bencher) {
b.iter(|| {
let raw = black_box(
[
1u8,
2,
3,
5,
7,
11,
13,
17,
19,
23,
29,
31,
37,
41,
43,
47,
53,
59,
61,
67,
71,
73,
79,
83,
89,
97,
101,
103,
107,
109,
113,
127,
],
);
let _ = U256::from_big_endian(&raw[..]);
});
}

View File

@ -1,19 +0,0 @@
// Copyright 2015-2017 Parity Technologies
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
extern crate rustc_version;
use rustc_version::{version_meta, Channel};
fn main() {
if cfg!(feature = "use_asm") {
if let Channel::Nightly = version_meta().unwrap().channel {
println!("cargo:rustc-cfg=asm_available");
}
}
}

View File

@ -8,8 +8,8 @@
//! Efficient large, fixed-size big integers and hashes.
#![cfg_attr(asm_available, feature(asm))]
#![cfg_attr(not(feature = "std"), no_std)]
#![cfg_attr(not(feature="std"), no_std)]
#![cfg_attr(all(not(feature="std"), test), feature(alloc))]
#[doc(hidden)]
pub extern crate byteorder;
@ -22,7 +22,6 @@ pub extern crate heapsize;
#[doc(hidden)]
pub extern crate core;
#[cfg(feature = "std")]
#[doc(hidden)]
pub extern crate rustc_hex;
@ -30,5 +29,11 @@ pub extern crate rustc_hex;
#[doc(hidden)]
pub extern crate quickcheck;
#[cfg(all(not(feature = "std"), test))]
extern crate alloc;
#[macro_use]
extern crate crunchy;
mod uint;
pub use uint::*;

View File

@ -50,7 +50,6 @@ macro_rules! impl_map_from {
}
}
#[cfg(not(all(asm_available, target_arch="x86_64")))]
#[macro_export]
#[doc(hidden)]
macro_rules! uint_overflowing_add {
@ -73,85 +72,6 @@ macro_rules! uint_overflowing_add_reg {
})
}
#[cfg(all(asm_available, target_arch="x86_64"))]
#[macro_export]
#[doc(hidden)]
macro_rules! uint_overflowing_add {
(U256, $n_words: tt, $self_expr: expr, $other: expr) => ({
let mut result: [u64; $n_words] = unsafe { ::core::mem::uninitialized() };
let self_t: &[u64; $n_words] = &$self_expr.0;
let other_t: &[u64; $n_words] = &$other.0;
let overflow: u8;
unsafe {
asm!("
add $9, $0
adc $10, $1
adc $11, $2
adc $12, $3
setc %al
"
: "=r"(result[0]), "=r"(result[1]), "=r"(result[2]), "=r"(result[3]), "={al}"(overflow)
: "0"(self_t[0]), "1"(self_t[1]), "2"(self_t[2]), "3"(self_t[3]),
"mr"(other_t[0]), "mr"(other_t[1]), "mr"(other_t[2]), "mr"(other_t[3])
:
:
);
}
(U256(result), overflow != 0)
});
(U512, $n_words: tt, $self_expr: expr, $other: expr) => ({
let mut result: [u64; $n_words] = unsafe { ::core::mem::uninitialized() };
let self_t: &[u64; $n_words] = &$self_expr.0;
let other_t: &[u64; $n_words] = &$other.0;
let overflow: u8;
unsafe {
asm!("
add $15, $0
adc $16, $1
adc $17, $2
adc $18, $3
lodsq
adc $11, %rax
stosq
lodsq
adc $12, %rax
stosq
lodsq
adc $13, %rax
stosq
lodsq
adc $14, %rax
stosq
setc %al
": "=r"(result[0]), "=r"(result[1]), "=r"(result[2]), "=r"(result[3]),
"={al}"(overflow) /* $0 - $4 */
: "{rdi}"(&result[4] as *const u64) /* $5 */
"{rsi}"(&other_t[4] as *const u64) /* $6 */
"0"(self_t[0]), "1"(self_t[1]), "2"(self_t[2]), "3"(self_t[3]),
"m"(self_t[4]), "m"(self_t[5]), "m"(self_t[6]), "m"(self_t[7]),
/* $7 - $14 */
"mr"(other_t[0]), "mr"(other_t[1]), "mr"(other_t[2]), "mr"(other_t[3]),
"m"(other_t[4]), "m"(other_t[5]), "m"(other_t[6]), "m"(other_t[7]) /* $15 - $22 */
: "rdi", "rsi"
:
);
}
(U512(result), overflow != 0)
});
($name:ident, $n_words: tt, $self_expr: expr, $other: expr) => (
uint_overflowing_add_reg!($name, $n_words, $self_expr, $other)
)
}
#[cfg(not(all(asm_available, target_arch="x86_64")))]
#[macro_export]
#[doc(hidden)]
macro_rules! uint_overflowing_sub {
@ -219,204 +139,6 @@ macro_rules! uint_overflowing_sub_reg {
})
}
#[cfg(all(asm_available, target_arch="x86_64"))]
#[macro_export]
#[doc(hidden)]
macro_rules! uint_overflowing_sub {
(U256, $n_words: tt, $self_expr: expr, $other: expr) => ({
let mut result: [u64; $n_words] = unsafe { ::core::mem::uninitialized() };
let self_t: &[u64; $n_words] = &$self_expr.0;
let other_t: &[u64; $n_words] = &$other.0;
let overflow: u8;
unsafe {
asm!("
sub $9, $0
sbb $10, $1
sbb $11, $2
sbb $12, $3
setb %al
"
: "=r"(result[0]), "=r"(result[1]), "=r"(result[2]), "=r"(result[3]), "={al}"(overflow)
: "0"(self_t[0]), "1"(self_t[1]), "2"(self_t[2]), "3"(self_t[3]), "mr"(other_t[0]), "mr"(other_t[1]), "mr"(other_t[2]), "mr"(other_t[3])
:
:
);
}
(U256(result), overflow != 0)
});
(U512, $n_words: tt, $self_expr: expr, $other: expr) => ({
let mut result: [u64; $n_words] = unsafe { ::core::mem::uninitialized() };
let self_t: &[u64; $n_words] = &$self_expr.0;
let other_t: &[u64; $n_words] = &$other.0;
let overflow: u8;
unsafe {
asm!("
sub $15, $0
sbb $16, $1
sbb $17, $2
sbb $18, $3
lodsq
sbb $19, %rax
stosq
lodsq
sbb $20, %rax
stosq
lodsq
sbb $21, %rax
stosq
lodsq
sbb $22, %rax
stosq
setb %al
"
: "=r"(result[0]), "=r"(result[1]), "=r"(result[2]), "=r"(result[3]),
"={al}"(overflow) /* $0 - $4 */
: "{rdi}"(&result[4] as *const u64) /* $5 */
"{rsi}"(&self_t[4] as *const u64) /* $6 */
"0"(self_t[0]), "1"(self_t[1]), "2"(self_t[2]), "3"(self_t[3]),
"m"(self_t[4]), "m"(self_t[5]), "m"(self_t[6]), "m"(self_t[7]),
/* $7 - $14 */
"m"(other_t[0]), "m"(other_t[1]), "m"(other_t[2]), "m"(other_t[3]),
"m"(other_t[4]), "m"(other_t[5]), "m"(other_t[6]), "m"(other_t[7]) /* $15 - $22 */
: "rdi", "rsi"
:
);
}
(U512(result), overflow != 0)
});
($name:ident, $n_words: tt, $self_expr: expr, $other: expr) => ({
uint_overflowing_sub_reg!($name, $n_words, $self_expr, $other)
})
}
#[cfg(all(asm_available, target_arch="x86_64"))]
#[macro_export]
macro_rules! uint_overflowing_mul {
(U256, $n_words: tt, $self_expr: expr, $other: expr) => ({
let mut result: [u64; $n_words] = unsafe { ::core::mem::uninitialized() };
let self_t: &[u64; $n_words] = &$self_expr.0;
let other_t: &[u64; $n_words] = &$other.0;
let overflow: u64;
unsafe {
asm!("
mov $5, %rax
mulq $9
mov %rax, $0
mov %rdx, $1
mov $5, %rax
mulq $10
add %rax, $1
adc $$0, %rdx
mov %rdx, $2
mov $5, %rax
mulq $11
add %rax, $2
adc $$0, %rdx
mov %rdx, $3
mov $5, %rax
mulq $12
add %rax, $3
adc $$0, %rdx
mov %rdx, %rcx
mov $6, %rax
mulq $9
add %rax, $1
adc %rdx, $2
adc $$0, $3
adc $$0, %rcx
mov $6, %rax
mulq $10
add %rax, $2
adc %rdx, $3
adc $$0, %rcx
adc $$0, $3
adc $$0, %rcx
mov $6, %rax
mulq $11
add %rax, $3
adc $$0, %rdx
or %rdx, %rcx
mov $7, %rax
mulq $9
add %rax, $2
adc %rdx, $3
adc $$0, %rcx
mov $7, %rax
mulq $10
add %rax, $3
adc $$0, %rdx
or %rdx, %rcx
mov $8, %rax
mulq $9
add %rax, $3
or %rdx, %rcx
cmpq $$0, %rcx
jne 2f
mov $8, %rcx
jrcxz 12f
mov $12, %rcx
mov $11, %rax
or %rax, %rcx
mov $10, %rax
or %rax, %rcx
jmp 2f
12:
mov $12, %rcx
jrcxz 11f
mov $7, %rcx
mov $6, %rax
or %rax, %rcx
cmpq $$0, %rcx
jne 2f
11:
mov $11, %rcx
jrcxz 2f
mov $7, %rcx
2:
"
: /* $0 */ "={r8}"(result[0]), /* $1 */ "={r9}"(result[1]), /* $2 */ "={r10}"(result[2]),
/* $3 */ "={r11}"(result[3]), /* $4 */ "={rcx}"(overflow)
: /* $5 */ "m"(self_t[0]), /* $6 */ "m"(self_t[1]), /* $7 */ "m"(self_t[2]),
/* $8 */ "m"(self_t[3]), /* $9 */ "m"(other_t[0]), /* $10 */ "m"(other_t[1]),
/* $11 */ "m"(other_t[2]), /* $12 */ "m"(other_t[3])
: "rax", "rdx"
:
);
}
(U256(result), overflow > 0)
});
($name:ident, $n_words: tt, $self_expr: expr, $other: expr) => (
uint_overflowing_mul_reg!($name, $n_words, $self_expr, $other)
)
}
#[cfg(not(all(asm_available, target_arch="x86_64")))]
#[macro_export]
#[doc(hidden)]
macro_rules! uint_overflowing_mul {
@ -428,37 +150,47 @@ macro_rules! uint_overflowing_mul {
#[macro_export]
#[doc(hidden)]
macro_rules! uint_full_mul_reg {
($name:ident, $n_words: tt, $self_expr:expr, $other:expr) => ({{
($name:ident, 8, $self_expr:expr, $other:expr) => {
uint_full_mul_reg!($name, 8, $self_expr, $other, |a, b| a != 0 || b != 0);
};
($name:ident, $n_words:tt, $self_expr:expr, $other:expr) => {
uint_full_mul_reg!($name, $n_words, $self_expr, $other, |_, _| true);
};
($name:ident, $n_words:tt, $self_expr:expr, $other:expr, $check:expr) => ({{
#![allow(unused_assignments)]
let $name(ref me) = $self_expr;
let $name(ref you) = $other;
let mut ret = [0u64; 2*$n_words];
let mut ret = [0u64; $n_words * 2];
unroll! {
for i in 0..$n_words {
let mut carry = 0u64;
let (b_u, b_l) = $crate::split(you[i]);
let b = you[i];
unroll! {
for j in 0..$n_words {
if me[j] != 0 || carry != 0 {
let a = $crate::split(me[j]);
if $check(me[j], carry) {
let a = me[j];
// multiply parts
let (c_l, overflow_l) = $crate::mul_u32(a, b_l, ret[i + j]);
let (c_u, overflow_u) = $crate::mul_u32(a, b_u, c_l >> 32);
ret[i + j] = (c_l & 0xFFFFFFFF) + (c_u << 32);
let (hi, low) = $crate::split_u128(a as u128 * b as u128);
// No overflow here
let res = (c_u >> 32) + (overflow_u << 32);
// possible overflows
let (res, o1) = res.overflowing_add(overflow_l + carry);
let (res, o2) = res.overflowing_add(ret[i + j + 1]);
ret[i + j + 1] = res;
let overflow = {
let existing_low = &mut ret[i + j];
let (low, o) = low.overflowing_add(*existing_low);
*existing_low = low;
o
};
// Only single overflow possible there
carry = (o1 | o2) as u64;
carry = {
let existing_hi = &mut ret[i + j + 1];
let hi = hi + overflow as u64;
let (hi, o0) = hi.overflowing_add(carry);
let (hi, o1) = hi.overflowing_add(*existing_hi);
*existing_hi = hi;
(o0 | o1) as u64
}
}
}
}
@ -466,7 +198,7 @@ macro_rules! uint_full_mul_reg {
}
ret
}})
}});
}
#[macro_export]
@ -606,12 +338,19 @@ pub fn split(a: u64) -> (u64, u64) {
(a >> 32, a & 0xFFFF_FFFF)
}
#[inline(always)]
#[doc(hidden)]
pub fn split_u128(a: u128) -> (u64, u64) {
((a >> 64) as _, (a & 0xFFFFFFFFFFFFFFFF) as _)
}
#[macro_export]
macro_rules! construct_uint {
($name:ident, $n_words: tt) => (
/// Little-endian large integer type
#[repr(C)]
#[derive(Copy, Clone, Eq, PartialEq, Hash)]
// TODO: serialize stuff? #[cfg_attr(feature="serialize", derive(Serialize, Deserialize))]
pub struct $name(pub [u64; $n_words]);
impl AsRef<$name> for $name {
@ -627,6 +366,7 @@ macro_rules! construct_uint {
}
impl $name {
pub const MAX: $name = $name([u64::max_value(); $n_words]);
/// Convert from a decimal string.
pub fn from_dec_str(value: &str) -> Result<Self, $crate::FromDecStrErr> {
if !value.bytes().all(|b| b >= 48 && b <= 57) {
@ -1066,6 +806,13 @@ macro_rules! construct_uint {
}
}
impl From<$name> for [u8; $n_words * 8] {
fn from(number: $name) -> Self {
let mut arr = [0u8; $n_words * 8];
number.to_big_endian(&mut arr);
arr
}
}
impl Default for $name {
fn default() -> Self {
$name::zero()
@ -1464,6 +1211,13 @@ macro_rules! impl_std_for_uint_internals {
}
}
#[cfg(not(feature="std"))]
#[macro_export]
#[doc(hidden)]
macro_rules! impl_std_for_uint_internals {
($name: ident, $n_words: tt) => {}
}
#[cfg(feature="std")]
#[macro_export]
#[doc(hidden)]
@ -1471,7 +1225,7 @@ macro_rules! impl_std_for_uint {
($name: ident, $n_words: tt) => {
impl ::core::fmt::Debug for $name {
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
write!(f, "{:#x}", self)
::core::fmt::Display::fmt(self, f)
}
}
@ -1481,16 +1235,24 @@ macro_rules! impl_std_for_uint {
return write!(f, "0");
}
let mut s = String::new();
let mut buf = [0_u8; $n_words*20];
let mut i = buf.len() - 1;
let mut current = *self;
let ten = $name::from(10);
while !current.is_zero() {
s = format!("{}{}", (current % ten).low_u32(), s);
loop {
let digit = (current % ten).low_u64() as u8;
buf[i] = digit + b'0';
current = current / ten;
if current.is_zero() {
break;
}
i -= 1;
}
write!(f, "{}", s)
// sequence of `'0'..'9'` chars is guaranteed to be a valid UTF8 string
let s = unsafe {::core::str::from_utf8_unchecked(&buf[i..])};
f.write_str(s)
}
}
@ -1499,10 +1261,9 @@ macro_rules! impl_std_for_uint {
fn from_str(value: &str) -> Result<$name, Self::Err> {
use $crate::rustc_hex::FromHex;
let bytes: Vec<u8> = match value.len() % 2 == 0 {
true => try!(value.from_hex()),
false => try!(("0".to_owned() + value).from_hex())
true => value.from_hex()?,
false => ("0".to_owned() + value).from_hex()?
};
let bytes_ref: &[u8] = &bytes;
@ -1553,12 +1314,6 @@ macro_rules! impl_std_for_uint {
($name: ident, $n_words: tt) => {}
}
#[cfg(not(feature="std"))]
#[macro_export]
#[doc(hidden)]
macro_rules! impl_std_for_uint_internals {
($name: ident, $n_words: tt) => {}
}
#[cfg(feature="heapsizeof")]
#[macro_export]
@ -1619,3 +1374,6 @@ macro_rules! impl_quickcheck_arbitrary_for_uint {
macro_rules! impl_quickcheck_arbitrary_for_uint {
($uint: ty, $n_bytes: tt) => {}
}
construct_uint!(U256, 4);
construct_uint!(U512, 8);

View File

@ -4,17 +4,15 @@ extern crate core;
extern crate uint;
#[macro_use]
extern crate crunchy;
#[cfg(feature = "impl_quickcheck_arbitrary")]
#[macro_use]
extern crate quickcheck;
use std::u64::MAX;
use std::str::FromStr;
use uint::FromDecStrErr;
use core::u64::MAX;
use core::str::FromStr;
use uint::{U256, U512, FromDecStrErr};
#[cfg(feature="std")]
construct_uint!(U128, 2);
construct_uint!(U256, 4);
construct_uint!(U512, 8);
#[test]
fn uint256_checked_ops() {
@ -347,7 +345,8 @@ fn uint256_pow_overflow_panic() {
fn should_format_and_debug_correctly() {
let test = |x: usize, hex: &'static str, display: &'static str| {
assert_eq!(format!("{}", U256::from(x)), display);
assert_eq!(format!("{:?}", U256::from(x)), format!("0x{}", hex));
// TODO: proper impl for Debug so we get this to pass: assert_eq!(format!("{:?}", U256::from(x)), format!("0x{}", hex));
assert_eq!(format!("{:?}", U256::from(x)), display);
assert_eq!(format!("{:x}", U256::from(x)), hex);
assert_eq!(format!("{:#x}", U256::from(x)), format!("0x{}", hex));
};
@ -361,6 +360,30 @@ fn should_format_and_debug_correctly() {
test(0x1000, "1000", "4096");
}
#[test]
pub fn display_u128() {
let expected = "340282366920938463463374607431768211455";
let value = U128::MAX;
assert_eq!(format!("{}", value), expected);
assert_eq!(format!("{:?}", value), expected);
}
#[test]
pub fn display_u256() {
let expected = "115792089237316195423570985008687907853269984665640564039457584007913129639935";
let value = U256::MAX;
assert_eq!(format!("{}", value), expected);
assert_eq!(format!("{:?}", value), expected);
}
#[test]
pub fn display_u512() {
let expected = "13407807929942597099574024998205846127479365820592393377723561443721764030073546976801874298166903427690031858186486050853753882811946569946433649006084095";
let value = U512::MAX;
assert_eq!(format!("{}", value), expected);
assert_eq!(format!("{:?}", value), expected);
}
#[test]
fn uint256_overflowing_pow() {
assert_eq!(
@ -977,6 +1000,18 @@ fn from_big_endian() {
assert_eq!(U256::from(1), number);
}
#[test]
fn from_fixed_array() {
let expected: [u8; 32] = [
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 1,
];
let ary : [u8; 32] = U256::from(1).into();
assert_eq!(ary, expected);
}
#[test]
fn leading_zeros() {
assert_eq!(U256::from("000000000000000000000001adbdd6bd6ff027485484b97f8a6a4c7129756dd1").leading_zeros(), 95);