diff --git a/src/bytes.rs b/src/bytes.rs index 06735995f..52dad3cb9 100644 --- a/src/bytes.rs +++ b/src/bytes.rs @@ -8,6 +8,7 @@ use std::fmt; use std::error::Error as StdError; +use uint::{U128, U256}; /// TODO: optimise some conversations pub trait ToBytes { @@ -82,6 +83,26 @@ impl_map_to_bytes!(usize, u64); impl_map_to_bytes!(u16, u64); impl_map_to_bytes!(u32, u64); +macro_rules! impl_uint_to_bytes { + ($name: ident) => { + impl ToBytes for $name { + fn to_bytes(&self) -> Vec { + let mut res= vec![]; + let count = self.to_bytes_len(); + for i in 0..count { + let j = count - 1 - i; + res.push(self.byte(j)); + } + res + } + fn to_bytes_len(&self) -> usize { (self.bits() + 7) / 8 } + } + } +} + +impl_uint_to_bytes!(U256); +impl_uint_to_bytes!(U128); + #[derive(Debug, PartialEq, Eq)] pub enum FromBytesError { UnexpectedEnd @@ -101,6 +122,7 @@ pub type FromBytesResult = Result; /// implements "Sized", so the compiler can deducate the size /// of the return type +/// TODO: check size of bytes before conversation and return appropriate error pub trait FromBytes: Sized { fn from_bytes(bytes: &[u8]) -> FromBytesResult; } @@ -149,3 +171,16 @@ macro_rules! impl_map_from_bytes { impl_map_from_bytes!(usize, u64); impl_map_from_bytes!(u16, u64); impl_map_from_bytes!(u32, u64); + +macro_rules! impl_uint_from_bytes { + ($name: ident) => { + impl FromBytes for $name { + fn from_bytes(bytes: &[u8]) -> FromBytesResult<$name> { + Ok($name::from(bytes)) + } + } + } +} + +impl_uint_from_bytes!(U256); +impl_uint_from_bytes!(U128); diff --git a/src/rlp.rs b/src/rlp.rs index cd83a8c7e..03a10348c 100644 --- a/src/rlp.rs +++ b/src/rlp.rs @@ -522,8 +522,10 @@ impl Encoder for BasicEncoder { #[cfg(test)] mod tests { use std::{fmt, cmp}; + use std::str::FromStr; use rlp; use rlp::{Rlp, RlpStream, Decodable}; + use uint::U256; #[test] fn rlp_at() { @@ -643,6 +645,21 @@ mod tests { run_encode_tests(tests); } + #[test] + fn encode_u256() { + let tests = vec![ + ETestPair(U256::from(0u64), vec![0x80u8]), + ETestPair(U256::from(0x1000000u64), vec![0x84, 0x01, 0x00, 0x00, 0x00]), + ETestPair(U256::from(0xffffffffu64), vec![0x84, 0xff, 0xff, 0xff, 0xff]), + ETestPair(U256::from_str("8090a0b0c0d0e0f00910203040506077000000000000000100000000000012f0").unwrap(), + vec![0xa0, 0x80, 0x90, 0xa0, 0xb0, 0xc0, 0xd0, 0xe0, 0xf0, + 0x09, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x77, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0xf0]) + ]; + run_encode_tests(tests); + } + #[test] fn encode_str() { let tests = vec![ @@ -769,6 +786,21 @@ mod tests { run_decode_tests(tests); } + #[test] + fn decode_u256() { + let tests = vec![ + DTestPair(U256::from(0u64), vec![0x80u8]), + DTestPair(U256::from(0x1000000u64), vec![0x84, 0x01, 0x00, 0x00, 0x00]), + DTestPair(U256::from(0xffffffffu64), vec![0x84, 0xff, 0xff, 0xff, 0xff]), + DTestPair(U256::from_str("8090a0b0c0d0e0f00910203040506077000000000000000100000000000012f0").unwrap(), + vec![0xa0, 0x80, 0x90, 0xa0, 0xb0, 0xc0, 0xd0, 0xe0, 0xf0, + 0x09, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x77, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0xf0]) + ]; + run_decode_tests(tests); + } + #[test] fn decode_str() { let tests = vec![ diff --git a/src/uint.rs b/src/uint.rs index 149ff5efb..daba98b63 100644 --- a/src/uint.rs +++ b/src/uint.rs @@ -180,6 +180,12 @@ macro_rules! construct_uint { arr[index / 64] & (1 << (index % 64)) != 0 } + #[inline] + pub fn byte(&self, index: usize) -> u8 { + let &$name(ref arr) = self; + (arr[index / 8] >> ((index % 8)) * 8) as u8 + } + /// Multiplication by u32 fn mul_u32(self, other: u32) -> $name { let $name(ref arr) = self; @@ -507,6 +513,7 @@ mod tests { #[test] pub fn uint256_bits_test() { + assert_eq!(U256::from(0u64).bits(), 0); assert_eq!(U256::from(255u64).bits(), 8); assert_eq!(U256::from(256u64).bits(), 9); assert_eq!(U256::from(300u64).bits(), 9); @@ -523,11 +530,22 @@ mod tests { assert_eq!(shl.bits(), 0); //// Bit set check + //// 01010 assert!(!U256::from(10u8).bit(0)); assert!(U256::from(10u8).bit(1)); assert!(!U256::from(10u8).bit(2)); assert!(U256::from(10u8).bit(3)); assert!(!U256::from(10u8).bit(4)); + + //// byte check + assert_eq!(U256::from(10u8).byte(0), 10); + assert_eq!(U256::from(0xffu64).byte(0), 0xff); + assert_eq!(U256::from(0xffu64).byte(1), 0); + assert_eq!(U256::from(0x01ffu64).byte(0), 0xff); + assert_eq!(U256::from(0x01ffu64).byte(1), 0x1); + assert_eq!(U256([0u64, 0xfc, 0, 0]).byte(8), 0xfc); + assert_eq!(U256([0u64, 0, 0, u64::max_value()]).byte(31), 0xff); + assert_eq!(U256([0u64, 0, 0, (u64::max_value() >> 8) + 1]).byte(31), 0x01); } #[test]