diff --git a/src/block.rs b/src/block.rs index b1db20fd7..963124be0 100644 --- a/src/block.rs +++ b/src/block.rs @@ -45,14 +45,14 @@ impl Decodable for Block { if decoder.as_raw().len() != try!(decoder.as_rlp().payload_info()).total() { return Err(DecoderError::RlpIsTooBig); } - let d = try!(decoder.as_list()); - if d.len() != 3 { + let d = decoder.as_rlp(); + if d.item_count() != 3 { return Err(DecoderError::RlpIncorrectListLen); } Ok(Block { - header: try!(Decodable::decode(&d[0])), - transactions: try!(Decodable::decode(&d[1])), - uncles: try!(Decodable::decode(&d[2])), + header: try!(d.val_at(0)), + transactions: try!(d.val_at(1)), + uncles: try!(d.val_at(2)), }) } } diff --git a/src/extras.rs b/src/extras.rs index d571e7c36..4459826cc 100644 --- a/src/extras.rs +++ b/src/extras.rs @@ -133,12 +133,12 @@ impl HeapSizeOf for BlockDetails { impl Decodable for BlockDetails { fn decode(decoder: &D) -> Result where D: Decoder { - let d = try!(decoder.as_list()); + let d = decoder.as_rlp(); let details = BlockDetails { - number: try!(Decodable::decode(&d[0])), - total_difficulty: try!(Decodable::decode(&d[1])), - parent: try!(Decodable::decode(&d[2])), - children: try!(Decodable::decode(&d[3])) + number: try!(d.val_at(0)), + total_difficulty: try!(d.val_at(1)), + parent: try!(d.val_at(2)), + children: try!(d.val_at(3)), }; Ok(details) } @@ -257,10 +257,10 @@ impl HeapSizeOf for TransactionAddress { impl Decodable for TransactionAddress { fn decode(decoder: &D) -> Result where D: Decoder { - let d = try!(decoder.as_list()); + let d = decoder.as_rlp(); let tx_address = TransactionAddress { - block_hash: try!(Decodable::decode(&d[0])), - index: try!(Decodable::decode(&d[1])) + block_hash: try!(d.val_at(0)), + index: try!(d.val_at(1)), }; Ok(tx_address) diff --git a/src/transaction.rs b/src/transaction.rs index 3085bc461..24b617f67 100644 --- a/src/transaction.rs +++ b/src/transaction.rs @@ -267,20 +267,20 @@ impl Decodable for Action { impl Decodable for Transaction { fn decode(decoder: &D) -> Result where D: Decoder { - let d = try!(decoder.as_list()); - if d.len() != 9 { + let d = decoder.as_rlp(); + if d.item_count() != 9 { return Err(DecoderError::RlpIncorrectListLen); } Ok(Transaction { - nonce: try!(Decodable::decode(&d[0])), - gas_price: try!(Decodable::decode(&d[1])), - gas: try!(Decodable::decode(&d[2])), - action: try!(Decodable::decode(&d[3])), - value: try!(Decodable::decode(&d[4])), - data: try!(Decodable::decode(&d[5])), - v: try!(u16::decode(&d[6])) as u8, - r: try!(Decodable::decode(&d[7])), - s: try!(Decodable::decode(&d[8])), + nonce: try!(d.val_at(0)), + gas_price: try!(d.val_at(1)), + gas: try!(d.val_at(2)), + action: try!(d.val_at(3)), + value: try!(d.val_at(4)), + data: try!(d.val_at(5)), + v: try!(d.val_at(6)), + r: try!(d.val_at(7)), + s: try!(d.val_at(8)), hash: RefCell::new(None), sender: RefCell::new(None), }) diff --git a/util/src/bytes.rs b/util/src/bytes.rs index 102206f6c..050c07a66 100644 --- a/util/src/bytes.rs +++ b/util/src/bytes.rs @@ -11,37 +11,14 @@ //! let slice: &[u8] = arr.bytes(); //! } //! -//! fn to_bytes() { -//! use util::bytes::ToBytes; -//! -//! let mut out: Vec = Vec::new(); -//! "hello_world".to_bytes(&mut out); -//! 400u32.to_bytes(&mut out); -//! 0xffffffffffffffffu64.to_bytes(&mut out); -//! } -//! -//! fn from_bytes() { -//! use util::bytes::FromBytes; -//! -//! let a = String::from_bytes(&[b'd', b'o', b'g']); -//! let b = u16::from_bytes(&[0xfa]); -//! let c = u64::from_bytes(&[0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff]); -//! } -//! //! fn main() { //! bytes_convertable(); -//! to_bytes(); -//! from_bytes(); //! } //! ``` -use std::mem; use std::fmt; use std::slice; -use std::cmp::Ordering; -use std::error::Error as StdError; use std::ops::{Deref, DerefMut}; -use uint::{Uint, U128, U256}; use hash::FixedHash; use elastic_array::*; @@ -205,213 +182,6 @@ fn bytes_convertable() { assert_eq!([0u8; 0].bytes(), &[]); } -/// Converts given type to its shortest representation in bytes -/// -/// TODO: optimise some conversations -pub trait ToBytes { - /// Serialize self to byte array - fn to_bytes>(&self, out: &mut V); - /// Get length of serialized data in bytes - fn to_bytes_len(&self) -> usize; -} - -impl <'a> ToBytes for &'a str { - fn to_bytes>(&self, out: &mut V) { - out.vec_extend(self.as_bytes()); - } - - fn to_bytes_len(&self) -> usize { - self.as_bytes().len() - } -} - -impl ToBytes for String { - fn to_bytes>(&self, out: &mut V) { - out.vec_extend(self.as_bytes()); - } - - fn to_bytes_len(&self) -> usize { - self.len() - } -} - -impl ToBytes for u64 { - fn to_bytes>(&self, out: &mut V) { - let count = self.to_bytes_len(); - for i in 0..count { - let j = count - 1 - i; - out.vec_push((*self >> (j * 8)) as u8); - } - } - - fn to_bytes_len(&self) -> usize { 8 - self.leading_zeros() as usize / 8 } -} - -impl ToBytes for bool { - fn to_bytes>(&self, out: &mut V) { - out.vec_push(if *self { 1u8 } else { 0u8 }) - } - - fn to_bytes_len(&self) -> usize { 1 } -} - -macro_rules! impl_map_to_bytes { - ($from: ident, $to: ty) => { - impl ToBytes for $from { - fn to_bytes>(&self, out: &mut V) { - (*self as $to).to_bytes(out) - } - - fn to_bytes_len(&self) -> usize { (*self as $to).to_bytes_len() } - } - } -} - -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, out: &mut V) { - let count = self.to_bytes_len(); - for i in 0..count { - let j = count - 1 - i; - out.vec_push(self.byte(j)); - } - } - fn to_bytes_len(&self) -> usize { (self.bits() + 7) / 8 } - } - } -} - -impl_uint_to_bytes!(U256); -impl_uint_to_bytes!(U128); - -impl ToBytes for T where T: FixedHash { - fn to_bytes>(&self, out: &mut V) { - out.vec_extend(self.bytes()); - } - fn to_bytes_len(&self) -> usize { self.bytes().len() } -} - -/// Error returned when FromBytes conversation goes wrong -#[derive(Debug, PartialEq, Eq)] -pub enum FromBytesError { - /// TODO [debris] Please document me - DataIsTooShort, - /// TODO [debris] Please document me - DataIsTooLong, - /// Integer-representation is non-canonically prefixed with zero byte(s). - ZeroPrefixedInt, -} - -impl StdError for FromBytesError { - fn description(&self) -> &str { "from_bytes error" } -} - -impl fmt::Display for FromBytesError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - fmt::Debug::fmt(&self, f) - } -} - -/// Alias for the result of FromBytes trait -pub type FromBytesResult = Result; - -/// Converts to given type from its bytes representation -/// -/// TODO: check size of bytes before conversation and return appropriate error -pub trait FromBytes: Sized { - /// TODO [debris] Please document me - fn from_bytes(bytes: &[u8]) -> FromBytesResult; -} - -impl FromBytes for String { - fn from_bytes(bytes: &[u8]) -> FromBytesResult { - Ok(::std::str::from_utf8(bytes).unwrap().to_owned()) - } -} - -macro_rules! impl_uint_from_bytes { - ($to: ident) => { - impl FromBytes for $to { - fn from_bytes(bytes: &[u8]) -> FromBytesResult<$to> { - match bytes.len() { - 0 => Ok(0), - l if l <= mem::size_of::<$to>() => { - if bytes[0] == 0 { - return Err(FromBytesError::ZeroPrefixedInt) - } - let mut res = 0 as $to; - for i in 0..l { - let shift = (l - 1 - i) * 8; - res = res + ((bytes[i] as $to) << shift); - } - Ok(res) - } - _ => Err(FromBytesError::DataIsTooLong) - } - } - } - } -} - -impl FromBytes for bool { - fn from_bytes(bytes: &[u8]) -> FromBytesResult { - match bytes.len() { - 0 => Ok(false), - 1 => Ok(bytes[0] != 0), - _ => Err(FromBytesError::DataIsTooLong), - } - } -} - -//impl_uint_from_bytes!(u8); -impl_uint_from_bytes!(u16); -impl_uint_from_bytes!(u32); -impl_uint_from_bytes!(u64); -impl_uint_from_bytes!(usize); - -macro_rules! impl_uint_from_bytes { - ($name: ident) => { - impl FromBytes for $name { - fn from_bytes(bytes: &[u8]) -> FromBytesResult<$name> { - if !bytes.is_empty() && bytes[0] == 0 { - Err(FromBytesError::ZeroPrefixedInt) - } else if bytes.len() <= $name::SIZE { - Ok($name::from(bytes)) - } else { - Err(FromBytesError::DataIsTooLong) - } - } - } - } -} - -impl_uint_from_bytes!(U256); -impl_uint_from_bytes!(U128); - -impl FromBytes for T where T: FixedHash { - fn from_bytes(bytes: &[u8]) -> FromBytesResult { - match bytes.len().cmp(&T::size()) { - Ordering::Less => return Err(FromBytesError::DataIsTooShort), - Ordering::Greater => return Err(FromBytesError::DataIsTooLong), - Ordering::Equal => () - }; - - unsafe { - use std::{mem, ptr}; - - let mut res: T = mem::uninitialized(); - ptr::copy(bytes.as_ptr(), res.as_slice_mut().as_mut_ptr(), T::size()); - - Ok(res) - } - } -} - /// Simple trait to allow for raw population of a Sized object from a byte slice. pub trait Populatable { /// Copies a bunch of bytes `d` to `self`, overwriting as necessary. diff --git a/util/src/network/session.rs b/util/src/network/session.rs index 09b7af5d3..fb385b487 100644 --- a/util/src/network/session.rs +++ b/util/src/network/session.rs @@ -57,11 +57,10 @@ pub struct PeerCapabilityInfo { impl Decodable for PeerCapabilityInfo { fn decode(decoder: &D) -> Result where D: Decoder { - let c = try!(decoder.as_list()); - let v: u32 = try!(Decodable::decode(&c[1])); + let c = decoder.as_rlp(); Ok(PeerCapabilityInfo { - protocol: try!(Decodable::decode(&c[0])), - version: v as u8, + protocol: try!(c.val_at(0)), + version: try!(c.val_at(1)) }) } } diff --git a/util/src/rlp/bytes.rs b/util/src/rlp/bytes.rs new file mode 100644 index 000000000..69562764c --- /dev/null +++ b/util/src/rlp/bytes.rs @@ -0,0 +1,255 @@ +//! Unified interfaces for RLP bytes operations on basic types +//! + +use std::mem; +use std::fmt; +use std::cmp::Ordering; +use std::error::Error as StdError; +use uint::{Uint, U128, U256}; +use hash::FixedHash; +use elastic_array::*; + +/// Vector like object +pub trait VecLike { + /// Add an element to the collection + fn vec_push(&mut self, value: T); + + /// Add a slice to the collection + fn vec_extend(&mut self, slice: &[T]); +} + +impl VecLike for Vec where T: Copy { + fn vec_push(&mut self, value: T) { + Vec::::push(self, value) + } + + fn vec_extend(&mut self, slice: &[T]) { + Vec::::extend_from_slice(self, slice) + } +} + +macro_rules! impl_veclike_for_elastic_array { + ($from: ident) => { + impl VecLike for $from where T: Copy { + fn vec_push(&mut self, value: T) { + $from::::push(self, value) + } + fn vec_extend(&mut self, slice: &[T]) { + $from::::append_slice(self, slice) + + } + } + } +} + +impl_veclike_for_elastic_array!(ElasticArray16); +impl_veclike_for_elastic_array!(ElasticArray32); +impl_veclike_for_elastic_array!(ElasticArray1024); + +/// Converts given type to its shortest representation in bytes +/// +/// TODO: optimise some conversations +pub trait ToBytes { + /// Serialize self to byte array + fn to_bytes>(&self, out: &mut V); + /// Get length of serialized data in bytes + fn to_bytes_len(&self) -> usize; +} + +impl <'a> ToBytes for &'a str { + fn to_bytes>(&self, out: &mut V) { + out.vec_extend(self.as_bytes()); + } + + fn to_bytes_len(&self) -> usize { + self.as_bytes().len() + } +} + +impl ToBytes for String { + fn to_bytes>(&self, out: &mut V) { + out.vec_extend(self.as_bytes()); + } + + fn to_bytes_len(&self) -> usize { + self.len() + } +} + +impl ToBytes for u64 { + fn to_bytes>(&self, out: &mut V) { + let count = self.to_bytes_len(); + for i in 0..count { + let j = count - 1 - i; + out.vec_push((*self >> (j * 8)) as u8); + } + } + + fn to_bytes_len(&self) -> usize { 8 - self.leading_zeros() as usize / 8 } +} + +impl ToBytes for bool { + fn to_bytes>(&self, out: &mut V) { + out.vec_push(if *self { 1u8 } else { 0u8 }) + } + + fn to_bytes_len(&self) -> usize { 1 } +} + +macro_rules! impl_map_to_bytes { + ($from: ident, $to: ty) => { + impl ToBytes for $from { + fn to_bytes>(&self, out: &mut V) { + (*self as $to).to_bytes(out) + } + + fn to_bytes_len(&self) -> usize { (*self as $to).to_bytes_len() } + } + } +} + +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, out: &mut V) { + let count = self.to_bytes_len(); + for i in 0..count { + let j = count - 1 - i; + out.vec_push(self.byte(j)); + } + } + fn to_bytes_len(&self) -> usize { (self.bits() + 7) / 8 } + } + } +} + +impl_uint_to_bytes!(U256); +impl_uint_to_bytes!(U128); + +impl ToBytes for T where T: FixedHash { + fn to_bytes>(&self, out: &mut V) { + out.vec_extend(self.bytes()); + } + fn to_bytes_len(&self) -> usize { self.bytes().len() } +} + +/// Error returned when FromBytes conversation goes wrong +#[derive(Debug, PartialEq, Eq)] +pub enum FromBytesError { + /// TODO [debris] Please document me + DataIsTooShort, + /// TODO [debris] Please document me + DataIsTooLong, + /// Integer-representation is non-canonically prefixed with zero byte(s). + ZeroPrefixedInt, +} + +impl StdError for FromBytesError { + fn description(&self) -> &str { "from_bytes error" } +} + +impl fmt::Display for FromBytesError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fmt::Debug::fmt(&self, f) + } +} + +/// Alias for the result of FromBytes trait +pub type FromBytesResult = Result; + +/// Converts to given type from its bytes representation +/// +/// TODO: check size of bytes before conversation and return appropriate error +pub trait FromBytes: Sized { + /// TODO [debris] Please document me + fn from_bytes(bytes: &[u8]) -> FromBytesResult; +} + +impl FromBytes for String { + fn from_bytes(bytes: &[u8]) -> FromBytesResult { + Ok(::std::str::from_utf8(bytes).unwrap().to_owned()) + } +} + +macro_rules! impl_uint_from_bytes { + ($to: ident) => { + impl FromBytes for $to { + fn from_bytes(bytes: &[u8]) -> FromBytesResult<$to> { + match bytes.len() { + 0 => Ok(0), + l if l <= mem::size_of::<$to>() => { + if bytes[0] == 0 { + return Err(FromBytesError::ZeroPrefixedInt) + } + let mut res = 0 as $to; + for i in 0..l { + let shift = (l - 1 - i) * 8; + res = res + ((bytes[i] as $to) << shift); + } + Ok(res) + } + _ => Err(FromBytesError::DataIsTooLong) + } + } + } + } +} + +impl FromBytes for bool { + fn from_bytes(bytes: &[u8]) -> FromBytesResult { + match bytes.len() { + 0 => Ok(false), + 1 => Ok(bytes[0] != 0), + _ => Err(FromBytesError::DataIsTooLong), + } + } +} + +//impl_uint_from_bytes!(u8); +impl_uint_from_bytes!(u16); +impl_uint_from_bytes!(u32); +impl_uint_from_bytes!(u64); +impl_uint_from_bytes!(usize); + +macro_rules! impl_uint_from_bytes { + ($name: ident) => { + impl FromBytes for $name { + fn from_bytes(bytes: &[u8]) -> FromBytesResult<$name> { + if !bytes.is_empty() && bytes[0] == 0 { + Err(FromBytesError::ZeroPrefixedInt) + } else if bytes.len() <= $name::SIZE { + Ok($name::from(bytes)) + } else { + Err(FromBytesError::DataIsTooLong) + } + } + } + } +} + +impl_uint_from_bytes!(U256); +impl_uint_from_bytes!(U128); + +impl FromBytes for T where T: FixedHash { + fn from_bytes(bytes: &[u8]) -> FromBytesResult { + match bytes.len().cmp(&T::size()) { + Ordering::Less => return Err(FromBytesError::DataIsTooShort), + Ordering::Greater => return Err(FromBytesError::DataIsTooLong), + Ordering::Equal => () + }; + + unsafe { + use std::{mem, ptr}; + + let mut res: T = mem::uninitialized(); + ptr::copy(bytes.as_ptr(), res.as_slice_mut().as_mut_ptr(), T::size()); + + Ok(res) + } + } +} + diff --git a/util/src/rlp/mod.rs b/util/src/rlp/mod.rs index 88872c2d1..f6101abc6 100644 --- a/util/src/rlp/mod.rs +++ b/util/src/rlp/mod.rs @@ -30,22 +30,18 @@ //! * You want to get view onto rlp-slice. //! * You don't want to decode whole rlp at once. -/// TODO [Gav Wood] Please document me pub mod rlptraits; -/// TODO [Gav Wood] Please document me -pub mod rlperrors; -/// TODO [debris] Please document me -pub mod rlpin; -/// TODO [debris] Please document me -pub mod untrusted_rlp; -/// TODO [debris] Please document me -pub mod rlpstream; +mod rlperrors; +mod rlpin; +mod untrusted_rlp; +mod rlpstream; +mod bytes; #[cfg(test)] mod tests; pub use self::rlperrors::DecoderError; -pub use self::rlptraits::{Decoder, Decodable, View, Stream, Encodable, Encoder, RlpEncodable}; +pub use self::rlptraits::{Decoder, Decodable, View, Stream, Encodable, Encoder, RlpEncodable, RlpDecodable}; pub use self::untrusted_rlp::{UntrustedRlp, UntrustedRlpIterator, PayloadInfo, Prototype}; pub use self::rlpin::{Rlp, RlpIterator}; pub use self::rlpstream::{RlpStream}; @@ -73,7 +69,7 @@ pub const SHA3_EMPTY_LIST_RLP: H256 = H256( [0x1d, 0xcc, 0x4d, 0xe8, 0xde, 0xc7, /// assert_eq!(animals, vec!["cat".to_string(), "dog".to_string()]); /// } /// ``` -pub fn decode(bytes: &[u8]) -> T where T: Decodable { +pub fn decode(bytes: &[u8]) -> T where T: RlpDecodable { let rlp = Rlp::new(bytes); rlp.as_val() } diff --git a/util/src/rlp/rlperrors.rs b/util/src/rlp/rlperrors.rs index 6ac162236..f5d4629ad 100644 --- a/util/src/rlp/rlperrors.rs +++ b/util/src/rlp/rlperrors.rs @@ -1,6 +1,6 @@ use std::fmt; use std::error::Error as StdError; -use bytes::FromBytesError; +use rlp::bytes::FromBytesError; #[derive(Debug, PartialEq, Eq)] /// TODO [debris] Please document me diff --git a/util/src/rlp/rlpin.rs b/util/src/rlp/rlpin.rs index 5cecce44f..cfcaee014 100644 --- a/util/src/rlp/rlpin.rs +++ b/util/src/rlp/rlpin.rs @@ -1,5 +1,5 @@ use std::fmt; -use rlp::{View, Decodable, DecoderError, UntrustedRlp, PayloadInfo, Prototype}; +use rlp::{View, DecoderError, UntrustedRlp, PayloadInfo, Prototype, RlpDecodable}; impl<'a> From> for Rlp<'a> { fn from(rlp: UntrustedRlp<'a>) -> Rlp<'a> { @@ -88,28 +88,28 @@ impl<'a, 'view> View<'a, 'view> for Rlp<'a> where 'a: 'view { self.into_iter() } - fn as_val(&self) -> Result where T: Decodable { + fn as_val(&self) -> Result where T: RlpDecodable { self.rlp.as_val() } - fn val_at(&self, index: usize) -> Result where T: Decodable { + fn val_at(&self, index: usize) -> Result where T: RlpDecodable { self.at(index).rlp.as_val() } } impl <'a, 'view> Rlp<'a> where 'a: 'view { - fn view_as_val(r: &R) -> T where R: View<'a, 'view>, T: Decodable { + fn view_as_val(r: &R) -> T where R: View<'a, 'view>, T: RlpDecodable { let res: Result = r.as_val(); res.unwrap_or_else(|_| panic!()) } /// TODO [debris] Please document me - pub fn as_val(&self) -> T where T: Decodable { + pub fn as_val(&self) -> T where T: RlpDecodable { Self::view_as_val(self) } /// TODO [debris] Please document me - pub fn val_at(&self, index: usize) -> T where T: Decodable { + pub fn val_at(&self, index: usize) -> T where T: RlpDecodable { Self::view_as_val(&self.at(index)) } } diff --git a/util/src/rlp/rlpstream.rs b/util/src/rlp/rlpstream.rs index 5eb071389..b6b500a74 100644 --- a/util/src/rlp/rlpstream.rs +++ b/util/src/rlp/rlpstream.rs @@ -1,6 +1,6 @@ use std::ops::Deref; use elastic_array::*; -use bytes::{ToBytes, VecLike}; +use rlp::bytes::{ToBytes, VecLike}; use rlp::{Stream, Encoder, Encodable}; use rlp::rlptraits::{ByteEncodable, RlpEncodable}; diff --git a/util/src/rlp/rlptraits.rs b/util/src/rlp/rlptraits.rs index f79c7848c..17acbb40b 100644 --- a/util/src/rlp/rlptraits.rs +++ b/util/src/rlp/rlptraits.rs @@ -1,7 +1,8 @@ +//! Common RLP traits use std::ops::Deref; -use bytes::VecLike; +use rlp::bytes::VecLike; use rlp::{DecoderError, UntrustedRlp}; -use rlpstream::RlpStream; +use rlp::rlpstream::RlpStream; use elastic_array::ElasticArray1024; use hash::H256; use sha3::*; @@ -12,17 +13,21 @@ pub trait Decoder: Sized { fn read_value(&self, f: F) -> Result where F: FnOnce(&[u8]) -> Result; - /// TODO [arkpar] Please document me - fn as_list(&self) -> Result, DecoderError>; /// TODO [Gav Wood] Please document me fn as_rlp(&self) -> &UntrustedRlp; /// TODO [debris] Please document me fn as_raw(&self) -> &[u8]; } -/// TODO [debris] Please document me +/// RLP decodable trait pub trait Decodable: Sized { - /// TODO [debris] Please document me + /// Decode a value from RLP bytes + fn decode(decoder: &D) -> Result where D: Decoder; +} + +/// Internal helper trait. Implement `Decodable` for custom types. +pub trait RlpDecodable: Sized { + /// Decode a value from RLP bytes fn decode(decoder: &D) -> Result where D: Decoder; } @@ -201,10 +206,10 @@ pub trait View<'a, 'view>: Sized { fn iter(&'view self) -> Self::Iter; /// TODO [debris] Please document me - fn as_val(&self) -> Result where T: Decodable; + fn as_val(&self) -> Result where T: RlpDecodable; /// TODO [debris] Please document me - fn val_at(&self, index: usize) -> Result where T: Decodable; + fn val_at(&self, index: usize) -> Result where T: RlpDecodable; } /// TODO [debris] Please document me diff --git a/util/src/rlp/tests.rs b/util/src/rlp/tests.rs index 912709b5e..3b00676f8 100644 --- a/util/src/rlp/tests.rs +++ b/util/src/rlp/tests.rs @@ -13,7 +13,7 @@ fn rlp_at() { { let rlp = UntrustedRlp::new(&data); assert!(rlp.is_list()); - //let animals = as rlp::Decodable>::decode_untrusted(&rlp).unwrap(); + //let animals = as rlp::RlpDecodable>::decode_untrusted(&rlp).unwrap(); let animals: Vec = rlp.as_val().unwrap(); assert_eq!(animals, vec!["cat".to_owned(), "dog".to_owned()]); @@ -193,9 +193,9 @@ fn encode_vector_str() { run_encode_tests(tests); } -struct DTestPair(T, Vec) where T: rlp::Decodable + fmt::Debug + cmp::Eq; +struct DTestPair(T, Vec) where T: rlp::RlpDecodable + fmt::Debug + cmp::Eq; -fn run_decode_tests(tests: Vec>) where T: rlp::Decodable + fmt::Debug + cmp::Eq { +fn run_decode_tests(tests: Vec>) where T: rlp::RlpDecodable + fmt::Debug + cmp::Eq { for t in &tests { let res: T = rlp::decode(&t.1); assert_eq!(res, t.0); @@ -214,6 +214,16 @@ fn decode_vector_u8() { run_decode_tests(tests); } +#[test] +fn decode_untrusted_u8() { + let tests = vec![ + DTestPair(0x0u8, vec![0x80]), + DTestPair(0x77u8, vec![0x77]), + DTestPair(0xccu8, vec![0x81, 0xcc]), + ]; + run_decode_tests(tests); +} + #[test] fn decode_untrusted_u16() { let tests = vec![ diff --git a/util/src/rlp/untrusted_rlp.rs b/util/src/rlp/untrusted_rlp.rs index 07a9a4cde..604273b20 100644 --- a/util/src/rlp/untrusted_rlp.rs +++ b/util/src/rlp/untrusted_rlp.rs @@ -1,8 +1,8 @@ use std::cell::Cell; use std::fmt; use rustc_serialize::hex::ToHex; -use bytes::{FromBytes}; -use rlp::{View, Decoder, Decodable, DecoderError}; +use rlp::bytes::{FromBytes, FromBytesResult, FromBytesError}; +use rlp::{View, Decoder, Decodable, DecoderError, RlpDecodable}; /// rlp offset #[derive(Copy, Clone, Debug)] @@ -211,12 +211,12 @@ impl<'a, 'view> View<'a, 'view> for UntrustedRlp<'a> where 'a: 'view { self.into_iter() } - fn as_val(&self) -> Result where T: Decodable { + fn as_val(&self) -> Result where T: RlpDecodable { // optimize, so it doesn't use clone (although This clone is cheap) T::decode(&BasicDecoder::new(self.clone())) } - fn val_at(&self, index: usize) -> Result where T: Decodable { + fn val_at(&self, index: usize) -> Result where T: RlpDecodable { try!(self.at(index)).as_val() } } @@ -369,13 +369,6 @@ impl<'a> Decoder for BasicDecoder<'a> { self.rlp.as_raw() } - fn as_list(&self) -> Result, DecoderError> { - let v: Vec> = self.rlp.iter() - .map(BasicDecoder::new) - .collect(); - Ok(v) - } - fn as_rlp(&self) -> &UntrustedRlp { &self.rlp } @@ -391,8 +384,7 @@ impl Decodable for T where T: FromBytes { impl Decodable for Vec where T: Decodable { fn decode(decoder: &D) -> Result where D: Decoder { - let decoders = try!(decoder.as_list()); - decoders.iter().map(|d| T::decode(d)).collect() + decoder.as_rlp().iter().map(|d| T::decode(&BasicDecoder::new(d))).collect() } } @@ -423,15 +415,15 @@ macro_rules! impl_array_decodable { impl Decodable for [T; $len] where T: Decodable { #[allow(len_zero)] fn decode(decoder: &D) -> Result where D: Decoder { - let decoders = try!(decoder.as_list()); + let decoders = decoder.as_rlp(); let mut result: [T; $len] = unsafe { ::std::mem::uninitialized() }; - if decoders.len() != $len { + if decoders.item_count() != $len { return Err(DecoderError::RlpIncorrectListLen); } - for i in 0..decoders.len() { - result[i] = try!(T::decode(&decoders[i])); + for i in 0..decoders.item_count() { + result[i] = try!(T::decode(&BasicDecoder::new(try!(decoders.at(i))))); } Ok(result) @@ -454,6 +446,36 @@ impl_array_decodable_recursive!( 32, 40, 48, 56, 64, 72, 96, 128, 160, 192, 224, ); +impl RlpDecodable for T where T: Decodable { + fn decode(decoder: &D) -> Result where D: Decoder { + Decodable::decode(decoder) + } +} + +struct DecodableU8 (u8); + +impl FromBytes for DecodableU8 { + fn from_bytes(bytes: &[u8]) -> FromBytesResult { + match bytes.len() { + 0 => Ok(DecodableU8(0u8)), + 1 => { + if bytes[0] == 0 { + return Err(FromBytesError::ZeroPrefixedInt) + } + Ok(DecodableU8(bytes[0])) + } + _ => Err(FromBytesError::DataIsTooLong) + } + } +} + +impl RlpDecodable for u8 { + fn decode(decoder: &D) -> Result where D: Decoder { + let u: DecodableU8 = try!(Decodable::decode(decoder)); + Ok(u.0) + } +} + #[test] fn test_rlp_display() { use rustc_serialize::hex::FromHex;