diff --git a/.travis.yml b/.travis.yml index 2b14aa1..c54a3b6 100644 --- a/.travis.yml +++ b/.travis.yml @@ -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 .. diff --git a/uint/Cargo.toml b/uint/Cargo.toml index 8623c94..190841e 100644 --- a/uint/Cargo.toml +++ b/uint/Cargo.toml @@ -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 "] -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]] diff --git a/uint/README.md b/uint/README.md index 4a0388b..9ba5885 100644 --- a/uint/README.md +++ b/uint/README.md @@ -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`. \ No newline at end of file diff --git a/uint/benches/bigint.rs b/uint/benches/bigint.rs new file mode 100644 index 0000000..be8490b --- /dev/null +++ b/uint/benches/bigint.rs @@ -0,0 +1,230 @@ +// Copyright 2015-2017 Parity Technologies +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , 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[..]); + }); +} diff --git a/uint/build.rs b/uint/build.rs deleted file mode 100644 index 3ba1687..0000000 --- a/uint/build.rs +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright 2015-2017 Parity Technologies -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , 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"); - } - } -} diff --git a/uint/src/lib.rs b/uint/src/lib.rs index 40a3a8d..e53f3c8 100644 --- a/uint/src/lib.rs +++ b/uint/src/lib.rs @@ -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::*; diff --git a/uint/src/uint.rs b/uint/src/uint.rs index 9a72a99..dc2db06 100644 --- a/uint/src/uint.rs +++ b/uint/src/uint.rs @@ -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 { 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 = 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); \ No newline at end of file diff --git a/uint/tests/uint_tests.rs b/uint/tests/uint_tests.rs index 718cb8d..fdf1b71 100644 --- a/uint/tests/uint_tests.rs +++ b/uint/tests/uint_tests.rs @@ -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);