RLP decoder refactoring

This commit is contained in:
arkpar 2016-01-29 13:59:29 +01:00
parent cfa2776e75
commit 772de24cae
13 changed files with 362 additions and 305 deletions

View File

@ -45,14 +45,14 @@ impl Decodable for Block {
if decoder.as_raw().len() != try!(decoder.as_rlp().payload_info()).total() { if decoder.as_raw().len() != try!(decoder.as_rlp().payload_info()).total() {
return Err(DecoderError::RlpIsTooBig); return Err(DecoderError::RlpIsTooBig);
} }
let d = try!(decoder.as_list()); let d = decoder.as_rlp();
if d.len() != 3 { if d.item_count() != 3 {
return Err(DecoderError::RlpIncorrectListLen); return Err(DecoderError::RlpIncorrectListLen);
} }
Ok(Block { Ok(Block {
header: try!(Decodable::decode(&d[0])), header: try!(d.val_at(0)),
transactions: try!(Decodable::decode(&d[1])), transactions: try!(d.val_at(1)),
uncles: try!(Decodable::decode(&d[2])), uncles: try!(d.val_at(2)),
}) })
} }
} }

View File

@ -133,12 +133,12 @@ impl HeapSizeOf for BlockDetails {
impl Decodable for BlockDetails { impl Decodable for BlockDetails {
fn decode<D>(decoder: &D) -> Result<Self, DecoderError> where D: Decoder { fn decode<D>(decoder: &D) -> Result<Self, DecoderError> where D: Decoder {
let d = try!(decoder.as_list()); let d = decoder.as_rlp();
let details = BlockDetails { let details = BlockDetails {
number: try!(Decodable::decode(&d[0])), number: try!(d.val_at(0)),
total_difficulty: try!(Decodable::decode(&d[1])), total_difficulty: try!(d.val_at(1)),
parent: try!(Decodable::decode(&d[2])), parent: try!(d.val_at(2)),
children: try!(Decodable::decode(&d[3])) children: try!(d.val_at(3)),
}; };
Ok(details) Ok(details)
} }
@ -257,10 +257,10 @@ impl HeapSizeOf for TransactionAddress {
impl Decodable for TransactionAddress { impl Decodable for TransactionAddress {
fn decode<D>(decoder: &D) -> Result<Self, DecoderError> where D: Decoder { fn decode<D>(decoder: &D) -> Result<Self, DecoderError> where D: Decoder {
let d = try!(decoder.as_list()); let d = decoder.as_rlp();
let tx_address = TransactionAddress { let tx_address = TransactionAddress {
block_hash: try!(Decodable::decode(&d[0])), block_hash: try!(d.val_at(0)),
index: try!(Decodable::decode(&d[1])) index: try!(d.val_at(1)),
}; };
Ok(tx_address) Ok(tx_address)

View File

@ -267,20 +267,20 @@ impl Decodable for Action {
impl Decodable for Transaction { impl Decodable for Transaction {
fn decode<D>(decoder: &D) -> Result<Self, DecoderError> where D: Decoder { fn decode<D>(decoder: &D) -> Result<Self, DecoderError> where D: Decoder {
let d = try!(decoder.as_list()); let d = decoder.as_rlp();
if d.len() != 9 { if d.item_count() != 9 {
return Err(DecoderError::RlpIncorrectListLen); return Err(DecoderError::RlpIncorrectListLen);
} }
Ok(Transaction { Ok(Transaction {
nonce: try!(Decodable::decode(&d[0])), nonce: try!(d.val_at(0)),
gas_price: try!(Decodable::decode(&d[1])), gas_price: try!(d.val_at(1)),
gas: try!(Decodable::decode(&d[2])), gas: try!(d.val_at(2)),
action: try!(Decodable::decode(&d[3])), action: try!(d.val_at(3)),
value: try!(Decodable::decode(&d[4])), value: try!(d.val_at(4)),
data: try!(Decodable::decode(&d[5])), data: try!(d.val_at(5)),
v: try!(u16::decode(&d[6])) as u8, v: try!(d.val_at(6)),
r: try!(Decodable::decode(&d[7])), r: try!(d.val_at(7)),
s: try!(Decodable::decode(&d[8])), s: try!(d.val_at(8)),
hash: RefCell::new(None), hash: RefCell::new(None),
sender: RefCell::new(None), sender: RefCell::new(None),
}) })

View File

@ -11,37 +11,14 @@
//! let slice: &[u8] = arr.bytes(); //! let slice: &[u8] = arr.bytes();
//! } //! }
//! //!
//! fn to_bytes() {
//! use util::bytes::ToBytes;
//!
//! let mut out: Vec<u8> = 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() { //! fn main() {
//! bytes_convertable(); //! bytes_convertable();
//! to_bytes();
//! from_bytes();
//! } //! }
//! ``` //! ```
use std::mem;
use std::fmt; use std::fmt;
use std::slice; use std::slice;
use std::cmp::Ordering;
use std::error::Error as StdError;
use std::ops::{Deref, DerefMut}; use std::ops::{Deref, DerefMut};
use uint::{Uint, U128, U256};
use hash::FixedHash; use hash::FixedHash;
use elastic_array::*; use elastic_array::*;
@ -205,213 +182,6 @@ fn bytes_convertable() {
assert_eq!([0u8; 0].bytes(), &[]); 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<V: VecLike<u8>>(&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<V: VecLike<u8>>(&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<V: VecLike<u8>>(&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<V: VecLike<u8>>(&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<V: VecLike<u8>>(&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<V: VecLike<u8>>(&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<V: VecLike<u8>>(&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 <T>ToBytes for T where T: FixedHash {
fn to_bytes<V: VecLike<u8>>(&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<T> = Result<T, FromBytesError>;
/// 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<Self>;
}
impl FromBytes for String {
fn from_bytes(bytes: &[u8]) -> FromBytesResult<String> {
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<bool> {
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 <T>FromBytes for T where T: FixedHash {
fn from_bytes(bytes: &[u8]) -> FromBytesResult<T> {
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. /// Simple trait to allow for raw population of a Sized object from a byte slice.
pub trait Populatable { pub trait Populatable {
/// Copies a bunch of bytes `d` to `self`, overwriting as necessary. /// Copies a bunch of bytes `d` to `self`, overwriting as necessary.

View File

@ -57,11 +57,10 @@ pub struct PeerCapabilityInfo {
impl Decodable for PeerCapabilityInfo { impl Decodable for PeerCapabilityInfo {
fn decode<D>(decoder: &D) -> Result<Self, DecoderError> where D: Decoder { fn decode<D>(decoder: &D) -> Result<Self, DecoderError> where D: Decoder {
let c = try!(decoder.as_list()); let c = decoder.as_rlp();
let v: u32 = try!(Decodable::decode(&c[1]));
Ok(PeerCapabilityInfo { Ok(PeerCapabilityInfo {
protocol: try!(Decodable::decode(&c[0])), protocol: try!(c.val_at(0)),
version: v as u8, version: try!(c.val_at(1))
}) })
} }
} }

255
util/src/rlp/bytes.rs Normal file
View File

@ -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<T> {
/// 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<T> VecLike<T> for Vec<T> where T: Copy {
fn vec_push(&mut self, value: T) {
Vec::<T>::push(self, value)
}
fn vec_extend(&mut self, slice: &[T]) {
Vec::<T>::extend_from_slice(self, slice)
}
}
macro_rules! impl_veclike_for_elastic_array {
($from: ident) => {
impl<T> VecLike<T> for $from<T> where T: Copy {
fn vec_push(&mut self, value: T) {
$from::<T>::push(self, value)
}
fn vec_extend(&mut self, slice: &[T]) {
$from::<T>::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<V: VecLike<u8>>(&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<V: VecLike<u8>>(&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<V: VecLike<u8>>(&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<V: VecLike<u8>>(&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<V: VecLike<u8>>(&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<V: VecLike<u8>>(&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<V: VecLike<u8>>(&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 <T>ToBytes for T where T: FixedHash {
fn to_bytes<V: VecLike<u8>>(&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<T> = Result<T, FromBytesError>;
/// 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<Self>;
}
impl FromBytes for String {
fn from_bytes(bytes: &[u8]) -> FromBytesResult<String> {
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<bool> {
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 <T>FromBytes for T where T: FixedHash {
fn from_bytes(bytes: &[u8]) -> FromBytesResult<T> {
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)
}
}
}

View File

@ -30,22 +30,18 @@
//! * You want to get view onto rlp-slice. //! * You want to get view onto rlp-slice.
//! * You don't want to decode whole rlp at once. //! * You don't want to decode whole rlp at once.
/// TODO [Gav Wood] Please document me
pub mod rlptraits; pub mod rlptraits;
/// TODO [Gav Wood] Please document me mod rlperrors;
pub mod rlperrors; mod rlpin;
/// TODO [debris] Please document me mod untrusted_rlp;
pub mod rlpin; mod rlpstream;
/// TODO [debris] Please document me mod bytes;
pub mod untrusted_rlp;
/// TODO [debris] Please document me
pub mod rlpstream;
#[cfg(test)] #[cfg(test)]
mod tests; mod tests;
pub use self::rlperrors::DecoderError; 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::untrusted_rlp::{UntrustedRlp, UntrustedRlpIterator, PayloadInfo, Prototype};
pub use self::rlpin::{Rlp, RlpIterator}; pub use self::rlpin::{Rlp, RlpIterator};
pub use self::rlpstream::{RlpStream}; 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()]); /// assert_eq!(animals, vec!["cat".to_string(), "dog".to_string()]);
/// } /// }
/// ``` /// ```
pub fn decode<T>(bytes: &[u8]) -> T where T: Decodable { pub fn decode<T>(bytes: &[u8]) -> T where T: RlpDecodable {
let rlp = Rlp::new(bytes); let rlp = Rlp::new(bytes);
rlp.as_val() rlp.as_val()
} }

View File

@ -1,6 +1,6 @@
use std::fmt; use std::fmt;
use std::error::Error as StdError; use std::error::Error as StdError;
use bytes::FromBytesError; use rlp::bytes::FromBytesError;
#[derive(Debug, PartialEq, Eq)] #[derive(Debug, PartialEq, Eq)]
/// TODO [debris] Please document me /// TODO [debris] Please document me

View File

@ -1,5 +1,5 @@
use std::fmt; use std::fmt;
use rlp::{View, Decodable, DecoderError, UntrustedRlp, PayloadInfo, Prototype}; use rlp::{View, DecoderError, UntrustedRlp, PayloadInfo, Prototype, RlpDecodable};
impl<'a> From<UntrustedRlp<'a>> for Rlp<'a> { impl<'a> From<UntrustedRlp<'a>> for Rlp<'a> {
fn from(rlp: UntrustedRlp<'a>) -> 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() self.into_iter()
} }
fn as_val<T>(&self) -> Result<T, DecoderError> where T: Decodable { fn as_val<T>(&self) -> Result<T, DecoderError> where T: RlpDecodable {
self.rlp.as_val() self.rlp.as_val()
} }
fn val_at<T>(&self, index: usize) -> Result<T, DecoderError> where T: Decodable { fn val_at<T>(&self, index: usize) -> Result<T, DecoderError> where T: RlpDecodable {
self.at(index).rlp.as_val() self.at(index).rlp.as_val()
} }
} }
impl <'a, 'view> Rlp<'a> where 'a: 'view { impl <'a, 'view> Rlp<'a> where 'a: 'view {
fn view_as_val<T, R>(r: &R) -> T where R: View<'a, 'view>, T: Decodable { fn view_as_val<T, R>(r: &R) -> T where R: View<'a, 'view>, T: RlpDecodable {
let res: Result<T, DecoderError> = r.as_val(); let res: Result<T, DecoderError> = r.as_val();
res.unwrap_or_else(|_| panic!()) res.unwrap_or_else(|_| panic!())
} }
/// TODO [debris] Please document me /// TODO [debris] Please document me
pub fn as_val<T>(&self) -> T where T: Decodable { pub fn as_val<T>(&self) -> T where T: RlpDecodable {
Self::view_as_val(self) Self::view_as_val(self)
} }
/// TODO [debris] Please document me /// TODO [debris] Please document me
pub fn val_at<T>(&self, index: usize) -> T where T: Decodable { pub fn val_at<T>(&self, index: usize) -> T where T: RlpDecodable {
Self::view_as_val(&self.at(index)) Self::view_as_val(&self.at(index))
} }
} }

View File

@ -1,6 +1,6 @@
use std::ops::Deref; use std::ops::Deref;
use elastic_array::*; use elastic_array::*;
use bytes::{ToBytes, VecLike}; use rlp::bytes::{ToBytes, VecLike};
use rlp::{Stream, Encoder, Encodable}; use rlp::{Stream, Encoder, Encodable};
use rlp::rlptraits::{ByteEncodable, RlpEncodable}; use rlp::rlptraits::{ByteEncodable, RlpEncodable};

View File

@ -1,7 +1,8 @@
//! Common RLP traits
use std::ops::Deref; use std::ops::Deref;
use bytes::VecLike; use rlp::bytes::VecLike;
use rlp::{DecoderError, UntrustedRlp}; use rlp::{DecoderError, UntrustedRlp};
use rlpstream::RlpStream; use rlp::rlpstream::RlpStream;
use elastic_array::ElasticArray1024; use elastic_array::ElasticArray1024;
use hash::H256; use hash::H256;
use sha3::*; use sha3::*;
@ -12,17 +13,21 @@ pub trait Decoder: Sized {
fn read_value<T, F>(&self, f: F) -> Result<T, DecoderError> fn read_value<T, F>(&self, f: F) -> Result<T, DecoderError>
where F: FnOnce(&[u8]) -> Result<T, DecoderError>; where F: FnOnce(&[u8]) -> Result<T, DecoderError>;
/// TODO [arkpar] Please document me
fn as_list(&self) -> Result<Vec<Self>, DecoderError>;
/// TODO [Gav Wood] Please document me /// TODO [Gav Wood] Please document me
fn as_rlp(&self) -> &UntrustedRlp; fn as_rlp(&self) -> &UntrustedRlp;
/// TODO [debris] Please document me /// TODO [debris] Please document me
fn as_raw(&self) -> &[u8]; fn as_raw(&self) -> &[u8];
} }
/// TODO [debris] Please document me /// RLP decodable trait
pub trait Decodable: Sized { pub trait Decodable: Sized {
/// TODO [debris] Please document me /// Decode a value from RLP bytes
fn decode<D>(decoder: &D) -> Result<Self, DecoderError> where D: Decoder;
}
/// Internal helper trait. Implement `Decodable` for custom types.
pub trait RlpDecodable: Sized {
/// Decode a value from RLP bytes
fn decode<D>(decoder: &D) -> Result<Self, DecoderError> where D: Decoder; fn decode<D>(decoder: &D) -> Result<Self, DecoderError> where D: Decoder;
} }
@ -201,10 +206,10 @@ pub trait View<'a, 'view>: Sized {
fn iter(&'view self) -> Self::Iter; fn iter(&'view self) -> Self::Iter;
/// TODO [debris] Please document me /// TODO [debris] Please document me
fn as_val<T>(&self) -> Result<T, DecoderError> where T: Decodable; fn as_val<T>(&self) -> Result<T, DecoderError> where T: RlpDecodable;
/// TODO [debris] Please document me /// TODO [debris] Please document me
fn val_at<T>(&self, index: usize) -> Result<T, DecoderError> where T: Decodable; fn val_at<T>(&self, index: usize) -> Result<T, DecoderError> where T: RlpDecodable;
} }
/// TODO [debris] Please document me /// TODO [debris] Please document me

View File

@ -13,7 +13,7 @@ fn rlp_at() {
{ {
let rlp = UntrustedRlp::new(&data); let rlp = UntrustedRlp::new(&data);
assert!(rlp.is_list()); assert!(rlp.is_list());
//let animals = <Vec<String> as rlp::Decodable>::decode_untrusted(&rlp).unwrap(); //let animals = <Vec<String> as rlp::RlpDecodable>::decode_untrusted(&rlp).unwrap();
let animals: Vec<String> = rlp.as_val().unwrap(); let animals: Vec<String> = rlp.as_val().unwrap();
assert_eq!(animals, vec!["cat".to_owned(), "dog".to_owned()]); assert_eq!(animals, vec!["cat".to_owned(), "dog".to_owned()]);
@ -193,9 +193,9 @@ fn encode_vector_str() {
run_encode_tests(tests); run_encode_tests(tests);
} }
struct DTestPair<T>(T, Vec<u8>) where T: rlp::Decodable + fmt::Debug + cmp::Eq; struct DTestPair<T>(T, Vec<u8>) where T: rlp::RlpDecodable + fmt::Debug + cmp::Eq;
fn run_decode_tests<T>(tests: Vec<DTestPair<T>>) where T: rlp::Decodable + fmt::Debug + cmp::Eq { fn run_decode_tests<T>(tests: Vec<DTestPair<T>>) where T: rlp::RlpDecodable + fmt::Debug + cmp::Eq {
for t in &tests { for t in &tests {
let res: T = rlp::decode(&t.1); let res: T = rlp::decode(&t.1);
assert_eq!(res, t.0); assert_eq!(res, t.0);
@ -214,6 +214,16 @@ fn decode_vector_u8() {
run_decode_tests(tests); 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] #[test]
fn decode_untrusted_u16() { fn decode_untrusted_u16() {
let tests = vec![ let tests = vec![

View File

@ -1,8 +1,8 @@
use std::cell::Cell; use std::cell::Cell;
use std::fmt; use std::fmt;
use rustc_serialize::hex::ToHex; use rustc_serialize::hex::ToHex;
use bytes::{FromBytes}; use rlp::bytes::{FromBytes, FromBytesResult, FromBytesError};
use rlp::{View, Decoder, Decodable, DecoderError}; use rlp::{View, Decoder, Decodable, DecoderError, RlpDecodable};
/// rlp offset /// rlp offset
#[derive(Copy, Clone, Debug)] #[derive(Copy, Clone, Debug)]
@ -211,12 +211,12 @@ impl<'a, 'view> View<'a, 'view> for UntrustedRlp<'a> where 'a: 'view {
self.into_iter() self.into_iter()
} }
fn as_val<T>(&self) -> Result<T, DecoderError> where T: Decodable { fn as_val<T>(&self) -> Result<T, DecoderError> where T: RlpDecodable {
// optimize, so it doesn't use clone (although This clone is cheap) // optimize, so it doesn't use clone (although This clone is cheap)
T::decode(&BasicDecoder::new(self.clone())) T::decode(&BasicDecoder::new(self.clone()))
} }
fn val_at<T>(&self, index: usize) -> Result<T, DecoderError> where T: Decodable { fn val_at<T>(&self, index: usize) -> Result<T, DecoderError> where T: RlpDecodable {
try!(self.at(index)).as_val() try!(self.at(index)).as_val()
} }
} }
@ -369,13 +369,6 @@ impl<'a> Decoder for BasicDecoder<'a> {
self.rlp.as_raw() self.rlp.as_raw()
} }
fn as_list(&self) -> Result<Vec<Self>, DecoderError> {
let v: Vec<BasicDecoder<'a>> = self.rlp.iter()
.map(BasicDecoder::new)
.collect();
Ok(v)
}
fn as_rlp(&self) -> &UntrustedRlp { fn as_rlp(&self) -> &UntrustedRlp {
&self.rlp &self.rlp
} }
@ -391,8 +384,7 @@ impl<T> Decodable for T where T: FromBytes {
impl<T> Decodable for Vec<T> where T: Decodable { impl<T> Decodable for Vec<T> where T: Decodable {
fn decode<D>(decoder: &D) -> Result<Self, DecoderError> where D: Decoder { fn decode<D>(decoder: &D) -> Result<Self, DecoderError> where D: Decoder {
let decoders = try!(decoder.as_list()); decoder.as_rlp().iter().map(|d| T::decode(&BasicDecoder::new(d))).collect()
decoders.iter().map(|d| T::decode(d)).collect()
} }
} }
@ -423,15 +415,15 @@ macro_rules! impl_array_decodable {
impl<T> Decodable for [T; $len] where T: Decodable { impl<T> Decodable for [T; $len] where T: Decodable {
#[allow(len_zero)] #[allow(len_zero)]
fn decode<D>(decoder: &D) -> Result<Self, DecoderError> where D: Decoder { fn decode<D>(decoder: &D) -> Result<Self, DecoderError> where D: Decoder {
let decoders = try!(decoder.as_list()); let decoders = decoder.as_rlp();
let mut result: [T; $len] = unsafe { ::std::mem::uninitialized() }; let mut result: [T; $len] = unsafe { ::std::mem::uninitialized() };
if decoders.len() != $len { if decoders.item_count() != $len {
return Err(DecoderError::RlpIncorrectListLen); return Err(DecoderError::RlpIncorrectListLen);
} }
for i in 0..decoders.len() { for i in 0..decoders.item_count() {
result[i] = try!(T::decode(&decoders[i])); result[i] = try!(T::decode(&BasicDecoder::new(try!(decoders.at(i)))));
} }
Ok(result) Ok(result)
@ -454,6 +446,36 @@ impl_array_decodable_recursive!(
32, 40, 48, 56, 64, 72, 96, 128, 160, 192, 224, 32, 40, 48, 56, 64, 72, 96, 128, 160, 192, 224,
); );
impl<T> RlpDecodable for T where T: Decodable {
fn decode<D>(decoder: &D) -> Result<Self, DecoderError> where D: Decoder {
Decodable::decode(decoder)
}
}
struct DecodableU8 (u8);
impl FromBytes for DecodableU8 {
fn from_bytes(bytes: &[u8]) -> FromBytesResult<DecodableU8> {
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<D>(decoder: &D) -> Result<Self, DecoderError> where D: Decoder {
let u: DecodableU8 = try!(Decodable::decode(decoder));
Ok(u.0)
}
}
#[test] #[test]
fn test_rlp_display() { fn test_rlp_display() {
use rustc_serialize::hex::FromHex; use rustc_serialize::hex::FromHex;