diff --git a/benches/rlp.rs b/benches/rlp.rs
new file mode 100644
index 0000000..3f8166e
--- /dev/null
+++ b/benches/rlp.rs
@@ -0,0 +1,111 @@
+// Copyright 2015-2017 Parity Technologies (UK) Ltd.
+// This file is part of Parity.
+
+// Parity is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Parity is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Parity. If not, see .
+
+//! benchmarking for rlp
+//! should be started with:
+//! ```bash
+//! multirust run nightly cargo bench
+//! ```
+
+#![feature(test)]
+
+extern crate test;
+extern crate ethcore_bigint as bigint;
+extern crate rlp;
+
+use test::Bencher;
+use bigint::prelude::U256;
+use rlp::{RlpStream, Rlp};
+
+#[bench]
+fn bench_stream_u64_value(b: &mut Bencher) {
+ b.iter(|| {
+ // u64
+ let mut stream = RlpStream::new();
+ stream.append(&0x1023456789abcdefu64);
+ let _ = stream.out();
+ });
+}
+
+#[bench]
+fn bench_decode_u64_value(b: &mut Bencher) {
+ b.iter(|| {
+ // u64
+ let data = vec![0x88, 0x10, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef];
+ let rlp = Rlp::new(&data);
+ let _: u64 = rlp.as_val();
+ });
+}
+
+#[bench]
+fn bench_stream_u256_value(b: &mut Bencher) {
+ b.iter(|| {
+ // u256
+ let mut stream = RlpStream::new();
+ let uint: U256 = "8090a0b0c0d0e0f00910203040506077000000000000000100000000000012f0".into();
+ stream.append(&uint);
+ let _ = stream.out();
+ });
+}
+
+#[bench]
+fn bench_decode_u256_value(b: &mut Bencher) {
+ b.iter(|| {
+ // u256
+ let data = 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];
+ let rlp = Rlp::new(&data);
+ let _ : U256 = rlp.as_val();
+ });
+}
+
+#[bench]
+fn bench_stream_nested_empty_lists(b: &mut Bencher) {
+ b.iter(|| {
+ // [ [], [[]], [ [], [[]] ] ]
+ let mut stream = RlpStream::new_list(3);
+ stream.begin_list(0);
+ stream.begin_list(1).begin_list(0);
+ stream.begin_list(2).begin_list(0).begin_list(1).begin_list(0);
+ let _ = stream.out();
+ });
+}
+
+#[bench]
+fn bench_decode_nested_empty_lists(b: &mut Bencher) {
+ b.iter(|| {
+ // [ [], [[]], [ [], [[]] ] ]
+ let data = vec![0xc7, 0xc0, 0xc1, 0xc0, 0xc3, 0xc0, 0xc1, 0xc0];
+ let rlp = Rlp::new(&data);
+ let _v0: Vec = rlp.at(0).as_list();
+ let _v1: Vec = rlp.at(1).at(0).as_list();
+ let nested_rlp = rlp.at(2);
+ let _v2a: Vec = nested_rlp.at(0).as_list();
+ let _v2b: Vec = nested_rlp.at(1).at(0).as_list();
+ });
+}
+
+#[bench]
+fn bench_stream_1000_empty_lists(b: &mut Bencher) {
+ b.iter(|| {
+ let mut stream = RlpStream::new_list(1000);
+ for _ in 0..1000 {
+ stream.begin_list(0);
+ }
+ let _ = stream.out();
+ });
+}
diff --git a/src/bytes.rs b/src/bytes.rs
deleted file mode 100644
index e5f266f..0000000
--- a/src/bytes.rs
+++ /dev/null
@@ -1,148 +0,0 @@
-// Copyright 2015-2017 Parity Technologies (UK) Ltd.
-// This file is part of Parity.
-
-// Parity is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-
-// Parity is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-
-// You should have received a copy of the GNU General Public License
-// along with Parity. If not, see .
-
-//! Unified interfaces for RLP bytes operations on basic types
-//!
-
-use std::{mem, fmt, cmp};
-use std::error::Error as StdError;
-use bigint::prelude::{U128, U256, H64, H128, H160, H256, H512, H520, H2048};
-
-/// Error returned when `FromBytes` conversation goes wrong
-#[derive(Debug, PartialEq, Eq)]
-pub enum FromBytesError {
- /// Expected more RLP data
- DataIsTooShort,
- /// Extra bytes after the end of the last item
- DataIsTooLong,
- /// Integer-representation is non-canonically prefixed with zero byte(s).
- ZeroPrefixedInt,
- /// String representation is not utf-8
- InvalidUtf8,
-}
-
-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 {
- /// Create a value from bytes
- fn from_bytes(bytes: &[u8]) -> FromBytesResult;
-}
-
-impl FromBytes for String {
- fn from_bytes(bytes: &[u8]) -> FromBytesResult {
- ::std::str::from_utf8(bytes).map(|s| s.to_owned()).map_err(|_| FromBytesError::InvalidUtf8)
- }
-}
-
-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, $size: expr) => {
- 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() <= $size {
- Ok($name::from(bytes))
- } else {
- Err(FromBytesError::DataIsTooLong)
- }
- }
- }
- }
-}
-
-impl_uint_from_bytes!(U256, 32);
-impl_uint_from_bytes!(U128, 16);
-
-macro_rules! impl_hash_from_bytes {
- ($name: ident, $size: expr) => {
- impl FromBytes for $name {
- fn from_bytes(bytes: &[u8]) -> FromBytesResult<$name> {
- match bytes.len().cmp(&$size) {
- cmp::Ordering::Less => Err(FromBytesError::DataIsTooShort),
- cmp::Ordering::Greater => Err(FromBytesError::DataIsTooLong),
- cmp::Ordering::Equal => {
- let mut t = [0u8; $size];
- t.copy_from_slice(bytes);
- Ok($name(t))
- }
- }
- }
- }
- }
-}
-
-impl_hash_from_bytes!(H64, 8);
-impl_hash_from_bytes!(H128, 16);
-impl_hash_from_bytes!(H160, 20);
-impl_hash_from_bytes!(H256, 32);
-impl_hash_from_bytes!(H512, 64);
-impl_hash_from_bytes!(H520, 65);
-impl_hash_from_bytes!(H2048, 256);
-
diff --git a/src/compression.rs b/src/compression.rs
index b7cf72a..7a9c5a9 100644
--- a/src/compression.rs
+++ b/src/compression.rs
@@ -17,7 +17,7 @@
use std::collections::HashMap;
use elastic_array::ElasticArray1024;
use common::{BLOCKS_RLP_SWAPPER, SNAPSHOT_RLP_SWAPPER};
-use {UntrustedRlp, View, Compressible, encode, RlpStream};
+use {UntrustedRlp, Compressible, encode, RlpStream};
/// Stores RLPs used for compression
pub struct InvalidRlpSwapper<'a> {
@@ -69,7 +69,7 @@ fn to_elastic(slice: &[u8]) -> ElasticArray1024 {
fn map_rlp(rlp: &UntrustedRlp, f: F) -> Option> where
F: Fn(&UntrustedRlp) -> Option> {
match rlp.iter()
- .fold((false, RlpStream::new_list(rlp.item_count())),
+ .fold((false, RlpStream::new_list(rlp.item_count().unwrap_or(0))),
|(is_some, mut acc), subrlp| {
let new = f(&subrlp);
if let Some(ref insert) = new {
@@ -138,7 +138,7 @@ fn deep_decompress(rlp: &UntrustedRlp, swapper: &InvalidRlpSwapper) -> Option
rlp.at(1).ok().map_or(simple_swap(),
@@ -169,7 +169,7 @@ impl<'a> Compressible for UntrustedRlp<'a> {
#[cfg(test)]
mod tests {
use compression::InvalidRlpSwapper;
- use {UntrustedRlp, Compressible, View, RlpType};
+ use {UntrustedRlp, Compressible, RlpType};
#[test]
fn invalid_rlp_swapper() {
diff --git a/src/error.rs b/src/error.rs
index f3b43f8..4ad754d 100644
--- a/src/error.rs
+++ b/src/error.rs
@@ -16,13 +16,10 @@
use std::fmt;
use std::error::Error as StdError;
-use bytes::FromBytesError;
#[derive(Debug, PartialEq, Eq)]
/// Error concerning the RLP decoder.
pub enum DecoderError {
- /// Couldn't convert given bytes to an instance of required type.
- FromBytesError(FromBytesError),
/// Data has additional bytes at the end of the valid RLP fragment.
RlpIsTooBig,
/// Data has too few bytes for valid RLP.
@@ -56,9 +53,3 @@ impl fmt::Display for DecoderError {
fmt::Debug::fmt(&self, f)
}
}
-
-impl From for DecoderError {
- fn from(err: FromBytesError) -> DecoderError {
- DecoderError::FromBytesError(err)
- }
-}
diff --git a/src/impls.rs b/src/impls.rs
index affac1d..909f3bd 100644
--- a/src/impls.rs
+++ b/src/impls.rs
@@ -1,7 +1,26 @@
+use std::{cmp, mem, str};
use byteorder::{ByteOrder, BigEndian};
use bigint::prelude::{Uint, U128, U256, H64, H128, H160, H256, H512, H520, H2048};
-use traits::Encodable;
+use traits::{Encodable, Decodable};
use stream::RlpStream;
+use {UntrustedRlp, DecoderError};
+
+pub fn decode_usize(bytes: &[u8]) -> Result {
+ match bytes.len() {
+ l if l <= mem::size_of::() => {
+ if bytes[0] == 0 {
+ return Err(DecoderError::RlpInvalidIndirection);
+ }
+ let mut res = 0usize;
+ for i in 0..l {
+ let shift = (l - 1 - i) * 8;
+ res = res + ((bytes[i] as usize) << shift);
+ }
+ Ok(res)
+ }
+ _ => Err(DecoderError::RlpIsTooBig),
+ }
+}
impl Encodable for bool {
fn rlp_append(&self, s: &mut RlpStream) {
@@ -13,6 +32,18 @@ impl Encodable for bool {
}
}
+impl Decodable for bool {
+ fn decode(rlp: &UntrustedRlp) -> Result {
+ rlp.decoder().decode_value(|bytes| {
+ match bytes.len() {
+ 0 => Ok(false),
+ 1 => Ok(bytes[0] != 0),
+ _ => Err(DecoderError::RlpIsTooBig),
+ }
+ })
+ }
+}
+
impl<'a> Encodable for &'a [u8] {
fn rlp_append(&self, s: &mut RlpStream) {
s.encoder().encode_value(self);
@@ -25,6 +56,14 @@ impl Encodable for Vec {
}
}
+impl Decodable for Vec {
+ fn decode(rlp: &UntrustedRlp) -> Result {
+ rlp.decoder().decode_value(|bytes| {
+ Ok(bytes.to_vec())
+ })
+ }
+}
+
impl Encodable for Option where T: Encodable {
fn rlp_append(&self, s: &mut RlpStream) {
match *self {
@@ -39,6 +78,17 @@ impl Encodable for Option where T: Encodable {
}
}
+impl Decodable for Option where T: Decodable {
+ fn decode(rlp: &UntrustedRlp) -> Result {
+ let items = rlp.item_count()?;
+ match items {
+ 1 => rlp.val_at(0).map(Some),
+ 0 => Ok(None),
+ _ => Err(DecoderError::RlpIncorrectListLen),
+ }
+ }
+}
+
impl Encodable for u8 {
fn rlp_append(&self, s: &mut RlpStream) {
if *self != 0 {
@@ -49,6 +99,19 @@ impl Encodable for u8 {
}
}
+impl Decodable for u8 {
+ fn decode(rlp: &UntrustedRlp) -> Result {
+ rlp.decoder().decode_value(|bytes| {
+ match bytes.len() {
+ 1 if bytes[0] != 0 => Ok(bytes[0]),
+ 0 => Ok(0),
+ 1 => Err(DecoderError::RlpInvalidIndirection),
+ _ => Err(DecoderError::RlpIsTooBig),
+ }
+ })
+ }
+}
+
macro_rules! impl_encodable_for_u {
($name: ident, $func: ident, $size: expr) => {
impl Encodable for $name {
@@ -62,16 +125,52 @@ macro_rules! impl_encodable_for_u {
}
}
+macro_rules! impl_decodable_for_u {
+ ($name: ident) => {
+ impl Decodable for $name {
+ fn decode(rlp: &UntrustedRlp) -> Result {
+ rlp.decoder().decode_value(|bytes| {
+ match bytes.len() {
+ 0 | 1 => u8::decode(rlp).map(|v| v as $name),
+ l if l <= mem::size_of::<$name>() => {
+ if bytes[0] == 0 {
+ return Err(DecoderError::RlpInvalidIndirection);
+ }
+ let mut res = 0 as $name;
+ for i in 0..l {
+ let shift = (l - 1 - i) * 8;
+ res = res + ((bytes[i] as $name) << shift);
+ }
+ Ok(res)
+ }
+ _ => Err(DecoderError::RlpIsTooBig),
+ }
+ })
+ }
+ }
+ }
+}
+
impl_encodable_for_u!(u16, write_u16, 2);
impl_encodable_for_u!(u32, write_u32, 4);
impl_encodable_for_u!(u64, write_u64, 8);
+impl_decodable_for_u!(u16);
+impl_decodable_for_u!(u32);
+impl_decodable_for_u!(u64);
+
impl Encodable for usize {
fn rlp_append(&self, s: &mut RlpStream) {
(*self as u64).rlp_append(s);
}
}
+impl Decodable for usize {
+ fn decode(rlp: &UntrustedRlp) -> Result {
+ u64::decode(rlp).map(|value| value as usize)
+ }
+}
+
macro_rules! impl_encodable_for_hash {
($name: ident) => {
impl Encodable for $name {
@@ -82,6 +181,24 @@ macro_rules! impl_encodable_for_hash {
}
}
+macro_rules! impl_decodable_for_hash {
+ ($name: ident, $size: expr) => {
+ impl Decodable for $name {
+ fn decode(rlp: &UntrustedRlp) -> Result {
+ rlp.decoder().decode_value(|bytes| match bytes.len().cmp(&$size) {
+ cmp::Ordering::Less => Err(DecoderError::RlpIsTooShort),
+ cmp::Ordering::Greater => Err(DecoderError::RlpIsTooBig),
+ cmp::Ordering::Equal => {
+ let mut t = [0u8; $size];
+ t.copy_from_slice(bytes);
+ Ok($name(t))
+ }
+ })
+ }
+ }
+ }
+}
+
impl_encodable_for_hash!(H64);
impl_encodable_for_hash!(H128);
impl_encodable_for_hash!(H160);
@@ -90,6 +207,14 @@ impl_encodable_for_hash!(H512);
impl_encodable_for_hash!(H520);
impl_encodable_for_hash!(H2048);
+impl_decodable_for_hash!(H64, 8);
+impl_decodable_for_hash!(H128, 16);
+impl_decodable_for_hash!(H160, 20);
+impl_decodable_for_hash!(H256, 32);
+impl_decodable_for_hash!(H512, 64);
+impl_decodable_for_hash!(H520, 65);
+impl_decodable_for_hash!(H2048, 256);
+
macro_rules! impl_encodable_for_uint {
($name: ident, $size: expr) => {
impl Encodable for $name {
@@ -103,9 +228,30 @@ macro_rules! impl_encodable_for_uint {
}
}
+macro_rules! impl_decodable_for_uint {
+ ($name: ident, $size: expr) => {
+ impl Decodable for $name {
+ fn decode(rlp: &UntrustedRlp) -> Result {
+ rlp.decoder().decode_value(|bytes| {
+ if !bytes.is_empty() && bytes[0] == 0 {
+ Err(DecoderError::RlpInvalidIndirection)
+ } else if bytes.len() <= $size {
+ Ok($name::from(bytes))
+ } else {
+ Err(DecoderError::RlpIsTooBig)
+ }
+ })
+ }
+ }
+ }
+}
+
impl_encodable_for_uint!(U256, 32);
impl_encodable_for_uint!(U128, 16);
+impl_decodable_for_uint!(U256, 32);
+impl_decodable_for_uint!(U128, 16);
+
impl<'a> Encodable for &'a str {
fn rlp_append(&self, s: &mut RlpStream) {
s.encoder().encode_value(self.as_bytes());
@@ -118,3 +264,14 @@ impl Encodable for String {
}
}
+impl Decodable for String {
+ fn decode(rlp: &UntrustedRlp) -> Result {
+ rlp.decoder().decode_value(|bytes| {
+ match str::from_utf8(bytes) {
+ Ok(s) => Ok(s.to_owned()),
+ // consider better error type here
+ Err(_err) => Err(DecoderError::RlpExpectedToBeData),
+ }
+ })
+ }
+}
diff --git a/src/lib.rs b/src/lib.rs
index 406501b..4b01691 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -61,17 +61,13 @@ mod untrusted_rlp;
mod stream;
mod compression;
mod common;
-mod bytes;
mod impls;
-#[cfg(test)]
-mod tests;
-
use std::borrow::Borrow;
use elastic_array::ElasticArray1024;
pub use error::DecoderError;
-pub use traits::{Decoder, Decodable, View, Encodable, RlpDecodable, Compressible};
+pub use traits::{Decodable, Encodable, Compressible};
pub use untrusted_rlp::{UntrustedRlp, UntrustedRlpIterator, PayloadInfo, Prototype};
pub use rlpin::{Rlp, RlpIterator};
pub use stream::RlpStream;
@@ -88,16 +84,21 @@ pub const EMPTY_LIST_RLP: [u8; 1] = [0xC0; 1];
/// extern crate rlp;
///
/// fn main () {
-/// let data = vec![0xc8, 0x83, b'c', b'a', b't', 0x83, b'd', b'o', b'g'];
-/// let animals: Vec = rlp::decode(&data);
-/// assert_eq!(animals, vec!["cat".to_string(), "dog".to_string()]);
+/// let data = vec![0x83, b'c', b'a', b't'];
+/// let animal: String = rlp::decode(&data);
+/// assert_eq!(animal, "cat".to_owned());
/// }
/// ```
-pub fn decode(bytes: &[u8]) -> T where T: RlpDecodable {
+pub fn decode(bytes: &[u8]) -> T where T: Decodable {
let rlp = Rlp::new(bytes);
rlp.as_val()
}
+pub fn decode_list(bytes: &[u8]) -> Vec where T: Decodable {
+ let rlp = Rlp::new(bytes);
+ rlp.as_list()
+}
+
/// Shortcut function to encode structure into rlp.
///
/// ```rust
diff --git a/src/rlpin.rs b/src/rlpin.rs
index 7ae7156..c7c054a 100644
--- a/src/rlpin.rs
+++ b/src/rlpin.rs
@@ -15,8 +15,7 @@
// along with Parity. If not, see .
use std::fmt;
-use rustc_serialize::hex::ToHex;
-use {View, DecoderError, UntrustedRlp, PayloadInfo, Prototype, RlpDecodable};
+use {UntrustedRlp, PayloadInfo, Prototype, Decodable};
impl<'a> From> for Rlp<'a> {
fn from(rlp: UntrustedRlp<'a>) -> Rlp<'a> {
@@ -39,95 +38,215 @@ impl<'a> fmt::Display for Rlp<'a> {
}
}
-impl<'a, 'view> View<'a, 'view> for Rlp<'a> where 'a: 'view {
- type Prototype = Prototype;
- type PayloadInfo = PayloadInfo;
- type Data = &'a [u8];
- type Item = Rlp<'a>;
- type Iter = RlpIterator<'a, 'view>;
-
+impl<'a, 'view> Rlp<'a> where 'a: 'view {
/// Create a new instance of `Rlp`
- fn new(bytes: &'a [u8]) -> Rlp<'a> {
+ pub fn new(bytes: &'a [u8]) -> Rlp<'a> {
Rlp {
rlp: UntrustedRlp::new(bytes)
}
}
- fn as_raw(&'view self) -> &'a [u8] {
+ /// The raw data of the RLP as slice.
+ ///
+ /// ```rust
+ /// extern crate rlp;
+ /// use rlp::*;
+ ///
+ /// fn main () {
+ /// let data = vec![0xc8, 0x83, b'c', b'a', b't', 0x83, b'd', b'o', b'g'];
+ /// let rlp = Rlp::new(&data);
+ /// let dog = rlp.at(1).as_raw();
+ /// assert_eq!(dog, &[0x83, b'd', b'o', b'g']);
+ /// }
+ /// ```
+ pub fn as_raw(&'view self) -> &'a [u8] {
self.rlp.as_raw()
}
- fn prototype(&self) -> Self::Prototype {
+ /// Get the prototype of the RLP.
+ pub fn prototype(&self) -> Prototype {
self.rlp.prototype().unwrap()
}
- fn payload_info(&self) -> Self::PayloadInfo {
+ /// Get payload info.
+ pub fn payload_info(&self) -> PayloadInfo {
self.rlp.payload_info().unwrap()
}
- fn data(&'view self) -> Self::Data {
+ /// Get underlieing data.
+ pub fn data(&'view self) -> &'a [u8] {
self.rlp.data().unwrap()
}
- fn item_count(&self) -> usize {
- self.rlp.item_count()
+ /// Returns number of RLP items.
+ ///
+ /// ```rust
+ /// extern crate rlp;
+ /// use rlp::*;
+ ///
+ /// fn main () {
+ /// let data = vec![0xc8, 0x83, b'c', b'a', b't', 0x83, b'd', b'o', b'g'];
+ /// let rlp = Rlp::new(&data);
+ /// assert_eq!(rlp.item_count(), 2);
+ /// let view = rlp.at(1);
+ /// assert_eq!(view.item_count(), 0);
+ /// }
+ /// ```
+ pub fn item_count(&self) -> usize {
+ self.rlp.item_count().unwrap_or(0)
}
- fn size(&self) -> usize {
+ /// Returns the number of bytes in the data, or zero if it isn't data.
+ ///
+ /// ```rust
+ /// extern crate rlp;
+ /// use rlp::*;
+ ///
+ /// fn main () {
+ /// let data = vec![0xc8, 0x83, b'c', b'a', b't', 0x83, b'd', b'o', b'g'];
+ /// let rlp = Rlp::new(&data);
+ /// assert_eq!(rlp.size(), 0);
+ /// let view = rlp.at(1);
+ /// assert_eq!(view.size(), 3);
+ /// }
+ /// ```
+ pub fn size(&self) -> usize {
self.rlp.size()
}
- fn at(&'view self, index: usize) -> Self::Item {
+ /// Get view onto RLP-slice at index.
+ ///
+ /// Caches offset to given index, so access to successive
+ /// slices is faster.
+ ///
+ /// ```rust
+ /// extern crate rlp;
+ /// use rlp::*;
+ ///
+ /// fn main () {
+ /// let data = vec![0xc8, 0x83, b'c', b'a', b't', 0x83, b'd', b'o', b'g'];
+ /// let rlp = Rlp::new(&data);
+ /// let dog: String = rlp.at(1).as_val();
+ /// assert_eq!(dog, "dog".to_string());
+ /// }
+ /// ```
+ pub fn at(&'view self, index: usize) -> Rlp<'a> {
From::from(self.rlp.at(index).unwrap())
}
- fn is_null(&self) -> bool {
+ /// No value
+ ///
+ /// ```rust
+ /// extern crate rlp;
+ /// use rlp::*;
+ ///
+ /// fn main () {
+ /// let data = vec![];
+ /// let rlp = Rlp::new(&data);
+ /// assert!(rlp.is_null());
+ /// }
+ /// ```
+ pub fn is_null(&self) -> bool {
self.rlp.is_null()
}
- fn is_empty(&self) -> bool {
+ /// Contains a zero-length string or zero-length list.
+ ///
+ /// ```rust
+ /// extern crate rlp;
+ /// use rlp::*;
+ ///
+ /// fn main () {
+ /// let data = vec![0xc0];
+ /// let rlp = Rlp::new(&data);
+ /// assert!(rlp.is_empty());
+ /// }
+ /// ```
+ pub fn is_empty(&self) -> bool {
self.rlp.is_empty()
}
- fn is_list(&self) -> bool {
+ /// List value
+ ///
+ /// ```rust
+ /// extern crate rlp;
+ /// use rlp::*;
+ ///
+ /// fn main () {
+ /// let data = vec![0xc8, 0x83, b'c', b'a', b't', 0x83, b'd', b'o', b'g'];
+ /// let rlp = Rlp::new(&data);
+ /// assert!(rlp.is_list());
+ /// }
+ /// ```
+ pub fn is_list(&self) -> bool {
self.rlp.is_list()
}
- fn is_data(&self) -> bool {
+ /// String value
+ ///
+ /// ```rust
+ /// extern crate rlp;
+ /// use rlp::*;
+ ///
+ /// fn main () {
+ /// let data = vec![0xc8, 0x83, b'c', b'a', b't', 0x83, b'd', b'o', b'g'];
+ /// let rlp = Rlp::new(&data);
+ /// assert!(rlp.at(1).is_data());
+ /// }
+ /// ```
+ pub fn is_data(&self) -> bool {
self.rlp.is_data()
}
- fn is_int(&self) -> bool {
+ /// Int value
+ ///
+ /// ```rust
+ /// extern crate rlp;
+ /// use rlp::*;
+ ///
+ /// fn main () {
+ /// let data = vec![0xc1, 0x10];
+ /// let rlp = Rlp::new(&data);
+ /// assert_eq!(rlp.is_int(), false);
+ /// assert_eq!(rlp.at(0).is_int(), true);
+ /// }
+ /// ```
+ pub fn is_int(&self) -> bool {
self.rlp.is_int()
}
- fn iter(&'view self) -> Self::Iter {
+ /// Get iterator over rlp-slices
+ ///
+ /// ```rust
+ /// extern crate rlp;
+ /// use rlp::*;
+ ///
+ /// fn main () {
+ /// let data = vec![0xc8, 0x83, b'c', b'a', b't', 0x83, b'd', b'o', b'g'];
+ /// let rlp = Rlp::new(&data);
+ /// let strings: Vec = rlp.iter().map(| i | i.as_val()).collect();
+ /// }
+ /// ```
+ pub fn iter(&'view self) -> RlpIterator<'a, 'view> {
self.into_iter()
}
- fn as_val(&self) -> Result where T: RlpDecodable {
- self.rlp.as_val()
+ /// Decode data into an object
+ pub fn as_val(&self) -> T where T: Decodable {
+ self.rlp.as_val().expect("Unexpected rlp error")
}
- 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: &'view R) -> T where R: View<'a, 'view>, T: RlpDecodable {
- let res: Result = r.as_val();
- res.unwrap_or_else(|e| panic!("DecodeError: {}, {}", e, r.as_raw().to_hex()))
+ pub fn as_list(&self) -> Vec where T: Decodable {
+ self.iter().map(|rlp| rlp.as_val()).collect()
}
- /// Decode into an object
- pub fn as_val(&self) -> T where T: RlpDecodable {
- Self::view_as_val(self)
+ /// Decode data at given list index into an object
+ pub fn val_at(&self, index: usize) -> T where T: Decodable {
+ self.at(index).as_val()
}
- /// Decode list item at given index into an object
- pub fn val_at(&self, index: usize) -> T where T: RlpDecodable {
- Self::view_as_val(&self.at(index))
+ pub fn list_at(&self, index: usize) -> Vec where T: Decodable {
+ self.at(index).as_list()
}
}
diff --git a/src/traits.rs b/src/traits.rs
index 3f79e9c..33c5ae5 100644
--- a/src/traits.rs
+++ b/src/traits.rs
@@ -16,212 +16,12 @@
//! Common RLP traits
use elastic_array::ElasticArray1024;
-use stream::RlpStream;
-use {DecoderError, UntrustedRlp};
-
-/// Type is able to decode RLP.
-pub trait Decoder: Sized {
- /// Read a value from the RLP into a given type.
- fn read_value(&self, f: &F) -> Result
- where F: Fn(&[u8]) -> Result;
-
- /// Get underlying `UntrustedRLP` object.
- fn as_rlp(&self) -> &UntrustedRlp;
- /// Get underlying raw bytes slice.
- fn as_raw(&self) -> &[u8];
-}
+use {DecoderError, UntrustedRlp, RlpStream};
/// RLP decodable trait
pub trait Decodable: Sized {
/// 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;
-}
-
-/// A view into RLP encoded data
-pub trait View<'a, 'view>: Sized {
- /// RLP prototype type
- type Prototype;
- /// Payload info type
- type PayloadInfo;
- /// Data type
- type Data;
- /// Item type
- type Item;
- /// Iterator type
- type Iter;
-
- /// Creates a new instance of `Rlp` reader
- fn new(bytes: &'a [u8]) -> Self;
-
- /// The raw data of the RLP as slice.
- ///
- /// ```rust
- /// extern crate rlp;
- /// use rlp::*;
- ///
- /// fn main () {
- /// let data = vec![0xc8, 0x83, b'c', b'a', b't', 0x83, b'd', b'o', b'g'];
- /// let rlp = Rlp::new(&data);
- /// let dog = rlp.at(1).as_raw();
- /// assert_eq!(dog, &[0x83, b'd', b'o', b'g']);
- /// }
- /// ```
- fn as_raw(&'view self) -> &'a [u8];
-
- /// Get the prototype of the RLP.
- fn prototype(&self) -> Self::Prototype;
-
- /// Get payload info.
- fn payload_info(&self) -> Self::PayloadInfo;
-
- /// Get underlieing data.
- fn data(&'view self) -> Self::Data;
-
- /// Returns number of RLP items.
- ///
- /// ```rust
- /// extern crate rlp;
- /// use rlp::*;
- ///
- /// fn main () {
- /// let data = vec![0xc8, 0x83, b'c', b'a', b't', 0x83, b'd', b'o', b'g'];
- /// let rlp = Rlp::new(&data);
- /// assert_eq!(rlp.item_count(), 2);
- /// let view = rlp.at(1);
- /// assert_eq!(view.item_count(), 0);
- /// }
- /// ```
- fn item_count(&self) -> usize;
-
- /// Returns the number of bytes in the data, or zero if it isn't data.
- ///
- /// ```rust
- /// extern crate rlp;
- /// use rlp::*;
- ///
- /// fn main () {
- /// let data = vec![0xc8, 0x83, b'c', b'a', b't', 0x83, b'd', b'o', b'g'];
- /// let rlp = Rlp::new(&data);
- /// assert_eq!(rlp.size(), 0);
- /// let view = rlp.at(1);
- /// assert_eq!(view.size(), 3);
- /// }
- /// ```
- fn size(&self) -> usize;
-
- /// Get view onto RLP-slice at index.
- ///
- /// Caches offset to given index, so access to successive
- /// slices is faster.
- ///
- /// ```rust
- /// extern crate rlp;
- /// use rlp::*;
- ///
- /// fn main () {
- /// let data = vec![0xc8, 0x83, b'c', b'a', b't', 0x83, b'd', b'o', b'g'];
- /// let rlp = Rlp::new(&data);
- /// let dog: String = rlp.at(1).as_val();
- /// assert_eq!(dog, "dog".to_string());
- /// }
- fn at(&'view self, index: usize) -> Self::Item;
-
- /// No value
- ///
- /// ```rust
- /// extern crate rlp;
- /// use rlp::*;
- ///
- /// fn main () {
- /// let data = vec![];
- /// let rlp = Rlp::new(&data);
- /// assert!(rlp.is_null());
- /// }
- /// ```
- fn is_null(&self) -> bool;
-
- /// Contains a zero-length string or zero-length list.
- ///
- /// ```rust
- /// extern crate rlp;
- /// use rlp::*;
- ///
- /// fn main () {
- /// let data = vec![0xc0];
- /// let rlp = Rlp::new(&data);
- /// assert!(rlp.is_empty());
- /// }
- /// ```
- fn is_empty(&self) -> bool;
-
- /// List value
- ///
- /// ```rust
- /// extern crate rlp;
- /// use rlp::*;
- ///
- /// fn main () {
- /// let data = vec![0xc8, 0x83, b'c', b'a', b't', 0x83, b'd', b'o', b'g'];
- /// let rlp = Rlp::new(&data);
- /// assert!(rlp.is_list());
- /// }
- /// ```
- fn is_list(&self) -> bool;
-
- /// String value
- ///
- /// ```rust
- /// extern crate rlp;
- /// use rlp::*;
- ///
- /// fn main () {
- /// let data = vec![0xc8, 0x83, b'c', b'a', b't', 0x83, b'd', b'o', b'g'];
- /// let rlp = Rlp::new(&data);
- /// assert!(rlp.at(1).is_data());
- /// }
- /// ```
- fn is_data(&self) -> bool;
-
- /// Int value
- ///
- /// ```rust
- /// extern crate rlp;
- /// use rlp::*;
- ///
- /// fn main () {
- /// let data = vec![0xc1, 0x10];
- /// let rlp = Rlp::new(&data);
- /// assert_eq!(rlp.is_int(), false);
- /// assert_eq!(rlp.at(0).is_int(), true);
- /// }
- /// ```
- fn is_int(&self) -> bool;
-
- /// Get iterator over rlp-slices
- ///
- /// ```rust
- /// extern crate rlp;
- /// use rlp::*;
- ///
- /// fn main () {
- /// let data = vec![0xc8, 0x83, b'c', b'a', b't', 0x83, b'd', b'o', b'g'];
- /// let rlp = Rlp::new(&data);
- /// let strings: Vec = rlp.iter().map(| i | i.as_val()).collect();
- /// }
- /// ```
- fn iter(&'view self) -> Self::Iter;
-
- /// Decode data into an object
- fn as_val(&self) -> Result where T: RlpDecodable;
-
- /// Decode data at given list index into an object
- fn val_at(&self, index: usize) -> Result where T: RlpDecodable;
+ fn decode(rlp: &UntrustedRlp) -> Result;
}
/// Structure encodable to RLP
diff --git a/src/untrusted_rlp.rs b/src/untrusted_rlp.rs
index e111fde..8f46bb6 100644
--- a/src/untrusted_rlp.rs
+++ b/src/untrusted_rlp.rs
@@ -17,9 +17,8 @@
use std::cell::Cell;
use std::fmt;
use rustc_serialize::hex::ToHex;
-
-use bytes::{FromBytes, FromBytesResult, FromBytesError};
-use ::{View, Decoder, Decodable, DecoderError, RlpDecodable};
+use impls::decode_usize;
+use {Decodable, DecoderError};
/// rlp offset
#[derive(Copy, Clone, Debug)]
@@ -64,7 +63,7 @@ fn calculate_payload_info(header_bytes: &[u8], len_of_len: usize) -> Result (),
}
if header_bytes.len() < header_len { return Err(DecoderError::RlpIsTooShort); }
- let value_len = usize::from_bytes(&header_bytes[1..header_len])?;
+ let value_len = decode_usize(&header_bytes[1..header_len])?;
Ok(PayloadInfo::new(header_len, value_len))
}
@@ -141,15 +140,8 @@ impl<'a> fmt::Display for UntrustedRlp<'a> {
}
}
-impl<'a, 'view> View<'a, 'view> for UntrustedRlp<'a> where 'a: 'view {
- type Prototype = Result;
- type PayloadInfo = Result;
- type Data = Result<&'a [u8], DecoderError>;
- type Item = Result, DecoderError>;
- type Iter = UntrustedRlpIterator<'a, 'view>;
-
- //returns new instance of `UntrustedRlp`
- fn new(bytes: &'a [u8]) -> UntrustedRlp<'a> {
+impl<'a, 'view> UntrustedRlp<'a> where 'a: 'view {
+ pub fn new(bytes: &'a [u8]) -> UntrustedRlp<'a> {
UntrustedRlp {
bytes: bytes,
offset_cache: Cell::new(OffsetCache::new(usize::max_value(), 0)),
@@ -157,45 +149,45 @@ impl<'a, 'view> View<'a, 'view> for UntrustedRlp<'a> where 'a: 'view {
}
}
- fn as_raw(&'view self) -> &'a [u8] {
+ pub fn as_raw(&'view self) -> &'a [u8] {
self.bytes
}
- fn prototype(&self) -> Self::Prototype {
+ pub fn prototype(&self) -> Result {
// optimize? && return appropriate errors
if self.is_data() {
Ok(Prototype::Data(self.size()))
} else if self.is_list() {
- Ok(Prototype::List(self.item_count()))
+ self.item_count().map(Prototype::List)
} else {
Ok(Prototype::Null)
}
}
- fn payload_info(&self) -> Self::PayloadInfo {
+ pub fn payload_info(&self) -> Result {
BasicDecoder::payload_info(self.bytes)
}
- fn data(&'view self) -> Self::Data {
+ pub fn data(&'view self) -> Result<&'a [u8], DecoderError> {
let pi = BasicDecoder::payload_info(self.bytes)?;
Ok(&self.bytes[pi.header_len..(pi.header_len + pi.value_len)])
}
- fn item_count(&self) -> usize {
+ pub fn item_count(&self) -> Result {
match self.is_list() {
true => match self.count_cache.get() {
- Some(c) => c,
+ Some(c) => Ok(c),
None => {
let c = self.iter().count();
self.count_cache.set(Some(c));
- c
+ Ok(c)
}
},
- false => 0
+ false => Err(DecoderError::RlpExpectedToBeList),
}
}
- fn size(&self) -> usize {
+ pub fn size(&self) -> usize {
match self.is_data() {
// TODO: No panic on malformed data, but ideally would Err on no PayloadInfo.
true => BasicDecoder::payload_info(self.bytes).map(|b| b.value_len).unwrap_or(0),
@@ -203,7 +195,7 @@ impl<'a, 'view> View<'a, 'view> for UntrustedRlp<'a> where 'a: 'view {
}
}
- fn at(&'view self, index: usize) -> Self::Item {
+ pub fn at(&'view self, index: usize) -> Result, DecoderError> {
if !self.is_list() {
return Err(DecoderError::RlpExpectedToBeList);
}
@@ -213,7 +205,7 @@ impl<'a, 'view> View<'a, 'view> for UntrustedRlp<'a> where 'a: 'view {
let c = self.offset_cache.get();
let (mut bytes, to_skip) = match c.index <= index {
true => (UntrustedRlp::consume(self.bytes, c.offset)?, index - c.index),
- false => (self.consume_list_prefix()?, index),
+ false => (self.consume_list_payload()?, index),
};
// skip up to x items
@@ -227,23 +219,23 @@ impl<'a, 'view> View<'a, 'view> for UntrustedRlp<'a> where 'a: 'view {
Ok(UntrustedRlp::new(&bytes[0..found.header_len + found.value_len]))
}
- fn is_null(&self) -> bool {
+ pub fn is_null(&self) -> bool {
self.bytes.len() == 0
}
- fn is_empty(&self) -> bool {
+ pub fn is_empty(&self) -> bool {
!self.is_null() && (self.bytes[0] == 0xc0 || self.bytes[0] == 0x80)
}
- fn is_list(&self) -> bool {
+ pub fn is_list(&self) -> bool {
!self.is_null() && self.bytes[0] >= 0xc0
}
- fn is_data(&self) -> bool {
+ pub fn is_data(&self) -> bool {
!self.is_null() && self.bytes[0] < 0xc0
}
- fn is_int(&self) -> bool {
+ pub fn is_int(&self) -> bool {
if self.is_null() {
return false;
}
@@ -256,23 +248,32 @@ impl<'a, 'view> View<'a, 'view> for UntrustedRlp<'a> where 'a: 'view {
}
}
- fn iter(&'view self) -> Self::Iter {
+ pub fn iter(&'view self) -> UntrustedRlpIterator<'a, 'view> {
self.into_iter()
}
- 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()))
+ pub fn as_val(&self) -> Result where T: Decodable {
+ T::decode(self)
}
- fn val_at(&self, index: usize) -> Result where T: RlpDecodable {
+ pub fn as_list(&self) -> Result, DecoderError> where T: Decodable {
+ self.iter().map(|rlp| rlp.as_val()).collect()
+ }
+
+ pub fn val_at(&self, index: usize) -> Result where T: Decodable {
self.at(index)?.as_val()
}
-}
-impl<'a> UntrustedRlp<'a> {
+ pub fn list_at(&self, index: usize) -> Result, DecoderError> where T: Decodable {
+ self.at(index)?.as_list()
+ }
+
+ pub fn decoder(&self) -> BasicDecoder {
+ BasicDecoder::new(self.clone())
+ }
+
/// consumes first found prefix
- fn consume_list_prefix(&self) -> Result<&'a [u8], DecoderError> {
+ fn consume_list_payload(&self) -> Result<&'a [u8], DecoderError> {
let item = BasicDecoder::payload_info(self.bytes)?;
let bytes = UntrustedRlp::consume(self.bytes, item.header_len)?;
Ok(bytes)
@@ -327,7 +328,7 @@ impl<'a, 'view> Iterator for UntrustedRlpIterator<'a, 'view> {
}
}
-struct BasicDecoder<'a> {
+pub struct BasicDecoder<'a> {
rlp: UntrustedRlp<'a>
}
@@ -346,10 +347,8 @@ impl<'a> BasicDecoder<'a> {
_ => Err(DecoderError::RlpIsTooShort),
}
}
-}
-impl<'a> Decoder for BasicDecoder<'a> {
- fn read_value(&self, f: &F) -> Result
+ pub fn decode_value(&self, f: F) -> Result
where F: Fn(&[u8]) -> Result {
let bytes = self.rlp.as_raw();
@@ -378,7 +377,7 @@ impl<'a> Decoder for BasicDecoder<'a> {
if bytes.len() < begin_of_value {
return Err(DecoderError::RlpInconsistentLengthAndData);
}
- let len = usize::from_bytes(&bytes[1..begin_of_value])?;
+ let len = decode_usize(&bytes[1..begin_of_value])?;
let last_index_of_value = begin_of_value + len;
if bytes.len() < last_index_of_value {
@@ -390,108 +389,12 @@ impl<'a> Decoder for BasicDecoder<'a> {
_ => Err(DecoderError::RlpExpectedToBeData)
}
}
-
- fn as_raw(&self) -> &[u8] {
- self.rlp.as_raw()
- }
-
- fn as_rlp(&self) -> &UntrustedRlp {
- &self.rlp
- }
-}
-
-impl Decodable for T where T: FromBytes {
- fn decode(decoder: &D) -> Result where D: Decoder {
- decoder.read_value(&|bytes: &[u8]| Ok(T::from_bytes(bytes)?))
- }
-}
-
-impl Decodable for Vec where T: Decodable {
- fn decode(decoder: &D) -> Result where D: Decoder {
- decoder.as_rlp().iter().map(|d| T::decode(&BasicDecoder::new(d))).collect()
- }
-}
-
-impl Decodable for Option where T: Decodable {
- fn decode(decoder: &D) -> Result where D: Decoder {
- decoder.as_rlp().iter().map(|d| T::decode(&BasicDecoder::new(d))).collect::, DecoderError>>().map(|mut a| a.pop())
- }
-}
-
-impl Decodable for Vec {
- fn decode(decoder: &D) -> Result where D: Decoder {
- decoder.read_value(&|bytes: &[u8]| Ok(bytes.to_vec()))
- }
-}
-
-macro_rules! impl_array_decodable {
- ($index_type:ty, $len:expr ) => (
- impl Decodable for [T; $len] where T: Decodable {
- fn decode(decoder: &D) -> Result where D: Decoder {
- let decoders = decoder.as_rlp();
-
- let mut result: [T; $len] = unsafe { ::std::mem::uninitialized() };
- if decoders.item_count() != $len {
- return Err(DecoderError::RlpIncorrectListLen);
- }
-
- for i in 0..decoders.item_count() {
- result[i] = T::decode(&BasicDecoder::new(decoders.at(i)?))?;
- }
-
- Ok(result)
- }
- }
- )
-}
-
-macro_rules! impl_array_decodable_recursive {
- ($index_type:ty, ) => ();
- ($index_type:ty, $len:expr, $($more:expr,)*) => (
- impl_array_decodable!($index_type, $len);
- impl_array_decodable_recursive!($index_type, $($more,)*);
- );
-}
-
-impl_array_decodable_recursive!(
- u8, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
- 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
- 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 = Decodable::decode(decoder)?;
- Ok(u.0)
- }
}
#[cfg(test)]
mod tests {
- use ::{UntrustedRlp, View};
+ use UntrustedRlp;
+
#[test]
fn test_rlp_display() {
use rustc_serialize::hex::FromHex;
diff --git a/src/tests.rs b/tests/tests.rs
similarity index 90%
rename from src/tests.rs
rename to tests/tests.rs
index bd3abfe..1c996ca 100644
--- a/src/tests.rs
+++ b/tests/tests.rs
@@ -14,9 +14,12 @@
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see .
+extern crate ethcore_bigint as bigint;
+extern crate rlp;
+
use std::{fmt, cmp};
use bigint::prelude::U256;
-use {Encodable, RlpDecodable, UntrustedRlp, RlpStream, View, DecoderError};
+use rlp::{Encodable, Decodable, UntrustedRlp, RlpStream, DecoderError};
#[test]
fn rlp_at() {
@@ -24,7 +27,7 @@ fn rlp_at() {
{
let rlp = UntrustedRlp::new(&data);
assert!(rlp.is_list());
- let animals: Vec = rlp.as_val().unwrap();
+ let animals: Vec = rlp.as_list().unwrap();
assert_eq!(animals, vec!["cat".to_owned(), "dog".to_owned()]);
let cat = rlp.at(0).unwrap();
@@ -89,7 +92,7 @@ fn run_encode_tests(tests: Vec>)
where T: Encodable
{
for t in &tests {
- let res = super::encode(&t.0);
+ let res = rlp::encode(&t.0);
assert_eq!(&res[..], &t.1[..]);
}
}
@@ -100,7 +103,7 @@ fn run_encode_tests_list(tests: Vec>)
where T: Encodable
{
for t in &tests {
- let res = super::encode_list(&t.0);
+ let res = rlp::encode_list(&t.0);
assert_eq!(&res[..], &t.1[..]);
}
}
@@ -210,11 +213,20 @@ fn encode_vector_str() {
run_encode_tests_list(tests);
}
-struct DTestPair(T, Vec) where T: RlpDecodable + fmt::Debug + cmp::Eq;
+struct DTestPair(T, Vec) where T: Decodable + fmt::Debug + cmp::Eq;
-fn run_decode_tests(tests: Vec>) where T: RlpDecodable + fmt::Debug + cmp::Eq {
+struct VDTestPair(Vec, Vec) where T: Decodable + fmt::Debug + cmp::Eq;
+
+fn run_decode_tests(tests: Vec>) where T: Decodable + fmt::Debug + cmp::Eq {
for t in &tests {
- let res: T = super::decode(&t.1);
+ let res: T = rlp::decode(&t.1);
+ assert_eq!(res, t.0);
+ }
+}
+
+fn run_decode_tests_list(tests: Vec>) where T: Decodable + fmt::Debug + cmp::Eq {
+ for t in &tests {
+ let res: Vec = rlp::decode_list(&t.1);
assert_eq!(res, t.0);
}
}
@@ -318,35 +330,19 @@ fn decode_untrusted_address() {
#[test]
fn decode_untrusted_vector_u64() {
let tests = vec![
- DTestPair(vec![], vec![0xc0]),
- DTestPair(vec![15u64], vec![0xc1, 0x0f]),
- DTestPair(vec![1, 2, 3, 7, 0xff], vec![0xc6, 1, 2, 3, 7, 0x81, 0xff]),
- DTestPair(vec![0xffffffff, 1, 2, 3, 7, 0xff], vec![0xcb, 0x84, 0xff, 0xff, 0xff, 0xff, 1, 2, 3, 7, 0x81, 0xff]),
+ VDTestPair(vec![], vec![0xc0]),
+ VDTestPair(vec![15u64], vec![0xc1, 0x0f]),
+ VDTestPair(vec![1, 2, 3, 7, 0xff], vec![0xc6, 1, 2, 3, 7, 0x81, 0xff]),
+ VDTestPair(vec![0xffffffff, 1, 2, 3, 7, 0xff], vec![0xcb, 0x84, 0xff, 0xff, 0xff, 0xff, 1, 2, 3, 7, 0x81, 0xff]),
];
- run_decode_tests(tests);
+ run_decode_tests_list(tests);
}
#[test]
fn decode_untrusted_vector_str() {
- let tests = vec![DTestPair(vec!["cat".to_owned(), "dog".to_owned()],
+ let tests = vec![VDTestPair(vec!["cat".to_owned(), "dog".to_owned()],
vec![0xc8, 0x83, b'c', b'a', b't', 0x83, b'd', b'o', b'g'])];
- run_decode_tests(tests);
-}
-
-#[test]
-fn decode_untrusted_vector_of_vectors_str() {
- let tests = vec![DTestPair(vec![vec!["cat".to_owned()]],
- vec![0xc5, 0xc4, 0x83, b'c', b'a', b't'])];
- run_decode_tests(tests);
-}
-
-#[test]
-fn test_decoding_array() {
- let v = vec![5u16, 2u16];
- let res = super::encode_list(&v);
- let arr: [u16; 2] = super::decode(&res);
- assert_eq!(arr[0], 5);
- assert_eq!(arr[1], 2);
+ run_decode_tests_list(tests);
}
#[test]