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() {
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)),
})
}
}

View File

@ -133,12 +133,12 @@ impl HeapSizeOf for BlockDetails {
impl Decodable for BlockDetails {
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 {
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<D>(decoder: &D) -> Result<Self, DecoderError> 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)

View File

@ -267,20 +267,20 @@ impl Decodable for Action {
impl Decodable for Transaction {
fn decode<D>(decoder: &D) -> Result<Self, DecoderError> 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),
})

View File

@ -11,37 +11,14 @@
//! 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() {
//! 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<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.
pub trait Populatable {
/// Copies a bunch of bytes `d` to `self`, overwriting as necessary.

View File

@ -57,11 +57,10 @@ pub struct PeerCapabilityInfo {
impl Decodable for PeerCapabilityInfo {
fn decode<D>(decoder: &D) -> Result<Self, DecoderError> 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))
})
}
}

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 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<T>(bytes: &[u8]) -> T where T: Decodable {
pub fn decode<T>(bytes: &[u8]) -> T where T: RlpDecodable {
let rlp = Rlp::new(bytes);
rlp.as_val()
}

View File

@ -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

View File

@ -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<UntrustedRlp<'a>> 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<T>(&self) -> Result<T, DecoderError> where T: Decodable {
fn as_val<T>(&self) -> Result<T, DecoderError> where T: RlpDecodable {
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()
}
}
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();
res.unwrap_or_else(|_| panic!())
}
/// 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)
}
/// 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))
}
}

View File

@ -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};

View File

@ -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<T, F>(&self, f: F) -> 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
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<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;
}
@ -201,10 +206,10 @@ pub trait View<'a, 'view>: Sized {
fn iter(&'view self) -> Self::Iter;
/// 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
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

View File

@ -13,7 +13,7 @@ fn rlp_at() {
{
let rlp = UntrustedRlp::new(&data);
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();
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>(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 {
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![

View File

@ -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<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)
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()
}
}
@ -369,13 +369,6 @@ impl<'a> Decoder for BasicDecoder<'a> {
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 {
&self.rlp
}
@ -391,8 +384,7 @@ impl<T> Decodable for T where T: FromBytes {
impl<T> Decodable for Vec<T> where T: Decodable {
fn decode<D>(decoder: &D) -> Result<Self, DecoderError> 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<T> Decodable for [T; $len] where T: Decodable {
#[allow(len_zero)]
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() };
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<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]
fn test_rlp_display() {
use rustc_serialize::hex::FromHex;