From 7e287755ca491bde2c9a27bb91c2bc43f64c1c4a Mon Sep 17 00:00:00 2001 From: debris Date: Mon, 7 Dec 2015 23:47:26 +0100 Subject: [PATCH] rlp view interface + refactor --- src/rlp/faces.rs | 179 +++++++++++++++++++++++++++++- src/rlp/mod.rs | 1 + src/rlp/rlp.rs | 83 +++++++++++--- src/rlp/untrusted_rlp.rs | 228 ++++++++++++++++++++++++++++++++++++--- 4 files changed, 462 insertions(+), 29 deletions(-) diff --git a/src/rlp/faces.rs b/src/rlp/faces.rs index 8ebe962c5..69e39b06d 100644 --- a/src/rlp/faces.rs +++ b/src/rlp/faces.rs @@ -1,23 +1,198 @@ -pub trait Reader<'a, 'view>: Sized { +pub trait Decoder { + type Error; + + fn read_value(&self, f: F) -> Result + where F: FnOnce(&[u8]) -> Result; + + fn read_list(&self, f: F) -> Result + where F: FnOnce(&[Self]) -> Result; +} + +pub trait Decodable: Sized { + fn decode(decoder: &D) -> Result 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 = rlp.iter().map(| i | String::decode(&i)).collect(); + /// } + /// ``` + fn iter(&'view self) -> Self::Iter; + + fn as_val(&self) -> Result where T: Decodable; } -pub trait Stream { +pub trait Encoder { + fn emit_value(&mut self, bytes: &[u8]) -> (); + fn emit_list(&mut self, f: F) -> () where F: FnOnce(&mut Self) -> (); +} + +pub trait Encodable { + fn encode(&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; } diff --git a/src/rlp/mod.rs b/src/rlp/mod.rs index 98e73665f..af6da14a2 100644 --- a/src/rlp/mod.rs +++ b/src/rlp/mod.rs @@ -1,6 +1,7 @@ pub mod old; pub mod faces; +pub mod coders; pub mod rlp; pub mod untrusted_rlp; diff --git a/src/rlp/rlp.rs b/src/rlp/rlp.rs index 603ba425d..54807bfda 100644 --- a/src/rlp/rlp.rs +++ b/src/rlp/rlp.rs @@ -1,19 +1,28 @@ -use super::faces::Reader; +use super::faces::{View, Decodable}; use super::untrusted_rlp::*; +impl<'a> From> 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(&self) -> Result where T: Decodable { + self.rlp.as_val() + } +} + +impl <'a, 'view> Rlp<'a> where 'a: 'view { + fn reader_as_val(r: &R) -> T where R: View<'a, 'view>, T: Decodable { + let res: Result = r.as_val(); + res.unwrap_or_else(|_| panic!()) + } + + pub fn as_val(&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> { + let index = self.index; + let result = self.rlp.rlp.at(index).ok().map(| iter | { From::from(iter) }); + self.index += 1; + result } } diff --git a/src/rlp/untrusted_rlp.rs b/src/rlp/untrusted_rlp.rs index 8d875324e..910696565 100644 --- a/src/rlp/untrusted_rlp.rs +++ b/src/rlp/untrusted_rlp.rs @@ -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, } -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; type PayloadInfo = Result; type Data = Result<&'a [u8], DecoderError>; type Item = Result, 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(&self) -> Result 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> { + 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 { + 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(&self, f: F) -> Result + where F: FnOnce(&[u8]) -> Result { + + 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(&self, f: F) -> Result + where F: FnOnce(&[Self]) -> Result { + + let v: Vec> = self.rlp.iter() + .map(| i | BasicDecoder::new(i)) + .collect(); + f(&v) + } +} +