rlp view interface + refactor

This commit is contained in:
debris 2015-12-07 23:47:26 +01:00
parent 36bea4692e
commit 7e287755ca
4 changed files with 462 additions and 29 deletions

View File

@ -1,23 +1,198 @@
pub trait Reader<'a, 'view>: Sized {
pub trait Decoder {
type Error;
fn read_value<T, F>(&self, f: F) -> Result<T, Self::Error>
where F: FnOnce(&[u8]) -> Result<T, Self::Error>;
fn read_list<T, F>(&self, f: F) -> Result<T, Self::Error>
where F: FnOnce(&[Self]) -> Result<T, Self::Error>;
}
pub trait Decodable: Sized {
fn decode<T, D>(decoder: &D) -> Result<T, D::Error> where D: Decoder;
}
pub trait View<'a, 'view>: Sized {
type Prototype;
type PayloadInfo;
type Data;
type Item;
type Iter;
type Error;
/// Creates a new instance of `Rlp` reader
fn new(bytes: &'a [u8]) -> Self;
/// The raw data of the 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 rlp = Rlp::new(&data);
/// let dog = rlp.at(1).raw();
/// assert_eq!(dog, &[0x83, b'd', b'o', b'g']);
/// }
/// ```
fn raw(&'view self) -> &'a [u8];
/// Get the prototype of the RLP.
fn prototype(&self) -> Self::Prototype;
fn payload_info(&self) -> Self::PayloadInfo;
fn data(&'view self) -> Self::Data;
/// Returns number of RLP items.
///
/// ```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_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 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_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 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());
/// }
fn at(&'view self, index: usize) -> Self::Item;
/// No value
///
/// ```rust
/// extern crate ethcore_util as util;
/// use util::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 ethcore_util as util;
/// use util::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 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());
/// }
/// ```
fn is_list(&self) -> bool;
/// 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());
/// }
/// ```
fn is_data(&self) -> bool;
/// Int value
///
/// ```rust
/// extern crate ethcore_util as util;
/// use util::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 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();
/// }
/// ```
fn iter(&'view self) -> Self::Iter;
fn as_val<T>(&self) -> Result<T, Self::Error> where T: Decodable;
}
pub trait Stream {
pub trait Encoder {
fn emit_value(&mut self, bytes: &[u8]) -> ();
fn emit_list<F>(&mut self, f: F) -> () where F: FnOnce(&mut Self) -> ();
}
pub trait Encodable {
fn encode<E>(&self, encoder: &mut E) -> () where E: Encoder;
}
pub trait Stream: Sized {
fn new() -> Self;
fn new_list(len: usize) -> Self;
fn append<'a, E>(&'a mut self, object: &E) -> &'a mut Self;
}

View File

@ -1,6 +1,7 @@
pub mod old;
pub mod faces;
pub mod coders;
pub mod rlp;
pub mod untrusted_rlp;

View File

@ -1,19 +1,28 @@
use super::faces::Reader;
use super::faces::{View, Decodable};
use super::untrusted_rlp::*;
impl<'a> From<UntrustedRlp<'a>> for Rlp<'a> {
fn from(rlp: UntrustedRlp<'a>) -> Rlp<'a> {
Rlp { rlp: rlp }
}
}
/// Data-oriented view onto trusted rlp-slice.
///
/// Unlikely to `UntrustedRlp` doesn't bother you with error
/// handling. It assumes that you know what you are doing.
#[derive(Debug)]
pub struct Rlp<'a> {
rlp: UntrustedRlp<'a>
}
impl<'a, 'view> Reader<'a, 'view> for Rlp<'a> where 'a: 'view {
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>;
type Error = DecoderError;
/// Create a new instance of `Rlp`
fn new(bytes: &'a [u8]) -> Rlp<'a> {
@ -27,46 +36,94 @@ impl<'a, 'view> Reader<'a, 'view> for Rlp<'a> where 'a: 'view {
}
fn prototype(&self) -> Self::Prototype {
unimplemented!()
self.rlp.prototype().unwrap()
}
fn payload_info(&self) -> Self::PayloadInfo {
unimplemented!()
self.rlp.payload_info().unwrap()
}
fn data(&'view self) -> Self::Data {
unimplemented!()
self.rlp.data().unwrap()
}
fn item_count(&self) -> usize {
unimplemented!()
self.rlp.item_count()
}
fn size(&self) -> usize {
unimplemented!()
self.rlp.size()
}
fn at(&'view self, index: usize) -> Self::Item {
unimplemented!()
From::from(self.rlp.at(index).unwrap())
}
fn is_null(&self) -> bool {
unimplemented!()
self.rlp.is_null()
}
fn is_empty(&self) -> bool {
unimplemented!()
self.rlp.is_empty()
}
fn is_list(&self) -> bool {
unimplemented!()
self.rlp.is_list()
}
fn is_data(&self) -> bool {
unimplemented!()
self.rlp.is_data()
}
fn is_int(&self) -> bool {
unimplemented!()
self.rlp.is_int()
}
fn iter(&'view self) -> Self::Iter {
self.into_iter()
}
fn as_val<T>(&self) -> Result<T, Self::Error> where T: Decodable {
self.rlp.as_val()
}
}
impl <'a, 'view> Rlp<'a> where 'a: 'view {
fn reader_as_val<T, R>(r: &R) -> T where R: View<'a, 'view>, T: Decodable {
let res: Result<T, R::Error> = r.as_val();
res.unwrap_or_else(|_| panic!())
}
pub fn as_val<T>(&self) -> T where T: Decodable {
Self::reader_as_val(self)
}
}
/// Iterator over trusted rlp-slice list elements.
pub struct RlpIterator<'a, 'view> where 'a: 'view {
rlp: &'view Rlp<'a>,
index: usize
}
impl<'a, 'view> IntoIterator for &'view Rlp<'a> where 'a: 'view {
type Item = Rlp<'a>;
type IntoIter = RlpIterator<'a, 'view>;
fn into_iter(self) -> Self::IntoIter {
RlpIterator {
rlp: self,
index: 0,
}
}
}
impl<'a, 'view> Iterator for RlpIterator<'a, 'view> {
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
}
}

View File

@ -1,8 +1,8 @@
use std::fmt;
use std::cell::Cell;
use std::error::Error as StdError;
use bytes::{FromBytesError};
use super::faces::Reader;
use bytes::{FromBytes, FromBytesError};
use super::faces::{View, Decoder, Decodable};
/// rlp offset
#[derive(Copy, Clone, Debug)]
@ -79,11 +79,22 @@ pub struct UntrustedRlp<'a> {
cache: Cell<OffsetCache>,
}
impl<'a, 'view> Reader<'a, 'view> for UntrustedRlp<'a> where 'a: 'view {
impl<'a> Clone for UntrustedRlp<'a> {
fn clone(&self) -> UntrustedRlp<'a> {
UntrustedRlp {
bytes: self.bytes,
cache: Cell::new(OffsetCache::new(usize::max_value(), 0))
}
}
}
impl<'a, 'view> View<'a, 'view> for UntrustedRlp<'a> where 'a: 'view {
type Prototype = Result<Prototype, DecoderError>;
type PayloadInfo = Result<PayloadInfo, DecoderError>;
type Data = Result<&'a [u8], DecoderError>;
type Item = Result<UntrustedRlp<'a>, DecoderError>;
type Iter = UntrustedRlpIterator<'a, 'view>;
type Error = DecoderError;
//returns new instance of `UntrustedRlp`
fn new(bytes: &'a [u8]) -> UntrustedRlp<'a> {
@ -98,46 +109,235 @@ impl<'a, 'view> Reader<'a, 'view> for UntrustedRlp<'a> where 'a: 'view {
}
fn prototype(&self) -> Self::Prototype {
unimplemented!()
// optimize? && return appropriate errors
if self.is_data() {
Ok(Prototype::Data(self.size()))
} else if self.is_list() {
Ok(Prototype::List(self.item_count()))
} else {
Ok(Prototype::Null)
}
}
fn payload_info(&self) -> Self::PayloadInfo {
unimplemented!()
BasicDecoder::payload_info(self.bytes)
}
fn data(&'view self) -> Self::Data {
unimplemented!()
let pi = try!(BasicDecoder::payload_info(self.bytes));
Ok(&self.bytes[pi.header_len..(pi.header_len + pi.value_len)])
}
fn item_count(&self) -> usize {
unimplemented!()
match self.is_list() {
true => self.iter().count(),
false => 0
}
}
fn size(&self) -> usize {
unimplemented!()
match self.is_data() {
// we can safely unwrap (?) cause its data
true => BasicDecoder::payload_info(self.bytes).unwrap().value_len,
false => 0
}
}
fn at(&'view self, index: usize) -> Self::Item {
unimplemented!()
if !self.is_list() {
return Err(DecoderError::RlpExpectedToBeList);
}
// move to cached position if it's index is less or equal to
// current search index, otherwise move to beginning of list
let c = self.cache.get();
let (mut bytes, to_skip) = match c.index <= index {
true => (try!(UntrustedRlp::consume(self.bytes, c.offset)), index - c.index),
false => (try!(self.consume_list_prefix()), index),
};
// skip up to x items
bytes = try!(UntrustedRlp::consume_items(bytes, to_skip));
// update the cache
self.cache.set(OffsetCache::new(index, self.bytes.len() - bytes.len()));
// construct new rlp
let found = try!(BasicDecoder::payload_info(bytes));
Ok(UntrustedRlp::new(&bytes[0..found.header_len + found.value_len]))
}
fn is_null(&self) -> bool {
unimplemented!()
self.bytes.len() == 0
}
fn is_empty(&self) -> bool {
unimplemented!()
!self.is_null() && (self.bytes[0] == 0xc0 || self.bytes[0] == 0x80)
}
fn is_list(&self) -> bool {
unimplemented!()
!self.is_null() && self.bytes[0] >= 0xc0
}
fn is_data(&self) -> bool {
unimplemented!()
!self.is_null() && self.bytes[0] < 0xc0
}
fn is_int(&self) -> bool {
unimplemented!()
if self.is_null() {
return false;
}
match self.bytes[0] {
0...0x80 => true,
0x81...0xb7 => self.bytes[1] != 0,
b @ 0xb8...0xbf => self.bytes[1 + b as usize - 0xb7] != 0,
_ => false
}
}
fn iter(&'view self) -> Self::Iter {
self.into_iter()
}
fn as_val<T>(&self) -> Result<T, Self::Error> where T: Decodable {
// optimize, so it doesn't use clone (although This clone is cheap)
T::decode(&BasicDecoder::new(self.clone()))
}
}
impl<'a> UntrustedRlp<'a> {
/// consumes first found prefix
fn consume_list_prefix(&self) -> Result<&'a [u8], DecoderError> {
let item = try!(BasicDecoder::payload_info(self.bytes));
let bytes = try!(UntrustedRlp::consume(self.bytes, item.header_len));
Ok(bytes)
}
/// consumes fixed number of items
fn consume_items(bytes: &'a [u8], items: usize) -> Result<&'a [u8], DecoderError> {
let mut result = bytes;
for _ in 0..items {
let i = try!(BasicDecoder::payload_info(result));
result = try!(UntrustedRlp::consume(result, (i.header_len + i.value_len)));
}
Ok(result)
}
/// consumes slice prefix of length `len`
fn consume(bytes: &'a [u8], len: usize) -> Result<&'a [u8], DecoderError> {
match bytes.len() >= len {
true => Ok(&bytes[len..]),
false => Err(DecoderError::RlpIsTooShort),
}
}
}
/// Iterator over rlp-slice list elements.
pub struct UntrustedRlpIterator<'a, 'view> where 'a: 'view {
rlp: &'view UntrustedRlp<'a>,
index: usize,
}
impl<'a, 'view> IntoIterator for &'view UntrustedRlp<'a> where 'a: 'view {
type Item = UntrustedRlp<'a>;
type IntoIter = UntrustedRlpIterator<'a, 'view>;
fn into_iter(self) -> Self::IntoIter {
UntrustedRlpIterator {
rlp: self,
index: 0,
}
}
}
impl<'a, 'view> Iterator for UntrustedRlpIterator<'a, 'view> {
type Item = UntrustedRlp<'a>;
fn next(&mut self) -> Option<UntrustedRlp<'a>> {
let index = self.index;
let result = self.rlp.at(index).ok();
self.index += 1;
result
}
}
struct BasicDecoder<'a> {
rlp: UntrustedRlp<'a>
}
impl<'a> BasicDecoder<'a> {
pub fn new(rlp: UntrustedRlp<'a>) -> BasicDecoder<'a> {
BasicDecoder {
rlp: rlp
}
}
/// Return first item info
fn payload_info(bytes: &[u8]) -> Result<PayloadInfo, DecoderError> {
let item = match bytes.first().map(|&x| x) {
None => return Err(DecoderError::RlpIsTooShort),
Some(0...0x7f) => PayloadInfo::new(0, 1),
Some(l @ 0x80...0xb7) => PayloadInfo::new(1, l as usize - 0x80),
Some(l @ 0xb8...0xbf) => {
let len_of_len = l as usize - 0xb7;
let header_len = 1 + len_of_len;
let value_len = try!(usize::from_bytes(&bytes[1..header_len]));
PayloadInfo::new(header_len, value_len)
}
Some(l @ 0xc0...0xf7) => PayloadInfo::new(1, l as usize - 0xc0),
Some(l @ 0xf8...0xff) => {
let len_of_len = l as usize - 0xf7;
let header_len = 1 + len_of_len;
let value_len = try!(usize::from_bytes(&bytes[1..header_len]));
PayloadInfo::new(header_len, value_len)
},
// we cant reach this place, but rust requires _ to be implemented
_ => { panic!(); }
};
match item.header_len + item.value_len <= bytes.len() {
true => Ok(item),
false => Err(DecoderError::RlpIsTooShort),
}
}
}
impl<'a> Decoder for BasicDecoder<'a> {
type Error = DecoderError;
fn read_value<T, F>(&self, f: F) -> Result<T, Self::Error>
where F: FnOnce(&[u8]) -> Result<T, Self::Error> {
let bytes = self.rlp.raw();
match bytes.first().map(|&x| x) {
// rlp is too short
None => Err(DecoderError::RlpIsTooShort),
// single byt value
Some(l @ 0...0x7f) => Ok(try!(f(&[l]))),
// 0-55 bytes
Some(l @ 0x80...0xb7) => Ok(try!(f(&bytes[1..(1 + l as usize - 0x80)]))),
// longer than 55 bytes
Some(l @ 0xb8...0xbf) => {
let len_of_len = l as usize - 0xb7;
let begin_of_value = 1 as usize + len_of_len;
let len = try!(usize::from_bytes(&bytes[1..begin_of_value]));
Ok(try!(f(&bytes[begin_of_value..begin_of_value + len])))
}
// we are reading value, not a list!
_ => { unreachable!(); }
}
}
fn read_list<T, F>(&self, f: F) -> Result<T, Self::Error>
where F: FnOnce(&[Self]) -> Result<T, Self::Error> {
let v: Vec<BasicDecoder<'a>> = self.rlp.iter()
.map(| i | BasicDecoder::new(i))
.collect();
f(&v)
}
}