docs for rlp

This commit is contained in:
debris 2015-11-30 02:55:03 +01:00
parent 448577d99c
commit 122144c00a

View File

@ -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
///
/// ```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 { pub fn is_data(&self) -> bool {
self.rlp.is_data() 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
///
/// ```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 { 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 {
@ -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();
@ -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);
} }
} }