Merge branch 'master' of github.com:gavofyork/ethcore-util
This commit is contained in:
commit
7abac7fba8
370
src/rlp.rs
370
src/rlp.rs
@ -1,85 +1,34 @@
|
|||||||
//! Rlp serialization module
|
//! Rlp serialization module
|
||||||
//!
|
//!
|
||||||
//! Types implementing `Endocable` and `Decodable` traits
|
//! Allows encoding, decoding, and view onto rlp-slice
|
||||||
//! can be easily coverted to and from rlp.
|
|
||||||
//! Trusted rlp should be decoded with `Rlp`, untrusted with `UntrustedRlp`.
|
|
||||||
//!
|
//!
|
||||||
//! # Examples:
|
//!# When should you use what?
|
||||||
//!
|
//!
|
||||||
//! ```rust
|
//!### Use `encode` function when:
|
||||||
//! extern crate ethcore_util;
|
//! * You want to encode something inline.
|
||||||
//! use ethcore_util::rlp::{Rlp, UntrustedRlp, RlpStream, Decodable};
|
//! * You do not work on big set of data.
|
||||||
|
//! * You want to encode whole data structure at once.
|
||||||
//!
|
//!
|
||||||
//! fn encode_value() {
|
//!### Use `decode` function when:
|
||||||
//! // 1029
|
//! * You want to decode something inline.
|
||||||
//! let mut stream = RlpStream::new();
|
//! * You do not work on big set of data.
|
||||||
//! stream.append(&1029u32);
|
//! * You want to decode whole rlp at once.
|
||||||
//! let out = stream.out().unwrap();
|
|
||||||
//! assert_eq!(out, vec![0x82, 0x04, 0x05]);
|
|
||||||
//! }
|
|
||||||
//!
|
//!
|
||||||
//! fn encode_list() {
|
//!### Use `RlpStream` when:
|
||||||
//! // [ "cat", "dog" ]
|
//! * You want to encode something in portions.
|
||||||
//! let mut stream = RlpStream::new_list(2);
|
//! * You encode a big set of data.
|
||||||
//! stream.append(&"cat").append(&"dog");
|
|
||||||
//! let out = stream.out().unwrap();
|
|
||||||
//! assert_eq!(out, vec![0xc8, 0x83, b'c', b'a', b't', 0x83, b'd', b'o', b'g']);
|
|
||||||
//! }
|
|
||||||
//!
|
//!
|
||||||
//! fn encode_list2() {
|
//!### Use `Rlp` when:
|
||||||
//! // [ [], [[]], [ [], [[]] ] ]
|
//! * You are working on trusted data (not corrupted).
|
||||||
//! let mut stream = RlpStream::new_list(3);
|
//! * You want to get view onto rlp-slice.
|
||||||
//! stream.append_list(0);
|
//! * You don't want to decode whole rlp at once.
|
||||||
//! stream.append_list(1).append_list(0);
|
|
||||||
//! stream.append_list(2).append_list(0).append_list(1).append_list(0);
|
|
||||||
//! let out = stream.out().unwrap();
|
|
||||||
//! assert_eq!(out, vec![0xc7, 0xc0, 0xc1, 0xc0, 0xc3, 0xc0, 0xc1, 0xc0]);
|
|
||||||
//! }
|
|
||||||
//!
|
|
||||||
//! fn decode_value() {
|
|
||||||
//! // 0x102456789abcdef
|
|
||||||
//! let data = vec![0x88, 0x10, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef];
|
|
||||||
//! let rlp = Rlp::new(&data);
|
|
||||||
//! let _ = u64::decode(&rlp);
|
|
||||||
//! }
|
|
||||||
//!
|
|
||||||
//! fn decode_untrusted_string() {
|
|
||||||
//! // "cat"
|
|
||||||
//! let data = vec![0x83, b'c', b'a', b't'];
|
|
||||||
//! let rlp = UntrustedRlp::new(&data);
|
|
||||||
//! let _ = String::decode_untrusted(&rlp).unwrap();
|
|
||||||
//! }
|
|
||||||
//!
|
|
||||||
//! fn decode_list() {
|
|
||||||
//! // ["cat", "dog"]
|
|
||||||
//! let data = vec![0xc8, 0x83, b'c', b'a', b't', 0x83, b'd', b'o', b'g'];
|
|
||||||
//! let rlp = Rlp::new(&data);
|
|
||||||
//! let _ : Vec<String> = Decodable::decode(&rlp);
|
|
||||||
//! }
|
|
||||||
//!
|
|
||||||
//! fn decode_list2() {
|
|
||||||
//! // [ [], [[]], [ [], [[]] ] ]
|
|
||||||
//! let data = vec![0xc7, 0xc0, 0xc1, 0xc0, 0xc3, 0xc0, 0xc1, 0xc0];
|
|
||||||
//! let rlp = Rlp::new(&data);
|
|
||||||
//! let _v0: Vec<u16> = Decodable::decode(&rlp.at(0));
|
|
||||||
//! let _v1: Vec<Vec<u16>> = Decodable::decode(&rlp.at(1));
|
|
||||||
//! let nested_rlp = rlp.at(2);
|
|
||||||
//! let _v2a: Vec<u16> = Decodable::decode(&nested_rlp.at(0));
|
|
||||||
//! let _v2b: Vec<Vec<u16>> = Decodable::decode(&nested_rlp.at(1));
|
|
||||||
//! }
|
|
||||||
//!
|
|
||||||
//! fn main() {
|
|
||||||
//! encode_value();
|
|
||||||
//! encode_list();
|
|
||||||
//! encode_list2();
|
|
||||||
//!
|
|
||||||
//! decode_value();
|
|
||||||
//! decode_untrusted_string();
|
|
||||||
//! decode_list();
|
|
||||||
//! decode_list2();
|
|
||||||
//! }
|
|
||||||
//! ```
|
|
||||||
//!
|
//!
|
||||||
|
//!### Use `UntrustedRlp` when:
|
||||||
|
//! * You are working on untrusted data (~corrupted).
|
||||||
|
//! * You need to handle data corruption errors.
|
||||||
|
//! * You are working on input data.
|
||||||
|
//! * You want to get view onto rlp-slice.
|
||||||
|
//! * You don't want to decode whole rlp at once.
|
||||||
|
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::cell::Cell;
|
use std::cell::Cell;
|
||||||
@ -88,7 +37,12 @@ use std::error::Error as StdError;
|
|||||||
use bytes::{ToBytes, FromBytes, FromBytesError};
|
use bytes::{ToBytes, FromBytes, FromBytesError};
|
||||||
use vector::InsertSlice;
|
use vector::InsertSlice;
|
||||||
|
|
||||||
/// rlp container
|
/// Data-oriented view onto rlp-slice.
|
||||||
|
///
|
||||||
|
/// This is immutable structere. No operations change it.
|
||||||
|
///
|
||||||
|
/// Should be used in places where, error handling is required,
|
||||||
|
/// eg. on input
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct UntrustedRlp<'a> {
|
pub struct UntrustedRlp<'a> {
|
||||||
bytes: &'a [u8],
|
bytes: &'a [u8],
|
||||||
@ -152,10 +106,10 @@ impl From<FromBytesError> for DecoderError {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Unsafe wrapper for rlp decode_untrustedr.
|
/// Data-oriented view onto trusted rlp-slice.
|
||||||
///
|
///
|
||||||
/// It assumes that you know what you are doing. Doesn't bother
|
/// Unlikely to `UntrustedRlp` doesn't bother you with error
|
||||||
/// you with error handling.
|
/// handling. It assumes that you know what you are doing.
|
||||||
pub struct Rlp<'a> {
|
pub struct Rlp<'a> {
|
||||||
rlp: UntrustedRlp<'a>
|
rlp: UntrustedRlp<'a>
|
||||||
}
|
}
|
||||||
@ -173,30 +127,79 @@ impl<'a> From<Rlp<'a>> for UntrustedRlp<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Rlp<'a> {
|
impl<'a> Rlp<'a> {
|
||||||
/// returns new instance of `Rlp`
|
/// Create a new instance of `Rlp`
|
||||||
pub fn new(bytes: &'a [u8]) -> Rlp<'a> {
|
pub fn new(bytes: &'a [u8]) -> Rlp<'a> {
|
||||||
Rlp {
|
Rlp {
|
||||||
rlp: UntrustedRlp::new(bytes)
|
rlp: UntrustedRlp::new(bytes)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get view onto rlp-slice at index.
|
||||||
|
///
|
||||||
|
/// Caches offset to given index, so access to successive
|
||||||
|
/// slices is faster.
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// extern crate ethcore_util as util;
|
||||||
|
/// use util::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::decode(&rlp.at(1));
|
||||||
|
/// assert_eq!(dog, "dog".to_string());
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
pub fn at(&self, index: usize) -> Rlp<'a> {
|
pub fn at(&self, index: usize) -> Rlp<'a> {
|
||||||
From::from(self.rlp.at(index).unwrap())
|
From::from(self.rlp.at(index).unwrap())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// returns true if rlp is a list
|
/// List value
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// extern crate ethcore_util as util;
|
||||||
|
/// use util::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 {
|
pub fn is_list(&self) -> bool {
|
||||||
self.rlp.is_list()
|
self.rlp.is_list()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// returns true if rlp is a value
|
/// String value
|
||||||
pub fn is_value(&self) -> bool {
|
///
|
||||||
self.rlp.is_value()
|
/// ```rust
|
||||||
|
/// extern crate ethcore_util as util;
|
||||||
|
/// use util::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()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// returns rlp iterator
|
/// Get iterator over rlp-slices
|
||||||
pub fn iter(&'a self) -> UntrustedRlpIterator<'a> {
|
///
|
||||||
self.rlp.into_iter()
|
/// ```rust
|
||||||
|
/// extern crate ethcore_util as util;
|
||||||
|
/// use util::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<String> = rlp.iter().map(| i | String::decode(&i)).collect();
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
pub fn iter(&'a self) -> RlpIterator<'a> {
|
||||||
|
self.into_iter()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -209,9 +212,22 @@ impl<'a> UntrustedRlp<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// get container subset at given index
|
/// Get view onto rlp-slice at index
|
||||||
///
|
///
|
||||||
/// paren container caches searched position
|
/// Caches offset to given index, so access to successive
|
||||||
|
/// slices is faster.
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// extern crate ethcore_util as util;
|
||||||
|
/// use util::rlp::*;
|
||||||
|
///
|
||||||
|
/// fn main () {
|
||||||
|
/// let data = vec![0xc8, 0x83, b'c', b'a', b't', 0x83, b'd', b'o', b'g'];
|
||||||
|
/// let rlp = UntrustedRlp::new(&data);
|
||||||
|
/// let dog = String::decode_untrusted(&rlp.at(1).unwrap()).unwrap();
|
||||||
|
/// assert_eq!(dog, "dog".to_string());
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
pub fn at(&self, index: usize) -> Result<UntrustedRlp<'a>, DecoderError> {
|
pub fn at(&self, index: usize) -> Result<UntrustedRlp<'a>, DecoderError> {
|
||||||
if !self.is_list() {
|
if !self.is_list() {
|
||||||
return Err(DecoderError::UntrustedRlpExpectedToBeList);
|
return Err(DecoderError::UntrustedRlpExpectedToBeList);
|
||||||
@ -236,17 +252,53 @@ impl<'a> UntrustedRlp<'a> {
|
|||||||
Ok(UntrustedRlp::new(&bytes[0..found.prefix_len + found.value_len]))
|
Ok(UntrustedRlp::new(&bytes[0..found.prefix_len + found.value_len]))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// returns true if rlp is a list
|
/// List value
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// extern crate ethcore_util as util;
|
||||||
|
/// use util::rlp::*;
|
||||||
|
///
|
||||||
|
/// fn main () {
|
||||||
|
/// let data = vec![0xc8, 0x83, b'c', b'a', b't', 0x83, b'd', b'o', b'g'];
|
||||||
|
/// let rlp = UntrustedRlp::new(&data);
|
||||||
|
/// assert!(rlp.is_list());
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
pub fn is_list(&self) -> bool {
|
pub fn is_list(&self) -> bool {
|
||||||
self.bytes.len() > 0 && self.bytes[0] >= 0xc0
|
self.bytes.len() > 0 && self.bytes[0] >= 0xc0
|
||||||
}
|
}
|
||||||
|
|
||||||
/// returns true if rlp is a value
|
/// String value
|
||||||
pub fn is_value(&self) -> bool {
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// extern crate ethcore_util as util;
|
||||||
|
/// use util::rlp::*;
|
||||||
|
///
|
||||||
|
/// fn main () {
|
||||||
|
/// let data = vec![0xc8, 0x83, b'c', b'a', b't', 0x83, b'd', b'o', b'g'];
|
||||||
|
/// let rlp = UntrustedRlp::new(&data);
|
||||||
|
/// assert!(rlp.at(1).unwrap().is_data());
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
pub fn is_data(&self) -> bool {
|
||||||
self.bytes.len() > 0 && self.bytes[0] <= 0xbf
|
self.bytes.len() > 0 && self.bytes[0] <= 0xbf
|
||||||
}
|
}
|
||||||
|
|
||||||
/// returns rlp iterator
|
/// Get iterator over rlp-slices
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// extern crate ethcore_util as util;
|
||||||
|
/// use util::rlp::*;
|
||||||
|
///
|
||||||
|
/// fn main () {
|
||||||
|
/// let data = vec![0xc8, 0x83, b'c', b'a', b't', 0x83, b'd', b'o', b'g'];
|
||||||
|
/// let rlp = UntrustedRlp::new(&data);
|
||||||
|
/// let strings: Vec<String> = rlp.iter()
|
||||||
|
/// .map(| i | String::decode_untrusted(&i))
|
||||||
|
/// .map(| s | s.unwrap())
|
||||||
|
/// .collect();
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
pub fn iter(&'a self) -> UntrustedRlpIterator<'a> {
|
pub fn iter(&'a self) -> UntrustedRlpIterator<'a> {
|
||||||
self.into_iter()
|
self.into_iter()
|
||||||
}
|
}
|
||||||
@ -307,7 +359,7 @@ impl<'a> UntrustedRlp<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// non-consuming rlp iterator
|
/// Iterator over rlp-slice list elements.
|
||||||
pub struct UntrustedRlpIterator<'a> {
|
pub struct UntrustedRlpIterator<'a> {
|
||||||
rlp: &'a UntrustedRlp<'a>,
|
rlp: &'a UntrustedRlp<'a>,
|
||||||
index: usize,
|
index: usize,
|
||||||
@ -336,18 +388,53 @@ impl<'a> Iterator for UntrustedRlpIterator<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// shortcut function to decoded Trusted Rlp `&[u8]` into an object
|
|
||||||
|
/// Iterator over trusted rlp-slice list elements.
|
||||||
|
pub struct RlpIterator<'a> {
|
||||||
|
rlp: &'a Rlp<'a>,
|
||||||
|
index: usize
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> IntoIterator for &'a Rlp<'a> {
|
||||||
|
type Item = Rlp<'a>;
|
||||||
|
type IntoIter = RlpIterator<'a>;
|
||||||
|
|
||||||
|
fn into_iter(self) -> Self::IntoIter {
|
||||||
|
RlpIterator {
|
||||||
|
rlp: self,
|
||||||
|
index: 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Iterator for RlpIterator<'a> {
|
||||||
|
type Item = Rlp<'a>;
|
||||||
|
|
||||||
|
fn next(&mut self) -> Option<Rlp<'a>> {
|
||||||
|
let index = self.index;
|
||||||
|
let result = self.rlp.rlp.at(index).ok().map(| iter | { From::from(iter) });
|
||||||
|
self.index += 1;
|
||||||
|
result
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Shortcut function to decode trusted rlp
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// extern crate ethcore_util as util;
|
||||||
|
/// use util::rlp::*;
|
||||||
|
///
|
||||||
|
/// fn main () {
|
||||||
|
/// let data = vec![0xc8, 0x83, b'c', b'a', b't', 0x83, b'd', b'o', b'g'];
|
||||||
|
/// let animals: Vec<String> = decode(&data);
|
||||||
|
/// 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: Decodable {
|
||||||
let rlp = Rlp::new(bytes);
|
let rlp = Rlp::new(bytes);
|
||||||
T::decode(&rlp)
|
T::decode(&rlp)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// shortcut function to decode UntrustedRlp `&[u8]` into an object
|
|
||||||
pub fn decode_untrusted<T>(bytes: &[u8]) -> Result<T, DecoderError> where T: Decodable {
|
|
||||||
let rlp = UntrustedRlp::new(bytes);
|
|
||||||
T::decode_untrusted(&rlp)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub trait Decodable: Sized {
|
pub trait Decodable: Sized {
|
||||||
fn decode_untrusted(rlp: &UntrustedRlp) -> Result<Self, DecoderError>;
|
fn decode_untrusted(rlp: &UntrustedRlp) -> Result<Self, DecoderError>;
|
||||||
fn decode(rlp: &Rlp) -> Self {
|
fn decode(rlp: &Rlp) -> Self {
|
||||||
@ -357,7 +444,7 @@ pub trait Decodable: Sized {
|
|||||||
|
|
||||||
impl<T> Decodable for T where T: FromBytes {
|
impl<T> Decodable for T where T: FromBytes {
|
||||||
fn decode_untrusted(rlp: &UntrustedRlp) -> Result<Self, DecoderError> {
|
fn decode_untrusted(rlp: &UntrustedRlp) -> Result<Self, DecoderError> {
|
||||||
match rlp.is_value() {
|
match rlp.is_data() {
|
||||||
true => BasicDecoder::read_value(rlp.bytes, | bytes | {
|
true => BasicDecoder::read_value(rlp.bytes, | bytes | {
|
||||||
Ok(try!(T::from_bytes(bytes)))
|
Ok(try!(T::from_bytes(bytes)))
|
||||||
}),
|
}),
|
||||||
@ -377,7 +464,7 @@ impl<T> Decodable for Vec<T> where T: Decodable {
|
|||||||
|
|
||||||
impl Decodable for Vec<u8> {
|
impl Decodable for Vec<u8> {
|
||||||
fn decode_untrusted(rlp: &UntrustedRlp) -> Result<Self, DecoderError> {
|
fn decode_untrusted(rlp: &UntrustedRlp) -> Result<Self, DecoderError> {
|
||||||
match rlp.is_value() {
|
match rlp.is_data() {
|
||||||
true => BasicDecoder::read_value(rlp.bytes, | bytes | {
|
true => BasicDecoder::read_value(rlp.bytes, | bytes | {
|
||||||
let mut res = vec![];
|
let mut res = vec![];
|
||||||
res.extend(bytes);
|
res.extend(bytes);
|
||||||
@ -432,15 +519,14 @@ impl ListInfo {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// container that should be used to encode rlp
|
/// Appendable rlp encoder.
|
||||||
pub struct RlpStream {
|
pub struct RlpStream {
|
||||||
unfinished_lists: LinkedList<ListInfo>,
|
unfinished_lists: LinkedList<ListInfo>,
|
||||||
encoder: BasicEncoder,
|
encoder: BasicEncoder,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RlpStream {
|
impl RlpStream {
|
||||||
/// create new container for values appended one after another,
|
/// Initializes instance of empty `RlpStream`.
|
||||||
/// but not being part of the same list
|
|
||||||
pub fn new() -> RlpStream {
|
pub fn new() -> RlpStream {
|
||||||
RlpStream {
|
RlpStream {
|
||||||
unfinished_lists: LinkedList::new(),
|
unfinished_lists: LinkedList::new(),
|
||||||
@ -448,7 +534,7 @@ impl RlpStream {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// create new container for list of size `max_len`
|
/// Initializes the `RLPStream` as a list.
|
||||||
pub fn new_list(len: usize) -> RlpStream {
|
pub fn new_list(len: usize) -> RlpStream {
|
||||||
let mut stream = RlpStream::new();
|
let mut stream = RlpStream::new();
|
||||||
stream.append_list(len);
|
stream.append_list(len);
|
||||||
@ -456,6 +542,18 @@ impl RlpStream {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Apends value to the end of stream, chainable.
|
/// Apends value to the end of stream, chainable.
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// extern crate ethcore_util as util;
|
||||||
|
/// use util::rlp::*;
|
||||||
|
///
|
||||||
|
/// fn main () {
|
||||||
|
/// let mut stream = RlpStream::new_list(2);
|
||||||
|
/// stream.append(&"cat").append(&"dog");
|
||||||
|
/// let out = stream.out().unwrap();
|
||||||
|
/// assert_eq!(out, vec![0xc8, 0x83, b'c', b'a', b't', 0x83, b'd', b'o', b'g']);
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
pub fn append<'a, E>(&'a mut self, object: &E) -> &'a mut RlpStream where E: Encodable + fmt::Debug {
|
pub fn append<'a, E>(&'a mut self, object: &E) -> &'a mut RlpStream where E: Encodable + fmt::Debug {
|
||||||
//println!("append: {:?}", object);
|
//println!("append: {:?}", object);
|
||||||
// encode given value and add it at the end of the stream
|
// encode given value and add it at the end of the stream
|
||||||
@ -469,6 +567,19 @@ impl RlpStream {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Declare appending the list of given size, chainable.
|
/// Declare appending the list of given size, chainable.
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// extern crate ethcore_util as util;
|
||||||
|
/// use util::rlp::*;
|
||||||
|
///
|
||||||
|
/// fn main () {
|
||||||
|
/// let mut stream = RlpStream::new_list(2);
|
||||||
|
/// stream.append_list(2).append(&"cat").append(&"dog");
|
||||||
|
/// stream.append(&"");
|
||||||
|
/// let out = stream.out().unwrap();
|
||||||
|
/// assert_eq!(out, vec![0xca, 0xc8, 0x83, b'c', b'a', b't', 0x83, b'd', b'o', b'g', 0x80]);
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
pub fn append_list<'a>(&'a mut self, len: usize) -> &'a mut RlpStream {
|
pub fn append_list<'a>(&'a mut self, len: usize) -> &'a mut RlpStream {
|
||||||
//println!("append_list: {}", len);
|
//println!("append_list: {}", len);
|
||||||
// push new list
|
// push new list
|
||||||
@ -499,12 +610,28 @@ impl RlpStream {
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
/// return true if stream is ready
|
/// Returns true if stream doesnt expect any more items.
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// extern crate ethcore_util as util;
|
||||||
|
/// use util::rlp::*;
|
||||||
|
///
|
||||||
|
/// fn main () {
|
||||||
|
/// let mut stream = RlpStream::new_list(2);
|
||||||
|
/// stream.append(&"cat");
|
||||||
|
/// assert_eq!(stream.is_finished(), false);
|
||||||
|
/// stream.append(&"dog");
|
||||||
|
/// assert_eq!(stream.is_finished(), true);
|
||||||
|
/// let out = stream.out().unwrap();
|
||||||
|
/// assert_eq!(out, vec![0xc8, 0x83, b'c', b'a', b't', 0x83, b'd', b'o', b'g']);
|
||||||
|
/// }
|
||||||
pub fn is_finished(&self) -> bool {
|
pub fn is_finished(&self) -> bool {
|
||||||
self.unfinished_lists.back().is_none()
|
self.unfinished_lists.back().is_none()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// streams out encoded bytes
|
/// Streams out encoded bytes.
|
||||||
|
///
|
||||||
|
/// Returns an error if stream is not finished.
|
||||||
pub fn out(self) -> Result<Vec<u8>, EncoderError> {
|
pub fn out(self) -> Result<Vec<u8>, EncoderError> {
|
||||||
match self.is_finished() {
|
match self.is_finished() {
|
||||||
true => Ok(self.encoder.out()),
|
true => Ok(self.encoder.out()),
|
||||||
@ -534,7 +661,18 @@ impl RlpStream {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// shortcut function to encode a `T: Encodable` into a UntrustedRlp `Vec<u8>`
|
/// Shortcut function to encode structure into rlp.
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// extern crate ethcore_util as util;
|
||||||
|
/// use util::rlp::*;
|
||||||
|
///
|
||||||
|
/// fn main () {
|
||||||
|
/// let animals = vec!["cat", "dog"];
|
||||||
|
/// let out = encode(&animals);
|
||||||
|
/// assert_eq!(out, vec![0xc8, 0x83, b'c', b'a', b't', 0x83, b'd', b'o', b'g']);
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
pub fn encode<E>(object: &E) -> Vec<u8> where E: Encodable
|
pub fn encode<E>(object: &E) -> Vec<u8> where E: Encodable
|
||||||
{
|
{
|
||||||
let mut encoder = BasicEncoder::new();
|
let mut encoder = BasicEncoder::new();
|
||||||
@ -694,17 +832,17 @@ mod tests {
|
|||||||
assert_eq!(animals, vec!["cat".to_string(), "dog".to_string()]);
|
assert_eq!(animals, vec!["cat".to_string(), "dog".to_string()]);
|
||||||
|
|
||||||
let cat = rlp.at(0).unwrap();
|
let cat = rlp.at(0).unwrap();
|
||||||
assert!(cat.is_value());
|
assert!(cat.is_data());
|
||||||
assert_eq!(cat.bytes, &[0x83, b'c', b'a', b't']);
|
assert_eq!(cat.bytes, &[0x83, b'c', b'a', b't']);
|
||||||
assert_eq!(String::decode_untrusted(&cat).unwrap(), "cat".to_string());
|
assert_eq!(String::decode_untrusted(&cat).unwrap(), "cat".to_string());
|
||||||
|
|
||||||
let dog = rlp.at(1).unwrap();
|
let dog = rlp.at(1).unwrap();
|
||||||
assert!(dog.is_value());
|
assert!(dog.is_data());
|
||||||
assert_eq!(dog.bytes, &[0x83, b'd', b'o', b'g']);
|
assert_eq!(dog.bytes, &[0x83, b'd', b'o', b'g']);
|
||||||
assert_eq!(String::decode_untrusted(&dog).unwrap(), "dog".to_string());
|
assert_eq!(String::decode_untrusted(&dog).unwrap(), "dog".to_string());
|
||||||
|
|
||||||
let cat_again = rlp.at(0).unwrap();
|
let cat_again = rlp.at(0).unwrap();
|
||||||
assert!(cat_again.is_value());
|
assert!(cat_again.is_data());
|
||||||
assert_eq!(cat_again.bytes, &[0x83, b'c', b'a', b't']);
|
assert_eq!(cat_again.bytes, &[0x83, b'c', b'a', b't']);
|
||||||
assert_eq!(String::decode_untrusted(&cat_again).unwrap(), "cat".to_string());
|
assert_eq!(String::decode_untrusted(&cat_again).unwrap(), "cat".to_string());
|
||||||
}
|
}
|
||||||
@ -733,18 +871,18 @@ mod tests {
|
|||||||
let mut iter = rlp.iter();
|
let mut iter = rlp.iter();
|
||||||
|
|
||||||
let cat = iter.next().unwrap();
|
let cat = iter.next().unwrap();
|
||||||
assert!(cat.is_value());
|
assert!(cat.is_data());
|
||||||
assert_eq!(cat.bytes, &[0x83, b'c', b'a', b't']);
|
assert_eq!(cat.bytes, &[0x83, b'c', b'a', b't']);
|
||||||
|
|
||||||
let dog = iter.next().unwrap();
|
let dog = iter.next().unwrap();
|
||||||
assert!(dog.is_value());
|
assert!(dog.is_data());
|
||||||
assert_eq!(dog.bytes, &[0x83, b'd', b'o', b'g']);
|
assert_eq!(dog.bytes, &[0x83, b'd', b'o', b'g']);
|
||||||
|
|
||||||
let none = iter.next();
|
let none = iter.next();
|
||||||
assert!(none.is_none());
|
assert!(none.is_none());
|
||||||
|
|
||||||
let cat_again = rlp.at(0).unwrap();
|
let cat_again = rlp.at(0).unwrap();
|
||||||
assert!(cat_again.is_value());
|
assert!(cat_again.is_data());
|
||||||
assert_eq!(cat_again.bytes, &[0x83, b'c', b'a', b't']);
|
assert_eq!(cat_again.bytes, &[0x83, b'c', b'a', b't']);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -922,7 +1060,7 @@ mod tests {
|
|||||||
|
|
||||||
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::Decodable + fmt::Debug + cmp::Eq {
|
||||||
for t in &tests {
|
for t in &tests {
|
||||||
let res: T = rlp::decode_untrusted(&t.1).unwrap();
|
let res: T = rlp::decode(&t.1);
|
||||||
assert_eq!(res, t.0);
|
assert_eq!(res, t.0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user