From 0eda699aa57df8fd527ea3f276f0ae91922ecd1e Mon Sep 17 00:00:00 2001 From: debris Date: Wed, 25 Nov 2015 12:46:27 +0100 Subject: [PATCH 01/26] rlp encoder --- src/rlp.rs | 156 +++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 153 insertions(+), 3 deletions(-) diff --git a/src/rlp.rs b/src/rlp.rs index a0fe455b5..f8422ed7e 100644 --- a/src/rlp.rs +++ b/src/rlp.rs @@ -2,8 +2,10 @@ use std::fmt; use std::cell::Cell; +use std::io::{Write, BufWriter}; +use std::io::Error as IoError; use std::error::Error as StdError; -use bytes::{FromBytes, FromBytesError}; +use bytes::{ToBytes, FromBytes, FromBytesError}; /// rlp container #[derive(Debug)] @@ -26,13 +28,13 @@ impl OffsetCache { } /// stores basic information about item -struct ItemInfo { +pub struct ItemInfo { prefix_len: usize, value_len: usize } impl ItemInfo { - fn new(prefix_len: usize, value_len: usize) -> ItemInfo { + pub fn new(prefix_len: usize, value_len: usize) -> ItemInfo { ItemInfo { prefix_len: prefix_len, value_len: value_len } } } @@ -189,6 +191,154 @@ impl <'a> Iterator for RlpIterator<'a> { } } +/// shortcut function to encode a `T: Encodable` into a Rlp `Vec` +pub fn encode(object: &E) -> Result, EncoderError> where E: Encodable { + let mut ret: Vec = vec![]; + { + let mut encoder = BasicEncoder::new(&mut ret); + try!(object.encode(&mut encoder)); + } + Ok(ret) +} + +#[derive(Debug)] +pub enum EncoderError { + IoError(IoError) +} + +impl StdError for EncoderError { + fn description(&self) -> &str { "encoder error" } +} + +impl fmt::Display for EncoderError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fmt::Debug::fmt(&self, f) + } +} + +impl From for EncoderError { + fn from(err: IoError) -> EncoderError { EncoderError::IoError(err) } +} + +pub trait Encodable { + fn encode(&self, encoder: &mut E) -> Result<(), E::Error> where E: Encoder; + fn item_info(&self) -> ItemInfo; +} + +pub trait Encoder { + type Error; + + fn emit_value(&mut self, value: &V) -> Result<(), Self::Error> where V: Encodable + ToBytes; + fn emit_array(&mut self, array: &[V]) -> Result<(), Self::Error> where V: Encodable; +} + +impl Encodable for T where T: ToBytes { + fn encode(&self, encoder: &mut E) -> Result<(), E::Error> where E: Encoder { + encoder.emit_value(self) + } + + fn item_info(&self) -> ItemInfo { + match self.to_bytes_len() { + // just 0 + 0 => ItemInfo::new(0, 1), + // byte is its own encoding + 1 if self.first_byte().unwrap() < 0x80 => ItemInfo::new(0, 1), + // (prefix + length), followed by the stirng + len @ 1...55 => ItemInfo::new(1, len), + // (prefix + length of length), followed by the length, followed by the value + len => ItemInfo::new(1 + len.to_bytes_len(), len) + } + } +} + +impl <'a, T> Encodable for &'a [T] where T: Encodable + 'a { + fn encode(&self, encoder: &mut E) -> Result<(), E::Error> where E: Encoder { + encoder.emit_array(self) + } + + fn item_info(&self) -> ItemInfo { + let prefix_len = match self.len() { + 0...55 => 1, + len => len.to_bytes_len() + }; + + let value_len = self.iter().fold(0, |acc, ref enc| { + let item = enc.item_info(); + acc + item.prefix_len + item.value_len + }); + + ItemInfo::new(prefix_len, value_len) + } +} + +impl Encodable for Vec where T: Encodable { + fn encode(&self, encoder: &mut E) -> Result<(), E::Error> where E: Encoder { + let r: &[T] = self.as_ref(); + r.encode(encoder) + } + + fn item_info(&self) -> ItemInfo { + let r: &[T] = self.as_ref(); + r.item_info() + } +} + +struct BasicEncoder where W: Write { + writer: BufWriter +} + +impl BasicEncoder where W: Write { + pub fn new(writer: W) -> BasicEncoder { + BasicEncoder { writer: BufWriter::new(writer) } + } +} + +impl Encoder for BasicEncoder where W: Write { + type Error = EncoderError; + + fn emit_value(&mut self, value: &V) -> Result<(), Self::Error> where V: Encodable + ToBytes { + let v = value.to_bytes(); + let bytes: &[u8] = v.as_ref(); + + match bytes.len() { + // just 0 + 0 => { try!(self.writer.write(&[0x80u8])); }, + // byte is its own encoding + 1 if bytes[0] < 0x80 => { try!(self.writer.write(bytes)); }, + // (prefix + length), followed by the string + len @ 1 ... 55 => { + try!(self.writer.write(&[0x80u8 + len as u8])); + try!(self.writer.write(bytes)); + } + // (prefix + length of length), followed by the length, followd by the string + len => { + try!(self.writer.write(&[0xb7 + len.to_bytes_len() as u8])); + try!(self.writer.write(&len.to_bytes())); + try!(self.writer.write(bytes)); + } + } + Ok(()) + } + + fn emit_array(&mut self, array: &[V]) -> Result<(), Self::Error> where V: Encodable { + let item = array.item_info(); + + match item.value_len { + len @ 0...55 => { try!(self.writer.write(&[0xc0u8 + len as u8])); } + len => { + try!(self.writer.write(&[0x7fu8 + len.to_bytes_len() as u8])); + try!(self.writer.write(&len.to_bytes())); + } + }; + + for el in array.iter() { + try!(el.encode(self)); + } + + Ok(()) + } +} + #[cfg(test)] mod tests { use rlp; From 6006f7cc38546b9e568f425fc71e5b01144e03ea Mon Sep 17 00:00:00 2001 From: debris Date: Wed, 25 Nov 2015 13:13:26 +0100 Subject: [PATCH 02/26] rlp encoding tests --- src/rlp.rs | 108 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 108 insertions(+) diff --git a/src/rlp.rs b/src/rlp.rs index f8422ed7e..c2e5c6ff4 100644 --- a/src/rlp.rs +++ b/src/rlp.rs @@ -403,5 +403,113 @@ mod tests { assert_eq!(cat_again.bytes, &[0x83, b'c', b'a', b't']); } } + + struct ETestPair(T, Vec) where T: rlp::Encodable; + + fn run_encode_tests(tests: Vec>) where T: rlp::Encodable { + for t in &tests { + let res = rlp::encode(&t.0).unwrap(); + assert_eq!(res, &t.1[..]); + } + } + + #[test] + fn encode_u8() { + let tests = vec![ + ETestPair(0u8, vec![0x80u8]), + ETestPair(15, vec![15]), + ETestPair(55, vec![55]), + ETestPair(56, vec![56]), + ETestPair(0x7f, vec![0x7f]), + ETestPair(0x80, vec![0x81, 0x80]), + ETestPair(0xff, vec![0x81, 0xff]), + ]; + run_encode_tests(tests); + } + + #[test] + fn encode_u16() { + let tests = vec![ + ETestPair(0u16, vec![0x80u8]), + ETestPair(0x100, vec![0x82, 0x01, 0x00]), + ETestPair(0xffff, vec![0x82, 0xff, 0xff]), + ]; + run_encode_tests(tests); + } + + #[test] + fn encode_u32() { + let tests = vec![ + ETestPair(0u32, vec![0x80u8]), + ETestPair(0x10000, vec![0x83, 0x01, 0x00, 0x00]), + ETestPair(0xffffff, vec![0x83, 0xff, 0xff, 0xff]), + ]; + run_encode_tests(tests); + } + + #[test] + fn encode_u64() { + let tests = vec![ + ETestPair(0u64, vec![0x80u8]), + ETestPair(0x1000000, vec![0x84, 0x01, 0x00, 0x00, 0x00]), + ETestPair(0xFFFFFFFF, vec![0x84, 0xff, 0xff, 0xff, 0xff]), + ]; + run_encode_tests(tests); + } + + #[test] + fn encode_str() { + let tests = vec![ + ETestPair("cat", vec![0x83, b'c', b'a', b't']), + ETestPair("dog", vec![0x83, b'd', b'o', b'g']), + ETestPair("Marek", vec![0x85, b'M', b'a', b'r', b'e', b'k']), + ETestPair("", vec![0x80]), + ETestPair("Lorem ipsum dolor sit amet, consectetur adipisicing elit", + vec![0xb8, 0x38, b'L', b'o', b'r', b'e', b'm', b' ', b'i', + b'p', b's', b'u', b'm', b' ', b'd', b'o', b'l', b'o', b'r', + b' ', b's', b'i', b't', b' ', b'a', b'm', b'e', b't', b',', + b' ', b'c', b'o', b'n', b's', b'e', b'c', b't', b'e', b't', + b'u', b'r', b' ', b'a', b'd', b'i', b'p', b'i', b's', b'i', + b'c', b'i', b'n', b'g', b' ', b'e', b'l', b'i', b't']) + ]; + run_encode_tests(tests); + } + + #[test] + fn encode_vector_u8() { + let tests = vec![ + ETestPair(vec![], vec![0xc0]), + ETestPair(vec![15u8], vec![0xc1, 0x0f]), + ETestPair(vec![1, 2, 3, 7, 0xff], vec![0xc6, 1, 2, 3, 7, 0x81, 0xff]), + ]; + run_encode_tests(tests); + } + + #[test] + fn encode_vector_u64() { + let tests = vec![ + ETestPair(vec![], vec![0xc0]), + ETestPair(vec![15u64], vec![0xc1, 0x0f]), + ETestPair(vec![1, 2, 3, 7, 0xff], vec![0xc6, 1, 2, 3, 7, 0x81, 0xff]), + ETestPair(vec![0xffffffff, 1, 2, 3, 7, 0xff], vec![0xcb, 0x84, 0xff, 0xff, 0xff, 0xff, 1, 2, 3, 7, 0x81, 0xff]), + ]; + run_encode_tests(tests); + } + + #[test] + fn encode_vector_str() { + let tests = vec![ + ETestPair(vec!["cat", "dog"], vec![0xc8, 0x83, b'c', b'a', b't', 0x83, b'd', b'o', b'g']) + ]; + run_encode_tests(tests); + } + + #[test] + fn encode_vector_of_vectors_str() { + let tests = vec![ + ETestPair(vec![vec!["cat"]], vec![0xc5, 0xc4, 0x83, b'c', b'a', b't']) + ]; + run_encode_tests(tests); + } } From 798b8b0fb884c4a94bd69fd614770da43470663a Mon Sep 17 00:00:00 2001 From: debris Date: Wed, 25 Nov 2015 17:54:50 +0100 Subject: [PATCH 03/26] rlp stream --- src/rlp.rs | 103 ++++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 95 insertions(+), 8 deletions(-) diff --git a/src/rlp.rs b/src/rlp.rs index c2e5c6ff4..2e8d52902 100644 --- a/src/rlp.rs +++ b/src/rlp.rs @@ -191,8 +191,86 @@ impl <'a> Iterator for RlpIterator<'a> { } } +/// container that should be used to encoding the rlp +pub struct RlpStream { + len: usize, + max_len: usize, + bytes: Vec, + last_err: Option +} + +impl RlpStream { + /// create new container of size `max_len` + pub fn new(max_len: usize) -> RlpStream { + RlpStream { + len: 0, + max_len: max_len, + bytes: vec![], + last_err: None + } + } + + /// apends value to the end of stream, chainable + pub fn append<'a, E>(&'a mut self, object: &E) -> &'a mut RlpStream where E: Encodable { + // if there was an error, stop appending + if !self.last_err.is_none() { + return self + } + + // encode given value and add it at the end of the stream + match encode(object) { + Err(e) => { + self.last_err = Some(e); + return self; + }, + Ok(ref mut v) => { + self.bytes.append(v); + self.len += 1; + }, + }; + + // if array is finished, prepend the length + if self.is_finished() { + self.prepend_the_length(); + } + + // allow chaining calls + self + } + + /// return try if stream is ready + pub fn is_finished(&self) -> bool { + self.len == self.max_len + } + + /// streams out encoded bytes + pub fn out(self) -> Result, EncoderError> { + match self.last_err { + None if self.is_finished() => Ok(self.bytes), + Some(e) => Err(e), + _ => Err(EncoderError::StreamIsUnfinished) + } + } + + /// prepend the length of the bytes to the beginning of the vector + fn prepend_the_length(&mut self) -> () { + let mut v = match self.bytes.len() { + len @ 0...55 => vec![0xc0u8 + len as u8], + len => { + let mut res = vec![0x7fu8 + len.to_bytes_len() as u8]; + let mut b = len.to_bytes(); + res.append(&mut b); + res + } + }; + + v.append(&mut self.bytes); + self.bytes = v; + } +} + /// shortcut function to encode a `T: Encodable` into a Rlp `Vec` -pub fn encode(object: &E) -> Result, EncoderError> where E: Encodable { +fn encode(object: &E) -> Result, EncoderError> where E: Encodable { let mut ret: Vec = vec![]; { let mut encoder = BasicEncoder::new(&mut ret); @@ -203,7 +281,8 @@ pub fn encode(object: &E) -> Result, EncoderError> where E: Encodable #[derive(Debug)] pub enum EncoderError { - IoError(IoError) + IoError(IoError), + StreamIsUnfinished } impl StdError for EncoderError { @@ -257,16 +336,16 @@ impl <'a, T> Encodable for &'a [T] where T: Encodable + 'a { } fn item_info(&self) -> ItemInfo { - let prefix_len = match self.len() { - 0...55 => 1, - len => len.to_bytes_len() - }; - let value_len = self.iter().fold(0, |acc, ref enc| { let item = enc.item_info(); acc + item.prefix_len + item.value_len }); + let prefix_len = match value_len { + 0...55 => 1, + len => len.to_bytes_len() + }; + ItemInfo::new(prefix_len, value_len) } } @@ -342,7 +421,7 @@ impl Encoder for BasicEncoder where W: Write { #[cfg(test)] mod tests { use rlp; - use rlp::Rlp; + use rlp::{Rlp, RlpStream}; #[test] fn rlp_at() { @@ -511,5 +590,13 @@ mod tests { ]; run_encode_tests(tests); } + + #[test] + fn rlp_stream() { + let mut stream = RlpStream::new(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']); + } } From 9f938fbaab03163c9369c5ab3be52a845efe9d4f Mon Sep 17 00:00:00 2001 From: debris Date: Wed, 25 Nov 2015 19:36:27 +0100 Subject: [PATCH 04/26] RlpStream array method --- src/rlp.rs | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/src/rlp.rs b/src/rlp.rs index 2e8d52902..aa3d08fe4 100644 --- a/src/rlp.rs +++ b/src/rlp.rs @@ -191,7 +191,7 @@ impl <'a> Iterator for RlpIterator<'a> { } } -/// container that should be used to encoding the rlp +/// container that should be used to encode rlp pub struct RlpStream { len: usize, max_len: usize, @@ -200,8 +200,14 @@ pub struct RlpStream { } impl RlpStream { - /// create new container of size `max_len` - pub fn new(max_len: usize) -> RlpStream { + /// create new container for values appended one after another, + /// but not being part of the same array + pub fn new() -> RlpStream { + RlpStream::array(0) + } + + /// create new container for array of size `max_len` + pub fn array(max_len: usize) -> RlpStream { RlpStream { len: 0, max_len: max_len, @@ -238,7 +244,7 @@ impl RlpStream { self } - /// return try if stream is ready + /// return true if stream is ready pub fn is_finished(&self) -> bool { self.len == self.max_len } @@ -593,7 +599,7 @@ mod tests { #[test] fn rlp_stream() { - let mut stream = RlpStream::new(2); + let mut stream = RlpStream::array(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']); From c5163b796fd344e04900604facf761dcd197b903 Mon Sep 17 00:00:00 2001 From: debris Date: Wed, 25 Nov 2015 21:04:43 +0100 Subject: [PATCH 05/26] improved encoder --- src/rlp.rs | 125 +++++++++++++++++++++++++---------------------------- 1 file changed, 58 insertions(+), 67 deletions(-) diff --git a/src/rlp.rs b/src/rlp.rs index aa3d08fe4..26a300db8 100644 --- a/src/rlp.rs +++ b/src/rlp.rs @@ -2,7 +2,7 @@ use std::fmt; use std::cell::Cell; -use std::io::{Write, BufWriter}; +use std::io::{Write}; use std::io::Error as IoError; use std::error::Error as StdError; use bytes::{ToBytes, FromBytes, FromBytesError}; @@ -28,7 +28,7 @@ impl OffsetCache { } /// stores basic information about item -pub struct ItemInfo { +struct ItemInfo { prefix_len: usize, value_len: usize } @@ -277,12 +277,9 @@ impl RlpStream { /// shortcut function to encode a `T: Encodable` into a Rlp `Vec` fn encode(object: &E) -> Result, EncoderError> where E: Encodable { - let mut ret: Vec = vec![]; - { - let mut encoder = BasicEncoder::new(&mut ret); - try!(object.encode(&mut encoder)); - } - Ok(ret) + let mut encoder = BasicEncoder::new(); + try!(object.encode(&mut encoder)); + Ok(encoder.out()) } #[derive(Debug)] @@ -307,7 +304,6 @@ impl From for EncoderError { pub trait Encodable { fn encode(&self, encoder: &mut E) -> Result<(), E::Error> where E: Encoder; - fn item_info(&self) -> ItemInfo; } pub trait Encoder { @@ -321,39 +317,12 @@ impl Encodable for T where T: ToBytes { fn encode(&self, encoder: &mut E) -> Result<(), E::Error> where E: Encoder { encoder.emit_value(self) } - - fn item_info(&self) -> ItemInfo { - match self.to_bytes_len() { - // just 0 - 0 => ItemInfo::new(0, 1), - // byte is its own encoding - 1 if self.first_byte().unwrap() < 0x80 => ItemInfo::new(0, 1), - // (prefix + length), followed by the stirng - len @ 1...55 => ItemInfo::new(1, len), - // (prefix + length of length), followed by the length, followed by the value - len => ItemInfo::new(1 + len.to_bytes_len(), len) - } - } } impl <'a, T> Encodable for &'a [T] where T: Encodable + 'a { fn encode(&self, encoder: &mut E) -> Result<(), E::Error> where E: Encoder { encoder.emit_array(self) } - - fn item_info(&self) -> ItemInfo { - let value_len = self.iter().fold(0, |acc, ref enc| { - let item = enc.item_info(); - acc + item.prefix_len + item.value_len - }); - - let prefix_len = match value_len { - 0...55 => 1, - len => len.to_bytes_len() - }; - - ItemInfo::new(prefix_len, value_len) - } } impl Encodable for Vec where T: Encodable { @@ -361,24 +330,46 @@ impl Encodable for Vec where T: Encodable { let r: &[T] = self.as_ref(); r.encode(encoder) } +} - fn item_info(&self) -> ItemInfo { - let r: &[T] = self.as_ref(); - r.item_info() +struct BasicEncoder { + bytes: Vec +} + +impl BasicEncoder { + fn new() -> BasicEncoder { + BasicEncoder { bytes: vec![] } + } + + /// inserts array prefix at given position + fn insert_array_len_at_pos(&mut self, len: usize, pos: usize) -> Result<(), EncoderError> { + // new bytes + let mut res: Vec = vec![]; + { + let (before_slice, after_slice) = self.bytes.split_at(pos); + try!(res.write(before_slice)); + + match len { + 0...55 => { try!(res.write(&[0xc0u8 + len as u8])); } + _ => { + try!(res.write(&[0x7fu8 + len.to_bytes_len() as u8])); + try!(res.write(&len.to_bytes())); + } + }; + + try!(res.write(after_slice)); + } + self.bytes = res; + Ok(()) + } + + /// get encoded value + fn out(self) -> Vec { + self.bytes } } -struct BasicEncoder where W: Write { - writer: BufWriter -} - -impl BasicEncoder where W: Write { - pub fn new(writer: W) -> BasicEncoder { - BasicEncoder { writer: BufWriter::new(writer) } - } -} - -impl Encoder for BasicEncoder where W: Write { +impl Encoder for BasicEncoder { type Error = EncoderError; fn emit_value(&mut self, value: &V) -> Result<(), Self::Error> where V: Encodable + ToBytes { @@ -387,40 +378,40 @@ impl Encoder for BasicEncoder where W: Write { match bytes.len() { // just 0 - 0 => { try!(self.writer.write(&[0x80u8])); }, + 0 => { try!(self.bytes.write(&[0x80u8])); }, // byte is its own encoding - 1 if bytes[0] < 0x80 => { try!(self.writer.write(bytes)); }, + 1 if bytes[0] < 0x80 => { try!(self.bytes.write(bytes)); }, // (prefix + length), followed by the string len @ 1 ... 55 => { - try!(self.writer.write(&[0x80u8 + len as u8])); - try!(self.writer.write(bytes)); + try!(self.bytes.write(&[0x80u8 + len as u8])); + try!(self.bytes.write(bytes)); } // (prefix + length of length), followed by the length, followd by the string len => { - try!(self.writer.write(&[0xb7 + len.to_bytes_len() as u8])); - try!(self.writer.write(&len.to_bytes())); - try!(self.writer.write(bytes)); + try!(self.bytes.write(&[0xb7 + len.to_bytes_len() as u8])); + try!(self.bytes.write(&len.to_bytes())); + try!(self.bytes.write(bytes)); } } Ok(()) } fn emit_array(&mut self, array: &[V]) -> Result<(), Self::Error> where V: Encodable { - let item = array.item_info(); - - match item.value_len { - len @ 0...55 => { try!(self.writer.write(&[0xc0u8 + len as u8])); } - len => { - try!(self.writer.write(&[0x7fu8 + len.to_bytes_len() as u8])); - try!(self.writer.write(&len.to_bytes())); - } - }; + // get len before inserting an array + let before_len = self.bytes.len(); + + // insert all array elements for el in array.iter() { try!(el.encode(self)); } - Ok(()) + // get len after inserting an array + let after_len = self.bytes.len(); + + // diff is array len + let array_len = after_len - before_len; + self.insert_array_len_at_pos(array_len, before_len) } } From c47bf0ce5f9fdfee20fbc9ccf4751215381619df Mon Sep 17 00:00:00 2001 From: debris Date: Wed, 25 Nov 2015 21:14:53 +0100 Subject: [PATCH 06/26] emit_value && emit_array do not have constrains regarding type --- src/rlp.rs | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/src/rlp.rs b/src/rlp.rs index 26a300db8..e751b9d56 100644 --- a/src/rlp.rs +++ b/src/rlp.rs @@ -309,19 +309,26 @@ pub trait Encodable { pub trait Encoder { type Error; - fn emit_value(&mut self, value: &V) -> Result<(), Self::Error> where V: Encodable + ToBytes; - fn emit_array(&mut self, array: &[V]) -> Result<(), Self::Error> where V: Encodable; + fn emit_value(&mut self, bytes: &[u8]) -> Result<(), Self::Error>; + fn emit_array(&mut self, f: F) -> Result<(), Self::Error> where + F: FnOnce(&mut Self) -> Result<(), Self::Error>; } impl Encodable for T where T: ToBytes { fn encode(&self, encoder: &mut E) -> Result<(), E::Error> where E: Encoder { - encoder.emit_value(self) + encoder.emit_value(&self.to_bytes()) } } impl <'a, T> Encodable for &'a [T] where T: Encodable + 'a { fn encode(&self, encoder: &mut E) -> Result<(), E::Error> where E: Encoder { - encoder.emit_array(self) + encoder.emit_array(|e| { + // insert all array elements + for el in self.iter() { + try!(el.encode(e)); + } + Ok(()) + }) } } @@ -372,10 +379,7 @@ impl BasicEncoder { impl Encoder for BasicEncoder { type Error = EncoderError; - fn emit_value(&mut self, value: &V) -> Result<(), Self::Error> where V: Encodable + ToBytes { - let v = value.to_bytes(); - let bytes: &[u8] = v.as_ref(); - + fn emit_value(&mut self, bytes: &[u8]) -> Result<(), Self::Error> { match bytes.len() { // just 0 0 => { try!(self.bytes.write(&[0x80u8])); }, @@ -396,15 +400,14 @@ impl Encoder for BasicEncoder { Ok(()) } - fn emit_array(&mut self, array: &[V]) -> Result<(), Self::Error> where V: Encodable { + fn emit_array(&mut self, f: F) -> Result<(), Self::Error> where + F: FnOnce(&mut Self) -> Result<(), Self::Error> { // get len before inserting an array let before_len = self.bytes.len(); // insert all array elements - for el in array.iter() { - try!(el.encode(self)); - } + try!(f(self)); // get len after inserting an array let after_len = self.bytes.len(); From 94ecd8c3dffdb173adbe87c431df2e57ce9dc455 Mon Sep 17 00:00:00 2001 From: debris Date: Wed, 25 Nov 2015 21:16:24 +0100 Subject: [PATCH 07/26] there is no need for item info new to be public --- src/rlp.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/rlp.rs b/src/rlp.rs index e751b9d56..452f71c57 100644 --- a/src/rlp.rs +++ b/src/rlp.rs @@ -34,7 +34,7 @@ struct ItemInfo { } impl ItemInfo { - pub fn new(prefix_len: usize, value_len: usize) -> ItemInfo { + fn new(prefix_len: usize, value_len: usize) -> ItemInfo { ItemInfo { prefix_len: prefix_len, value_len: value_len } } } From 93aeec19ec0694b0812581f2e3de543a3a4710fc Mon Sep 17 00:00:00 2001 From: debris Date: Wed, 25 Nov 2015 21:58:15 +0100 Subject: [PATCH 08/26] array -> list, RlpStream::array -> RlpStream::new_list --- src/rlp.rs | 56 +++++++++++++++++++++++++++--------------------------- 1 file changed, 28 insertions(+), 28 deletions(-) diff --git a/src/rlp.rs b/src/rlp.rs index 452f71c57..be67e4ace 100644 --- a/src/rlp.rs +++ b/src/rlp.rs @@ -43,7 +43,7 @@ impl ItemInfo { pub enum DecoderError { FromBytesError(FromBytesError), RlpIsTooShort, - RlpExpectedToBeArray, + RlpExpectedToBeList, BadRlp, } impl StdError for DecoderError { @@ -73,16 +73,16 @@ impl <'a>Rlp<'a> { /// /// paren container caches searched position pub fn at(&self, index: usize) -> Result, DecoderError> { - if !self.is_array() { - return Err(DecoderError::RlpExpectedToBeArray); + 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 array + // 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!(Rlp::consume(self.bytes, c.offset)), index - c.index), - false => (try!(self.consume_array_prefix()), index) + false => (try!(self.consume_list_prefix()), index) }; // skip up to x items @@ -96,8 +96,8 @@ impl <'a>Rlp<'a> { Ok(Rlp::new(&bytes[0..found.prefix_len + found.value_len])) } - /// returns true if rlp is an array - pub fn is_array(&self) -> bool { + /// returns true if rlp is an list + pub fn is_list(&self) -> bool { self.bytes.len() > 0 && self.bytes[0] >= 0xc0 } @@ -112,7 +112,7 @@ impl <'a>Rlp<'a> { } /// consumes first found prefix - fn consume_array_prefix(&self) -> Result<&'a [u8], DecoderError> { + fn consume_list_prefix(&self) -> Result<&'a [u8], DecoderError> { let item = try!(Rlp::item_info(self.bytes)); let bytes = try!(Rlp::consume(self.bytes, item.prefix_len)); Ok(bytes) @@ -201,13 +201,13 @@ pub struct RlpStream { impl RlpStream { /// create new container for values appended one after another, - /// but not being part of the same array + /// but not being part of the same list pub fn new() -> RlpStream { - RlpStream::array(0) + RlpStream::new_list(0) } - /// create new container for array of size `max_len` - pub fn array(max_len: usize) -> RlpStream { + /// create new container for list of size `max_len` + pub fn new_list(max_len: usize) -> RlpStream { RlpStream { len: 0, max_len: max_len, @@ -235,7 +235,7 @@ impl RlpStream { }, }; - // if array is finished, prepend the length + // if list is finished, prepend the length if self.is_finished() { self.prepend_the_length(); } @@ -310,7 +310,7 @@ pub trait Encoder { type Error; fn emit_value(&mut self, bytes: &[u8]) -> Result<(), Self::Error>; - fn emit_array(&mut self, f: F) -> Result<(), Self::Error> where + fn emit_list(&mut self, f: F) -> Result<(), Self::Error> where F: FnOnce(&mut Self) -> Result<(), Self::Error>; } @@ -322,8 +322,8 @@ impl Encodable for T where T: ToBytes { impl <'a, T> Encodable for &'a [T] where T: Encodable + 'a { fn encode(&self, encoder: &mut E) -> Result<(), E::Error> where E: Encoder { - encoder.emit_array(|e| { - // insert all array elements + encoder.emit_list(|e| { + // insert all list elements for el in self.iter() { try!(el.encode(e)); } @@ -348,8 +348,8 @@ impl BasicEncoder { BasicEncoder { bytes: vec![] } } - /// inserts array prefix at given position - fn insert_array_len_at_pos(&mut self, len: usize, pos: usize) -> Result<(), EncoderError> { + /// inserts list prefix at given position + fn insert_list_len_at_pos(&mut self, len: usize, pos: usize) -> Result<(), EncoderError> { // new bytes let mut res: Vec = vec![]; { @@ -400,21 +400,21 @@ impl Encoder for BasicEncoder { Ok(()) } - fn emit_array(&mut self, f: F) -> Result<(), Self::Error> where + fn emit_list(&mut self, f: F) -> Result<(), Self::Error> where F: FnOnce(&mut Self) -> Result<(), Self::Error> { - // get len before inserting an array + // get len before inserting an list let before_len = self.bytes.len(); - // insert all array elements + // insert all list elements try!(f(self)); - // get len after inserting an array + // get len after inserting an list let after_len = self.bytes.len(); - // diff is array len - let array_len = after_len - before_len; - self.insert_array_len_at_pos(array_len, before_len) + // diff is list len + let list_len = after_len - before_len; + self.insert_list_len_at_pos(list_len, before_len) } } @@ -428,7 +428,7 @@ mod tests { 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_array()); + assert!(rlp.is_list()); let cat = rlp.at(0).unwrap(); assert!(cat.is_value()); @@ -449,7 +449,7 @@ mod tests { let data = vec![0xc8, 0x83, b'c', b'a', b't', 0x83, b'd', b'o']; { let rlp = Rlp::new(&data); - assert!(rlp.is_array()); + assert!(rlp.is_list()); let cat_err = rlp.at(0).unwrap_err(); assert_eq!(cat_err, rlp::DecoderError::RlpIsTooShort); @@ -593,7 +593,7 @@ mod tests { #[test] fn rlp_stream() { - let mut stream = RlpStream::array(2); + 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']); From 9dff89427240e268677f7f8df133d3a90edec3f8 Mon Sep 17 00:00:00 2001 From: debris Date: Wed, 25 Nov 2015 22:13:57 +0100 Subject: [PATCH 09/26] do not use io::Write --- src/rlp.rs | 95 +++++++++++++++++++++++------------------------------- 1 file changed, 40 insertions(+), 55 deletions(-) diff --git a/src/rlp.rs b/src/rlp.rs index be67e4ace..4d146a30d 100644 --- a/src/rlp.rs +++ b/src/rlp.rs @@ -2,8 +2,6 @@ use std::fmt; use std::cell::Cell; -use std::io::{Write}; -use std::io::Error as IoError; use std::error::Error as StdError; use bytes::{ToBytes, FromBytes, FromBytesError}; @@ -224,16 +222,18 @@ impl RlpStream { } // encode given value and add it at the end of the stream - match encode(object) { - Err(e) => { - self.last_err = Some(e); - return self; - }, - Ok(ref mut v) => { - self.bytes.append(v); - self.len += 1; - }, - }; + self.bytes.extend(encode(object)); + self.len += 1; + + //Err(e) => { + //self.last_err = Some(e); + //return self; + //}, + //Ok(ref mut v) => { + //self.bytes.append(v); + //self.len += 1; + //}, + //}; // if list is finished, prepend the length if self.is_finished() { @@ -276,15 +276,14 @@ impl RlpStream { } /// shortcut function to encode a `T: Encodable` into a Rlp `Vec` -fn encode(object: &E) -> Result, EncoderError> where E: Encodable { +fn encode(object: &E) -> Vec where E: Encodable { let mut encoder = BasicEncoder::new(); - try!(object.encode(&mut encoder)); - Ok(encoder.out()) + object.encode(&mut encoder); + encoder.out() } #[derive(Debug)] pub enum EncoderError { - IoError(IoError), StreamIsUnfinished } @@ -298,42 +297,34 @@ impl fmt::Display for EncoderError { } } -impl From for EncoderError { - fn from(err: IoError) -> EncoderError { EncoderError::IoError(err) } -} - pub trait Encodable { - fn encode(&self, encoder: &mut E) -> Result<(), E::Error> where E: Encoder; + fn encode(&self, encoder: &mut E) -> () where E: Encoder; } pub trait Encoder { - type Error; - - fn emit_value(&mut self, bytes: &[u8]) -> Result<(), Self::Error>; - fn emit_list(&mut self, f: F) -> Result<(), Self::Error> where - F: FnOnce(&mut Self) -> Result<(), Self::Error>; + fn emit_value(&mut self, bytes: &[u8]) -> (); + fn emit_list(&mut self, f: F) -> () where F: FnOnce(&mut Self) -> (); } impl Encodable for T where T: ToBytes { - fn encode(&self, encoder: &mut E) -> Result<(), E::Error> where E: Encoder { + fn encode(&self, encoder: &mut E) -> () where E: Encoder { encoder.emit_value(&self.to_bytes()) } } impl <'a, T> Encodable for &'a [T] where T: Encodable + 'a { - fn encode(&self, encoder: &mut E) -> Result<(), E::Error> where E: Encoder { + fn encode(&self, encoder: &mut E) -> () where E: Encoder { encoder.emit_list(|e| { // insert all list elements for el in self.iter() { - try!(el.encode(e)); + el.encode(e); } - Ok(()) }) } } impl Encodable for Vec where T: Encodable { - fn encode(&self, encoder: &mut E) -> Result<(), E::Error> where E: Encoder { + fn encode(&self, encoder: &mut E) -> () where E: Encoder { let r: &[T] = self.as_ref(); r.encode(encoder) } @@ -349,25 +340,24 @@ impl BasicEncoder { } /// inserts list prefix at given position - fn insert_list_len_at_pos(&mut self, len: usize, pos: usize) -> Result<(), EncoderError> { + fn insert_list_len_at_pos(&mut self, len: usize, pos: usize) -> () { // new bytes let mut res: Vec = vec![]; { let (before_slice, after_slice) = self.bytes.split_at(pos); - try!(res.write(before_slice)); + res.extend(before_slice); match len { - 0...55 => { try!(res.write(&[0xc0u8 + len as u8])); } + 0...55 => res.push(0xc0u8 + len as u8), _ => { - try!(res.write(&[0x7fu8 + len.to_bytes_len() as u8])); - try!(res.write(&len.to_bytes())); + res.push(0x7fu8 + len.to_bytes_len() as u8); + res.extend(len.to_bytes()); } }; - try!(res.write(after_slice)); + res.extend(after_slice); } self.bytes = res; - Ok(()) } /// get encoded value @@ -377,44 +367,39 @@ impl BasicEncoder { } impl Encoder for BasicEncoder { - type Error = EncoderError; - - fn emit_value(&mut self, bytes: &[u8]) -> Result<(), Self::Error> { + fn emit_value(&mut self, bytes: &[u8]) -> () { match bytes.len() { // just 0 - 0 => { try!(self.bytes.write(&[0x80u8])); }, + 0 => self.bytes.push(0x80u8), // byte is its own encoding - 1 if bytes[0] < 0x80 => { try!(self.bytes.write(bytes)); }, + 1 if bytes[0] < 0x80 => self.bytes.extend(bytes), // (prefix + length), followed by the string len @ 1 ... 55 => { - try!(self.bytes.write(&[0x80u8 + len as u8])); - try!(self.bytes.write(bytes)); + self.bytes.push(0x80u8 + len as u8); + self.bytes.extend(bytes); } // (prefix + length of length), followed by the length, followd by the string len => { - try!(self.bytes.write(&[0xb7 + len.to_bytes_len() as u8])); - try!(self.bytes.write(&len.to_bytes())); - try!(self.bytes.write(bytes)); + self.bytes.push(0xb7 + len.to_bytes_len() as u8); + self.bytes.extend(len.to_bytes()); + self.bytes.extend(bytes); } } - Ok(()) } - fn emit_list(&mut self, f: F) -> Result<(), Self::Error> where - F: FnOnce(&mut Self) -> Result<(), Self::Error> { - + fn emit_list(&mut self, f: F) -> () where F: FnOnce(&mut Self) -> () { // get len before inserting an list let before_len = self.bytes.len(); // insert all list elements - try!(f(self)); + f(self); // get len after inserting an list let after_len = self.bytes.len(); // diff is list len let list_len = after_len - before_len; - self.insert_list_len_at_pos(list_len, before_len) + self.insert_list_len_at_pos(list_len, before_len); } } @@ -487,7 +472,7 @@ mod tests { fn run_encode_tests(tests: Vec>) where T: rlp::Encodable { for t in &tests { - let res = rlp::encode(&t.0).unwrap(); + let res = rlp::encode(&t.0); assert_eq!(res, &t.1[..]); } } From ebe7c09210e24bda53c7bc560326d505dd33ae4d Mon Sep 17 00:00:00 2001 From: debris Date: Wed, 25 Nov 2015 22:14:43 +0100 Subject: [PATCH 10/26] removed legacy comment --- src/rlp.rs | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/src/rlp.rs b/src/rlp.rs index 4d146a30d..48dbccc55 100644 --- a/src/rlp.rs +++ b/src/rlp.rs @@ -225,16 +225,6 @@ impl RlpStream { self.bytes.extend(encode(object)); self.len += 1; - //Err(e) => { - //self.last_err = Some(e); - //return self; - //}, - //Ok(ref mut v) => { - //self.bytes.append(v); - //self.len += 1; - //}, - //}; - // if list is finished, prepend the length if self.is_finished() { self.prepend_the_length(); From 1c2c8c4eb5dba77d91c6029c2954e0bad67a253d Mon Sep 17 00:00:00 2001 From: debris Date: Wed, 25 Nov 2015 22:16:50 +0100 Subject: [PATCH 11/26] removed last_err field from RlpStream --- src/rlp.rs | 18 +++++------------- 1 file changed, 5 insertions(+), 13 deletions(-) diff --git a/src/rlp.rs b/src/rlp.rs index 48dbccc55..bd5561635 100644 --- a/src/rlp.rs +++ b/src/rlp.rs @@ -193,8 +193,7 @@ impl <'a> Iterator for RlpIterator<'a> { pub struct RlpStream { len: usize, max_len: usize, - bytes: Vec, - last_err: Option + bytes: Vec } impl RlpStream { @@ -209,18 +208,12 @@ impl RlpStream { RlpStream { len: 0, max_len: max_len, - bytes: vec![], - last_err: None + bytes: vec![] } } /// apends value to the end of stream, chainable pub fn append<'a, E>(&'a mut self, object: &E) -> &'a mut RlpStream where E: Encodable { - // if there was an error, stop appending - if !self.last_err.is_none() { - return self - } - // encode given value and add it at the end of the stream self.bytes.extend(encode(object)); self.len += 1; @@ -241,10 +234,9 @@ impl RlpStream { /// streams out encoded bytes pub fn out(self) -> Result, EncoderError> { - match self.last_err { - None if self.is_finished() => Ok(self.bytes), - Some(e) => Err(e), - _ => Err(EncoderError::StreamIsUnfinished) + match self.is_finished() { + true => Ok(self.bytes), + false => Err(EncoderError::StreamIsUnfinished) } } From 20cadef4f085ec890f8758734298055887733063 Mon Sep 17 00:00:00 2001 From: debris Date: Wed, 25 Nov 2015 22:29:21 +0100 Subject: [PATCH 12/26] RlpStream uses BasicEncoder --- src/rlp.rs | 24 +++++++----------------- 1 file changed, 7 insertions(+), 17 deletions(-) diff --git a/src/rlp.rs b/src/rlp.rs index bd5561635..6161e5cca 100644 --- a/src/rlp.rs +++ b/src/rlp.rs @@ -193,7 +193,7 @@ impl <'a> Iterator for RlpIterator<'a> { pub struct RlpStream { len: usize, max_len: usize, - bytes: Vec + encoder: BasicEncoder } impl RlpStream { @@ -208,14 +208,14 @@ impl RlpStream { RlpStream { len: 0, max_len: max_len, - bytes: vec![] + encoder: BasicEncoder::new() } } /// apends value to the end of stream, chainable pub fn append<'a, E>(&'a mut self, object: &E) -> &'a mut RlpStream where E: Encodable { // encode given value and add it at the end of the stream - self.bytes.extend(encode(object)); + object.encode(&mut self.encoder); self.len += 1; // if list is finished, prepend the length @@ -235,30 +235,20 @@ impl RlpStream { /// streams out encoded bytes pub fn out(self) -> Result, EncoderError> { match self.is_finished() { - true => Ok(self.bytes), + true => Ok(self.encoder.out()), false => Err(EncoderError::StreamIsUnfinished) } } /// prepend the length of the bytes to the beginning of the vector fn prepend_the_length(&mut self) -> () { - let mut v = match self.bytes.len() { - len @ 0...55 => vec![0xc0u8 + len as u8], - len => { - let mut res = vec![0x7fu8 + len.to_bytes_len() as u8]; - let mut b = len.to_bytes(); - res.append(&mut b); - res - } - }; - - v.append(&mut self.bytes); - self.bytes = v; + let len = self.encoder.bytes.len(); + self.encoder.insert_list_len_at_pos(len, 0); } } /// shortcut function to encode a `T: Encodable` into a Rlp `Vec` -fn encode(object: &E) -> Vec where E: Encodable { +pub fn encode(object: &E) -> Vec where E: Encodable { let mut encoder = BasicEncoder::new(); object.encode(&mut encoder); encoder.out() From e40bb6d52c3e7e4324b87b2cc711271ccf9208f6 Mon Sep 17 00:00:00 2001 From: debris Date: Wed, 25 Nov 2015 23:40:01 +0100 Subject: [PATCH 13/26] rlp append_list --- src/rlp.rs | 90 +++++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 72 insertions(+), 18 deletions(-) diff --git a/src/rlp.rs b/src/rlp.rs index 6161e5cca..a085e2fc2 100644 --- a/src/rlp.rs +++ b/src/rlp.rs @@ -2,6 +2,7 @@ use std::fmt; use std::cell::Cell; +use std::collections::LinkedList; use std::error::Error as StdError; use bytes::{ToBytes, FromBytes, FromBytesError}; @@ -189,10 +190,26 @@ impl <'a> Iterator for RlpIterator<'a> { } } +#[derive(Debug)] +struct ListInfo { + position: usize, + current: usize, + max: usize +} + +impl ListInfo { + fn new(position: usize, max: usize) -> ListInfo { + ListInfo { + position: position, + current: 0, + max: max + } + } +} + /// container that should be used to encode rlp pub struct RlpStream { - len: usize, - max_len: usize, + unfinished_lists: LinkedList, encoder: BasicEncoder } @@ -200,36 +217,51 @@ impl RlpStream { /// create new container for values appended one after another, /// but not being part of the same list pub fn new() -> RlpStream { - RlpStream::new_list(0) + RlpStream { + unfinished_lists: LinkedList::new(), + encoder: BasicEncoder::new() + } } /// create new container for list of size `max_len` - pub fn new_list(max_len: usize) -> RlpStream { - RlpStream { - len: 0, - max_len: max_len, - encoder: BasicEncoder::new() - } + pub fn new_list(len: usize) -> RlpStream { + let mut stream = RlpStream::new(); + stream.append_list(len); + stream } /// apends value to the end of stream, chainable pub fn append<'a, E>(&'a mut self, object: &E) -> &'a mut RlpStream where E: Encodable { // encode given value and add it at the end of the stream object.encode(&mut self.encoder); - self.len += 1; // if list is finished, prepend the length - if self.is_finished() { - self.prepend_the_length(); + self.try_to_finish(); + + // return chainable self + self + } + + /// declare appending the list of given size + pub fn append_list<'a>(&'a mut self, len: usize) -> &'a mut RlpStream { + // push new list + let position = self.encoder.bytes.len(); + match len { + 0 => { + // we may finish, if the appended list len is equal 0 + self.encoder.insert_list_len_at_pos(0, position); + self.try_to_finish(); + }, + _ => self.unfinished_lists.push_back(ListInfo::new(position, len)) } - // allow chaining calls + // return chainable self self } /// return true if stream is ready pub fn is_finished(&self) -> bool { - self.len == self.max_len + self.unfinished_lists.back().is_none() } /// streams out encoded bytes @@ -240,10 +272,22 @@ impl RlpStream { } } - /// prepend the length of the bytes to the beginning of the vector - fn prepend_the_length(&mut self) -> () { - let len = self.encoder.bytes.len(); - self.encoder.insert_list_len_at_pos(len, 0); + /// try to finish lists + fn try_to_finish(&mut self) -> () { + let should_finish = match self.unfinished_lists.back_mut() { + None => false, + Some(ref mut x) => { + x.current += 1; + x.current == x.max + } + }; + + if should_finish { + let x = self.unfinished_lists.pop_back().unwrap(); + let len = self.encoder.bytes.len() - x.position; + self.encoder.insert_list_len_at_pos(len, x.position); + self.try_to_finish(); + } } } @@ -555,5 +599,15 @@ mod tests { let out = stream.out().unwrap(); assert_eq!(out, vec![0xc8, 0x83, b'c', b'a', b't', 0x83, b'd', b'o', b'g']); } + + #[test] + fn rlp_stream_list() { + let mut stream = RlpStream::new_list(3); + stream.append_list(0); + stream.append_list(1).append(&vec![] as &Vec); + 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]); + } } From 4748ed522196a66bc67f9a5a0163d7bd2def3065 Mon Sep 17 00:00:00 2001 From: debris Date: Thu, 26 Nov 2015 00:09:09 +0100 Subject: [PATCH 14/26] todos --- src/rlp.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/rlp.rs b/src/rlp.rs index a085e2fc2..3cb240734 100644 --- a/src/rlp.rs +++ b/src/rlp.rs @@ -243,6 +243,7 @@ impl RlpStream { } /// declare appending the list of given size + /// TODO: optimise insertion of empty list pub fn append_list<'a>(&'a mut self, len: usize) -> &'a mut RlpStream { // push new list let position = self.encoder.bytes.len(); @@ -356,6 +357,7 @@ impl BasicEncoder { } /// inserts list prefix at given position + /// TODO: optimise it, so it does not copy an array fn insert_list_len_at_pos(&mut self, len: usize, pos: usize) -> () { // new bytes let mut res: Vec = vec![]; From 15820887595077fb92350221b5e0a72e7caa510d Mon Sep 17 00:00:00 2001 From: debris Date: Thu, 26 Nov 2015 00:37:53 +0100 Subject: [PATCH 15/26] rlp encoding documentation --- src/rlp.rs | 43 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/src/rlp.rs b/src/rlp.rs index 3cb240734..e5ac25799 100644 --- a/src/rlp.rs +++ b/src/rlp.rs @@ -1,4 +1,47 @@ //! Rlp serialization module +//! +//! Types implementing `Endocable` and `Decodable` traits +//! can be easily coverted to and from rlp +//! +//! # Examples: +//! +//! ```rust +//! extern crate ethcore_util; +//! use ethcore_util::rlp::{RlpStream}; +//! +//! fn encode_value() { +//! // 1029 +//! let mut stream = RlpStream::new(); +//! stream.append(&1029u32); +//! let out = stream.out().unwrap(); +//! assert_eq!(out, vec![0x82, 0x04, 0x05]); +//! } +//! +//! fn encode_list() { +//! // [ "cat", "dog" ] +//! 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']); +//! } +//! +//! fn encode_list2() { +//! // [ [], [[]], [ [], [[]] ] ] +//! let mut stream = RlpStream::new_list(3); +//! stream.append_list(0); +//! 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 main() { +//! encode_value(); +//! encode_list(); +//! encode_list2(); +//! } +//! ``` +//! use std::fmt; use std::cell::Cell; From f5d2d7a2d409e8dbe726db6ed51451b347308a79 Mon Sep 17 00:00:00 2001 From: debris Date: Thu, 26 Nov 2015 01:22:33 +0100 Subject: [PATCH 16/26] benchmars. optimised inserting empty list --- benches/rlp.rs | 46 ++++++++++++++++++++++++++++++++++++++++++++++ src/rlp.rs | 3 +-- 2 files changed, 47 insertions(+), 2 deletions(-) create mode 100644 benches/rlp.rs diff --git a/benches/rlp.rs b/benches/rlp.rs new file mode 100644 index 000000000..20ddf25d4 --- /dev/null +++ b/benches/rlp.rs @@ -0,0 +1,46 @@ +//! benchmarking for rlp +//! should be started with: +//! ```bash +//! multirust run nightly cargo bench +//! ``` + +#![feature(test)] + +extern crate test; +extern crate ethcore_util; + +use test::Bencher; +use ethcore_util::rlp::{RlpStream}; + +#[bench] +fn bench_stream_value(b: &mut Bencher) { + b.iter( || { + //1029 + let mut stream = RlpStream::new(); + stream.append(&1029u32); + let _ = stream.out().unwrap(); + }); +} + +#[bench] +fn bench_stream_nested_empty_lists(b: &mut Bencher) { + b.iter( || { + // [ [], [[]], [ [], [[]] ] ] + let mut stream = RlpStream::new_list(3); + stream.append_list(0); + stream.append_list(1).append_list(0); + stream.append_list(2).append_list(0).append_list(1).append_list(0); + let _ = stream.out().unwrap(); + }); +} + +#[bench] +fn bench_stream_1000_empty_lists(b: &mut Bencher) { + b.iter( || { + let mut stream = RlpStream::new(); + for _ in 0..1000 { + stream.append_list(0); + } + let _ = stream.out().unwrap(); + }); +} diff --git a/src/rlp.rs b/src/rlp.rs index e5ac25799..f73417859 100644 --- a/src/rlp.rs +++ b/src/rlp.rs @@ -286,14 +286,13 @@ impl RlpStream { } /// declare appending the list of given size - /// TODO: optimise insertion of empty list pub fn append_list<'a>(&'a mut self, len: usize) -> &'a mut RlpStream { // push new list let position = self.encoder.bytes.len(); match len { 0 => { // we may finish, if the appended list len is equal 0 - self.encoder.insert_list_len_at_pos(0, position); + self.encoder.bytes.push(0xc0u8); self.try_to_finish(); }, _ => self.unfinished_lists.push_back(ListInfo::new(position, len)) From e90c07009ec32f5b05ab276f30bd1afcd20dce2a Mon Sep 17 00:00:00 2001 From: debris Date: Thu, 26 Nov 2015 01:26:32 +0100 Subject: [PATCH 17/26] fixed typos in comments --- src/rlp.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/rlp.rs b/src/rlp.rs index f73417859..a93bb14d3 100644 --- a/src/rlp.rs +++ b/src/rlp.rs @@ -138,7 +138,7 @@ impl <'a>Rlp<'a> { Ok(Rlp::new(&bytes[0..found.prefix_len + found.value_len])) } - /// returns true if rlp is an list + /// returns true if rlp is a list pub fn is_list(&self) -> bool { self.bytes.len() > 0 && self.bytes[0] >= 0xc0 } @@ -448,13 +448,13 @@ impl Encoder for BasicEncoder { } fn emit_list(&mut self, f: F) -> () where F: FnOnce(&mut Self) -> () { - // get len before inserting an list + // get len before inserting a list let before_len = self.bytes.len(); // insert all list elements f(self); - // get len after inserting an list + // get len after inserting a list let after_len = self.bytes.len(); // diff is list len From a20d92c03b29c0d9961d797d1dc2ddd18bcc7f5c Mon Sep 17 00:00:00 2001 From: debris Date: Thu, 26 Nov 2015 02:32:50 +0100 Subject: [PATCH 18/26] decoding rlp + tests --- src/rlp.rs | 174 ++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 172 insertions(+), 2 deletions(-) diff --git a/src/rlp.rs b/src/rlp.rs index a93bb14d3..12d94f4a1 100644 --- a/src/rlp.rs +++ b/src/rlp.rs @@ -86,6 +86,7 @@ pub enum DecoderError { FromBytesError(FromBytesError), RlpIsTooShort, RlpExpectedToBeList, + RlpExpectedToBeValue, BadRlp, } impl StdError for DecoderError { @@ -233,6 +234,61 @@ impl <'a> Iterator for RlpIterator<'a> { } } +/// shortcut function to decode a Rlp `&[u8]` into an object +pub fn decode(bytes: &[u8]) -> Result where T: Decodable { + let rlp = Rlp::new(bytes); + T::decode(&rlp) +} + +pub trait Decodable: Sized { + fn decode(rlp: &Rlp) -> Result; +} + +impl Decodable for T where T: FromBytes { + fn decode(rlp: &Rlp) -> Result { + match rlp.is_value() { + true => BasicDecoder::read_value(rlp.bytes), + false => Err(DecoderError::RlpExpectedToBeValue) + } + } +} + +impl Decodable for Vec where T: Decodable { + fn decode(rlp: &Rlp) -> Result { + match rlp.is_list() { + true => rlp.iter().map(|rlp| T::decode(&rlp)).collect(), + false => Err(DecoderError::RlpExpectedToBeValue) + } + } +} + +trait Decoder { + fn read_value(bytes: &[u8]) -> Result where T: FromBytes; +} + +struct BasicDecoder; + +impl Decoder for BasicDecoder { + fn read_value(bytes: &[u8]) -> Result where T: FromBytes { + match bytes.first().map(|&x| x) { + // rlp is too short + None => Err(DecoderError::RlpIsTooShort), + // single byt value + Some(l @ 0...0x7f) => Ok(try!(T::from_bytes(&[l]))), + // 0-55 bytes + Some(l @ 0x80...0xb7) => Ok(try!(T::from_bytes(&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!(T::from_bytes(&bytes[begin_of_value..begin_of_value + len]))) + }, + _ => Err(DecoderError::BadRlp) + } + } +} + #[derive(Debug)] struct ListInfo { position: usize, @@ -465,8 +521,9 @@ impl Encoder for BasicEncoder { #[cfg(test)] mod tests { + use std::{fmt, cmp}; use rlp; - use rlp::{Rlp, RlpStream}; + use rlp::{Rlp, RlpStream, Decodable}; #[test] fn rlp_at() { @@ -474,18 +531,23 @@ mod tests { { let rlp = Rlp::new(&data); assert!(rlp.is_list()); + let animals = as rlp::Decodable>::decode(&rlp).unwrap(); + assert_eq!(animals, vec!["cat".to_string(), "dog".to_string()]); let cat = rlp.at(0).unwrap(); assert!(cat.is_value()); assert_eq!(cat.bytes, &[0x83, b'c', b'a', b't']); + assert_eq!(String::decode(&cat).unwrap(), "cat".to_string()); let dog = rlp.at(1).unwrap(); assert!(dog.is_value()); assert_eq!(dog.bytes, &[0x83, b'd', b'o', b'g']); + assert_eq!(String::decode(&dog).unwrap(), "dog".to_string()); let cat_again = rlp.at(0).unwrap(); assert!(cat_again.is_value()); assert_eq!(cat_again.bytes, &[0x83, b'c', b'a', b't']); + assert_eq!(String::decode(&cat_again).unwrap(), "cat".to_string()); } } @@ -648,10 +710,118 @@ mod tests { fn rlp_stream_list() { let mut stream = RlpStream::new_list(3); stream.append_list(0); - stream.append_list(1).append(&vec![] as &Vec); + 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]); } + + struct DTestPair(T, Vec) where T: rlp::Decodable + fmt::Debug + cmp::Eq; + + fn run_decode_tests(tests: Vec>) where T: rlp::Decodable + fmt::Debug + cmp::Eq { + for t in &tests { + let res: T = rlp::decode(&t.1).unwrap(); + assert_eq!(res, t.0); + } + } + + #[test] + fn decode_u8() { + let tests = vec![ + DTestPair(0u8, vec![0u8]), + DTestPair(15, vec![15]), + DTestPair(55, vec![55]), + DTestPair(56, vec![56]), + DTestPair(0x7f, vec![0x7f]), + DTestPair(0x80, vec![0x81, 0x80]), + DTestPair(0xff, vec![0x81, 0xff]), + ]; + run_decode_tests(tests); + } + + #[test] + fn decode_u16() { + let tests = vec![ + DTestPair(0u16, vec![0u8]), + DTestPair(0x100, vec![0x82, 0x01, 0x00]), + DTestPair(0xffff, vec![0x82, 0xff, 0xff]), + ]; + run_decode_tests(tests); + } + + #[test] + fn decode_u32() { + let tests = vec![ + DTestPair(0u32, vec![0u8]), + DTestPair(0x10000, vec![0x83, 0x01, 0x00, 0x00]), + DTestPair(0xffffff, vec![0x83, 0xff, 0xff, 0xff]), + ]; + run_decode_tests(tests); + } + + #[test] + fn decode_u64() { + let tests = vec![ + DTestPair(0u64, vec![0u8]), + DTestPair(0x1000000, vec![0x84, 0x01, 0x00, 0x00, 0x00]), + DTestPair(0xFFFFFFFF, vec![0x84, 0xff, 0xff, 0xff, 0xff]), + ]; + run_decode_tests(tests); + } + + #[test] + fn decode_str() { + let tests = vec![ + DTestPair("cat".to_string(), vec![0x83, b'c', b'a', b't']), + DTestPair("dog".to_string(), vec![0x83, b'd', b'o', b'g']), + DTestPair("Marek".to_string(), vec![0x85, b'M', b'a', b'r', b'e', b'k']), + DTestPair("".to_string(), vec![0x80]), + DTestPair("Lorem ipsum dolor sit amet, consectetur adipisicing elit".to_string(), + vec![0xb8, 0x38, b'L', b'o', b'r', b'e', b'm', b' ', b'i', + b'p', b's', b'u', b'm', b' ', b'd', b'o', b'l', b'o', b'r', + b' ', b's', b'i', b't', b' ', b'a', b'm', b'e', b't', b',', + b' ', b'c', b'o', b'n', b's', b'e', b'c', b't', b'e', b't', + b'u', b'r', b' ', b'a', b'd', b'i', b'p', b'i', b's', b'i', + b'c', b'i', b'n', b'g', b' ', b'e', b'l', b'i', b't']) + ]; + run_decode_tests(tests); + } + + #[test] + fn decode_vector_u8() { + let tests = vec![ + DTestPair(vec![] as Vec, vec![0xc0]), + DTestPair(vec![15u8], vec![0xc1, 0x0f]), + DTestPair(vec![1u8, 2, 3, 7, 0xff], vec![0xc6, 1, 2, 3, 7, 0x81, 0xff]), + ]; + run_decode_tests(tests); + } + + #[test] + fn decode_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]), + ]; + run_decode_tests(tests); + } + + #[test] + fn decode_vector_str() { + let tests = vec![ + DTestPair(vec!["cat".to_string(), "dog".to_string()], vec![0xc8, 0x83, b'c', b'a', b't', 0x83, b'd', b'o', b'g']) + ]; + run_decode_tests(tests); + } + + #[test] + fn decode_vector_of_vectors_str() { + let tests = vec![ + DTestPair(vec![vec!["cat".to_string()]], vec![0xc5, 0xc4, 0x83, b'c', b'a', b't']) + ]; + run_decode_tests(tests); + } } From f0a6376a9effd4dbe6a0e06a8ba1c0e9eeb8ef41 Mon Sep 17 00:00:00 2001 From: debris Date: Thu, 26 Nov 2015 02:50:21 +0100 Subject: [PATCH 19/26] quick fixes --- benches/rlp.rs | 16 +++++++++++++++- src/rlp.rs | 2 +- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/benches/rlp.rs b/benches/rlp.rs index 20ddf25d4..10397db09 100644 --- a/benches/rlp.rs +++ b/benches/rlp.rs @@ -10,7 +10,8 @@ extern crate test; extern crate ethcore_util; use test::Bencher; -use ethcore_util::rlp::{RlpStream}; +use ethcore_util::rlp; +use ethcore_util::rlp::{RlpStream, Rlp, Decodable}; #[bench] fn bench_stream_value(b: &mut Bencher) { @@ -34,6 +35,19 @@ fn bench_stream_nested_empty_lists(b: &mut Bencher) { }); } +#[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 = Decodable::decode(&rlp.at(0).unwrap()).unwrap(); + let v1: Vec> = Decodable::decode(&rlp.at(1).unwrap()).unwrap(); + let v2a: Vec = Decodable::decode(&rlp.at(2).unwrap().at(0).unwrap()).unwrap(); + let v2b: Vec> = Decodable::decode(&rlp.at(2).unwrap().at(1).unwrap()).unwrap(); + }); +} + #[bench] fn bench_stream_1000_empty_lists(b: &mut Bencher) { b.iter( || { diff --git a/src/rlp.rs b/src/rlp.rs index 12d94f4a1..e9e175363 100644 --- a/src/rlp.rs +++ b/src/rlp.rs @@ -262,7 +262,7 @@ impl Decodable for Vec where T: Decodable { } } -trait Decoder { +pub trait Decoder { fn read_value(bytes: &[u8]) -> Result where T: FromBytes; } From 71d75765669a0eb21d10b7c0a12a0204cb5953ca Mon Sep 17 00:00:00 2001 From: debris Date: Thu, 26 Nov 2015 12:21:17 +0100 Subject: [PATCH 20/26] fixed return error type --- src/rlp.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/rlp.rs b/src/rlp.rs index e9e175363..cd83a8c7e 100644 --- a/src/rlp.rs +++ b/src/rlp.rs @@ -257,7 +257,7 @@ impl Decodable for Vec where T: Decodable { fn decode(rlp: &Rlp) -> Result { match rlp.is_list() { true => rlp.iter().map(|rlp| T::decode(&rlp)).collect(), - false => Err(DecoderError::RlpExpectedToBeValue) + false => Err(DecoderError::RlpExpectedToBeList) } } } From f95265d6aecfd1a74f567273d786da0735c6065e Mon Sep 17 00:00:00 2001 From: debris Date: Thu, 26 Nov 2015 13:42:42 +0100 Subject: [PATCH 21/26] uint256 --- src/lib.rs | 1 + src/uint.rs | 593 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 594 insertions(+) create mode 100644 src/uint.rs diff --git a/src/lib.rs b/src/lib.rs index 8a65c9873..ab8cac701 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -2,6 +2,7 @@ extern crate rustc_serialize; pub mod error; pub mod hash; +pub mod uint; pub mod bytes; pub mod rlp; diff --git a/src/uint.rs b/src/uint.rs new file mode 100644 index 000000000..149ff5efb --- /dev/null +++ b/src/uint.rs @@ -0,0 +1,593 @@ +// taken from Rust Bitcoin Library (https://github.com/apoelstra/rust-bitcoin) +// original author: Andrew Poelstra + +// Rust Bitcoin Library +// Written in 2014 by +// Andrew Poelstra +// +// To the extent possible under law, the author(s) have dedicated all +// copyright and related and neighboring rights to this software to +// the public domain worldwide. This software is distributed without +// any warranty. +// +// You should have received a copy of the CC0 Public Domain Dedication +// along with this software. +// If not, see . +// + +//! Big unsigned integer types +///! +///! Implementation of a various large-but-fixed sized unsigned integer types. +///! The functions here are designed to be fast. +///! + +use std::fmt; +use std::cmp::{Ord, PartialOrd, Ordering}; +use std::ops::*; +use std::str::FromStr; +use rustc_serialize::hex::{FromHex, FromHexError}; + +macro_rules! impl_map_from { + ($thing:ident, $from:ty, $to:ty) => { + impl From<$from> for $thing { + fn from(value: $from) -> $thing { + From::from(value as $to) + } + } + } +} + +macro_rules! impl_array_newtype { + ($thing:ident, $ty:ty, $len:expr) => { + impl $thing { + #[inline] + /// Converts the object to a raw pointer + pub fn as_ptr(&self) -> *const $ty { + let &$thing(ref dat) = self; + dat.as_ptr() + } + + #[inline] + /// Converts the object to a mutable raw pointer + pub fn as_mut_ptr(&mut self) -> *mut $ty { + let &mut $thing(ref mut dat) = self; + dat.as_mut_ptr() + } + + #[inline] + /// Returns the length of the object as an array + pub fn len(&self) -> usize { $len } + + #[inline] + /// Returns whether the object, as an array, is empty. Always false. + pub fn is_empty(&self) -> bool { false } + } + + impl<'a> From<&'a [$ty]> for $thing { + fn from(data: &'a [$ty]) -> $thing { + assert_eq!(data.len(), $len); + unsafe { + use std::intrinsics::copy_nonoverlapping; + use std::mem; + let mut ret: $thing = mem::uninitialized(); + copy_nonoverlapping(data.as_ptr(), + ret.as_mut_ptr(), + mem::size_of::<$thing>()); + ret + } + } + } + + impl Index for $thing { + type Output = $ty; + + #[inline] + fn index(&self, index: usize) -> &$ty { + let &$thing(ref dat) = self; + &dat[index] + } + } + + impl_index_newtype!($thing, $ty); + + impl PartialEq for $thing { + #[inline] + fn eq(&self, other: &$thing) -> bool { + &self[..] == &other[..] + } + } + + impl Eq for $thing {} + + impl Clone for $thing { + #[inline] + fn clone(&self) -> $thing { + $thing::from(&self[..]) + } + } + + impl Copy for $thing {} + } +} + +macro_rules! impl_index_newtype { + ($thing:ident, $ty:ty) => { + impl Index> for $thing { + type Output = [$ty]; + + #[inline] + fn index(&self, index: Range) -> &[$ty] { + &self.0[index] + } + } + + impl Index> for $thing { + type Output = [$ty]; + + #[inline] + fn index(&self, index: RangeTo) -> &[$ty] { + &self.0[index] + } + } + + impl Index> for $thing { + type Output = [$ty]; + + #[inline] + fn index(&self, index: RangeFrom) -> &[$ty] { + &self.0[index] + } + } + + impl Index for $thing { + type Output = [$ty]; + + #[inline] + fn index(&self, _: RangeFull) -> &[$ty] { + &self.0[..] + } + } + } +} + +macro_rules! construct_uint { + ($name:ident, $n_words:expr) => ( + /// Little-endian large integer type + pub struct $name(pub [u64; $n_words]); + impl_array_newtype!($name, u64, $n_words); + + impl $name { + /// Conversion to u32 + #[inline] + fn low_u32(&self) -> u32 { + let &$name(ref arr) = self; + arr[0] as u32 + } + + /// Return the least number of bits needed to represent the number + #[inline] + pub fn bits(&self) -> usize { + let &$name(ref arr) = self; + for i in 1..$n_words { + if arr[$n_words - i] > 0 { return (0x40 * ($n_words - i + 1)) - arr[$n_words - i].leading_zeros() as usize; } + } + 0x40 - arr[0].leading_zeros() as usize + } + + #[inline] + pub fn bit(&self, index: usize) -> bool { + let &$name(ref arr) = self; + arr[index / 64] & (1 << (index % 64)) != 0 + } + + /// Multiplication by u32 + fn mul_u32(self, other: u32) -> $name { + let $name(ref arr) = self; + let mut carry = [0u64; $n_words]; + let mut ret = [0u64; $n_words]; + for i in 0..$n_words { + let upper = other as u64 * (arr[i] >> 32); + let lower = other as u64 * (arr[i] & 0xFFFFFFFF); + if i < 3 { + carry[i + 1] += upper >> 32; + } + ret[i] = lower + (upper << 32); + } + $name(ret) + $name(carry) + } + } + + impl From for $name { + fn from(value: u64) -> $name { + let mut ret = [0; $n_words]; + ret[0] = value; + $name(ret) + } + } + + impl_map_from!($name, u8, u64); + impl_map_from!($name, u16, u64); + impl_map_from!($name, u32, u64); + + impl<'a> From<&'a [u8]> for $name { + fn from(bytes: &[u8]) -> $name { + assert!($n_words * 8 >= bytes.len()); + + let mut ret = [0; $n_words]; + for i in 0..bytes.len() { + let rev = bytes.len() - 1 - i; + let pos = rev / 8; + ret[pos] += (bytes[i] as u64) << (rev % 8) * 8; + } + $name(ret) + } + } + + impl FromStr for $name { + type Err = FromHexError; + + fn from_str(value: &str) -> Result<$name, Self::Err> { + println!("{}", value); + let bytes: &[u8] = &try!(value.from_hex()); + Ok(From::from(bytes)) + } + } + + impl Add<$name> for $name { + type Output = $name; + + fn add(self, other: $name) -> $name { + let $name(ref me) = self; + let $name(ref you) = other; + let mut ret = [0u64; $n_words]; + let mut carry = [0u64; $n_words]; + let mut b_carry = false; + for i in 0..$n_words { + ret[i] = me[i].wrapping_add(you[i]); + if i < $n_words - 1 && ret[i] < me[i] { + carry[i + 1] = 1; + b_carry = true; + } + } + if b_carry { $name(ret) + $name(carry) } else { $name(ret) } + } + } + + impl Sub<$name> for $name { + type Output = $name; + + #[inline] + fn sub(self, other: $name) -> $name { + self + !other + From::from(1u64) + } + } + + impl Mul<$name> for $name { + type Output = $name; + + fn mul(self, other: $name) -> $name { + let mut me = self; + // TODO: be more efficient about this + for i in 0..(2 * $n_words) { + me = (me + me.mul_u32((other >> (32 * i)).low_u32())) << (32 * i); + } + me + } + } + + impl Div<$name> for $name { + type Output = $name; + + fn div(self, other: $name) -> $name { + let mut sub_copy = self; + let mut shift_copy = other; + let mut ret = [0u64; $n_words]; + + let my_bits = self.bits(); + let your_bits = other.bits(); + + // Check for division by 0 + assert!(your_bits != 0); + + // Early return in case we are dividing by a larger number than us + if my_bits < your_bits { + return $name(ret); + } + + // Bitwise long division + let mut shift = my_bits - your_bits; + shift_copy = shift_copy << shift; + loop { + if sub_copy >= shift_copy { + ret[shift / 64] |= 1 << (shift % 64); + sub_copy = sub_copy - shift_copy; + } + shift_copy = shift_copy >> 1; + if shift == 0 { break; } + shift -= 1; + } + + $name(ret) + } + } + + impl BitAnd<$name> for $name { + type Output = $name; + + #[inline] + fn bitand(self, other: $name) -> $name { + let $name(ref arr1) = self; + let $name(ref arr2) = other; + let mut ret = [0u64; $n_words]; + for i in 0..$n_words { + ret[i] = arr1[i] & arr2[i]; + } + $name(ret) + } + } + + impl BitXor<$name> for $name { + type Output = $name; + + #[inline] + fn bitxor(self, other: $name) -> $name { + let $name(ref arr1) = self; + let $name(ref arr2) = other; + let mut ret = [0u64; $n_words]; + for i in 0..$n_words { + ret[i] = arr1[i] ^ arr2[i]; + } + $name(ret) + } + } + + impl BitOr<$name> for $name { + type Output = $name; + + #[inline] + fn bitor(self, other: $name) -> $name { + let $name(ref arr1) = self; + let $name(ref arr2) = other; + let mut ret = [0u64; $n_words]; + for i in 0..$n_words { + ret[i] = arr1[i] | arr2[i]; + } + $name(ret) + } + } + + impl Not for $name { + type Output = $name; + + #[inline] + fn not(self) -> $name { + let $name(ref arr) = self; + let mut ret = [0u64; $n_words]; + for i in 0..$n_words { + ret[i] = !arr[i]; + } + $name(ret) + } + } + + impl Shl for $name { + type Output = $name; + + fn shl(self, shift: usize) -> $name { + let $name(ref original) = self; + let mut ret = [0u64; $n_words]; + let word_shift = shift / 64; + let bit_shift = shift % 64; + for i in 0..$n_words { + // Shift + if bit_shift < 64 && i + word_shift < $n_words { + ret[i + word_shift] += original[i] << bit_shift; + } + // Carry + if bit_shift > 0 && i + word_shift + 1 < $n_words { + ret[i + word_shift + 1] += original[i] >> (64 - bit_shift); + } + } + $name(ret) + } + } + + impl Shr for $name { + type Output = $name; + + fn shr(self, shift: usize) -> $name { + let $name(ref original) = self; + let mut ret = [0u64; $n_words]; + let word_shift = shift / 64; + let bit_shift = shift % 64; + for i in word_shift..$n_words { + // Shift + ret[i - word_shift] += original[i] >> bit_shift; + // Carry + if bit_shift > 0 && i < $n_words - 1 { + ret[i - word_shift] += original[i + 1] << (64 - bit_shift); + } + } + $name(ret) + } + } + + impl Ord for $name { + fn cmp(&self, other: &$name) -> Ordering { + let &$name(ref me) = self; + let &$name(ref you) = other; + for i in 0..$n_words { + if me[$n_words - 1 - i] < you[$n_words - 1 - i] { return Ordering::Less; } + if me[$n_words - 1 - i] > you[$n_words - 1 - i] { return Ordering::Greater; } + } + Ordering::Equal + } + } + + impl PartialOrd for $name { + fn partial_cmp(&self, other: &$name) -> Option { + Some(self.cmp(other)) + } + } + + impl fmt::Debug for $name { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let &$name(ref data) = self; + try!(write!(f, "0x")); + for ch in data.iter().rev() { + try!(write!(f, "{:02x}", ch)); + } + Ok(()) + } + } + ); +} + +construct_uint!(U256, 4); +construct_uint!(U128, 2); + +impl From for U256 { + fn from(value: U128) -> U256 { + let U128(ref arr) = value; + let mut ret = [0; 4]; + ret[0] = arr[0]; + ret[1] = arr[1]; + U256(ret) + } +} + +#[cfg(test)] +mod tests { + use uint::U256; + use std::str::FromStr; + + #[test] + pub fn uint256_from() { + let e = U256([10, 0, 0, 0]); + + // test unsigned initialization + let ua = U256::from(10u8); + let ub = U256::from(10u16); + let uc = U256::from(10u32); + let ud = U256::from(10u64); + assert_eq!(e, ua); + assert_eq!(e, ub); + assert_eq!(e, uc); + assert_eq!(e, ud); + + // test initialization from bytes + let va = U256::from(&[10u8][..]); + assert_eq!(e, va); + + // more tests for initialization from bytes + assert_eq!(U256([0x1010, 0, 0, 0]), U256::from(&[0x10u8, 0x10][..])); + assert_eq!(U256([0x12f0, 0, 0, 0]), U256::from(&[0x12u8, 0xf0][..])); + assert_eq!(U256([0x12f0, 0, 0, 0]), U256::from(&[0, 0x12u8, 0xf0][..])); + assert_eq!(U256([0x12f0, 0 , 0, 0]), U256::from(&[0, 0, 0, 0, 0, 0, 0, 0x12u8, 0xf0][..])); + assert_eq!(U256([0x12f0, 1 , 0, 0]), U256::from(&[1, 0, 0, 0, 0, 0, 0, 0x12u8, 0xf0][..])); + assert_eq!(U256([0x12f0, 1 , 0x0910203040506077, 0x8090a0b0c0d0e0f0]), U256::from(&[ + 0x80, 0x90, 0xa0, 0xb0, 0xc0, 0xd0, 0xe0, 0xf0, + 0x09, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x77, + 0, 0, 0, 0, 0, 0, 0, 1, + 0, 0, 0, 0, 0, 0, 0x12u8, 0xf0][..])); + assert_eq!(U256([0x00192437100019fa, 0x243710, 0, 0]), U256::from(&[ + 0x24u8, 0x37, 0x10, + 0, 0x19, 0x24, 0x37, 0x10, 0, 0x19, 0xfa][..])); + + // test initializtion from string + let sa = U256::from_str("0a").unwrap(); + assert_eq!(e, sa); + assert_eq!(U256([0x1010, 0, 0, 0]), U256::from_str("1010").unwrap()); + assert_eq!(U256([0x12f0, 0, 0, 0]), U256::from_str("12f0").unwrap()); + assert_eq!(U256([0x12f0, 0, 0, 0]), U256::from_str("12f0").unwrap()); + assert_eq!(U256([0x12f0, 0 , 0, 0]), U256::from_str("0000000012f0").unwrap()); + assert_eq!(U256([0x12f0, 1 , 0, 0]), U256::from_str("0100000000000012f0").unwrap()); + assert_eq!(U256([0x12f0, 1 , 0x0910203040506077, 0x8090a0b0c0d0e0f0]), U256::from_str("8090a0b0c0d0e0f00910203040506077000000000000000100000000000012f0").unwrap()); + } + + #[test] + pub fn uint256_bits_test() { + assert_eq!(U256::from(255u64).bits(), 8); + assert_eq!(U256::from(256u64).bits(), 9); + assert_eq!(U256::from(300u64).bits(), 9); + assert_eq!(U256::from(60000u64).bits(), 16); + assert_eq!(U256::from(70000u64).bits(), 17); + + //// Try to read the following lines out loud quickly + let mut shl = U256::from(70000u64); + shl = shl << 100; + assert_eq!(shl.bits(), 117); + shl = shl << 100; + assert_eq!(shl.bits(), 217); + shl = shl << 100; + assert_eq!(shl.bits(), 0); + + //// Bit set check + assert!(!U256::from(10u8).bit(0)); + assert!(U256::from(10u8).bit(1)); + assert!(!U256::from(10u8).bit(2)); + assert!(U256::from(10u8).bit(3)); + assert!(!U256::from(10u8).bit(4)); + } + + #[test] + pub fn uint256_comp_test() { + let small = U256([10u64, 0, 0, 0]); + let big = U256([0x8C8C3EE70C644118u64, 0x0209E7378231E632, 0, 0]); + let bigger = U256([0x9C8C3EE70C644118u64, 0x0209E7378231E632, 0, 0]); + let biggest = U256([0x5C8C3EE70C644118u64, 0x0209E7378231E632, 0, 1]); + + assert!(small < big); + assert!(big < bigger); + assert!(bigger < biggest); + assert!(bigger <= biggest); + assert!(biggest <= biggest); + assert!(bigger >= big); + assert!(bigger >= small); + assert!(small <= small); + } + + #[test] + pub fn uint256_arithmetic_test() { + let init = U256::from(0xDEADBEEFDEADBEEFu64); + let copy = init; + + let add = init + copy; + assert_eq!(add, U256([0xBD5B7DDFBD5B7DDEu64, 1, 0, 0])); + // Bitshifts + let shl = add << 88; + assert_eq!(shl, U256([0u64, 0xDFBD5B7DDE000000, 0x1BD5B7D, 0])); + let shr = shl >> 40; + assert_eq!(shr, U256([0x7DDE000000000000u64, 0x0001BD5B7DDFBD5B, 0, 0])); + // Increment + let incr = shr + U256::from(1u64); + assert_eq!(incr, U256([0x7DDE000000000001u64, 0x0001BD5B7DDFBD5B, 0, 0])); + // Subtraction + let sub = incr - init; + assert_eq!(sub, U256([0x9F30411021524112u64, 0x0001BD5B7DDFBD5A, 0, 0])); + // Multiplication + let mult = sub.mul_u32(300); + assert_eq!(mult, U256([0x8C8C3EE70C644118u64, 0x0209E7378231E632, 0, 0])); + // Division + assert_eq!(U256::from(105u8) / U256::from(5u8), U256::from(21u8)); + let div = mult / U256::from(300u16); + assert_eq!(div, U256([0x9F30411021524112u64, 0x0001BD5B7DDFBD5A, 0, 0])); + //// TODO: bit inversion + } + + #[test] + pub fn uint256_extreme_bitshift_test() { + //// Shifting a u64 by 64 bits gives an undefined value, so make sure that + //// we're doing the Right Thing here + let init = U256::from(0xDEADBEEFDEADBEEFu64); + + assert_eq!(init << 64, U256([0, 0xDEADBEEFDEADBEEF, 0, 0])); + let add = (init << 64) + init; + assert_eq!(add, U256([0xDEADBEEFDEADBEEF, 0xDEADBEEFDEADBEEF, 0, 0])); + assert_eq!(add >> 0, U256([0xDEADBEEFDEADBEEF, 0xDEADBEEFDEADBEEF, 0, 0])); + assert_eq!(add << 0, U256([0xDEADBEEFDEADBEEF, 0xDEADBEEFDEADBEEF, 0, 0])); + assert_eq!(add >> 64, U256([0xDEADBEEFDEADBEEF, 0, 0, 0])); + assert_eq!(add << 64, U256([0, 0xDEADBEEFDEADBEEF, 0xDEADBEEFDEADBEEF, 0])); + } +} + From 4fcf044eddde2382ba18ceeac21076cdb37cecb9 Mon Sep 17 00:00:00 2001 From: debris Date: Thu, 26 Nov 2015 15:00:17 +0100 Subject: [PATCH 22/26] rlp encoding and decoding u256 --- src/bytes.rs | 35 +++++++++++++++++++++++++++++++++++ src/rlp.rs | 32 ++++++++++++++++++++++++++++++++ src/uint.rs | 18 ++++++++++++++++++ 3 files changed, 85 insertions(+) diff --git a/src/bytes.rs b/src/bytes.rs index 06735995f..52dad3cb9 100644 --- a/src/bytes.rs +++ b/src/bytes.rs @@ -8,6 +8,7 @@ use std::fmt; use std::error::Error as StdError; +use uint::{U128, U256}; /// TODO: optimise some conversations pub trait ToBytes { @@ -82,6 +83,26 @@ impl_map_to_bytes!(usize, u64); impl_map_to_bytes!(u16, u64); impl_map_to_bytes!(u32, u64); +macro_rules! impl_uint_to_bytes { + ($name: ident) => { + impl ToBytes for $name { + fn to_bytes(&self) -> Vec { + let mut res= vec![]; + let count = self.to_bytes_len(); + for i in 0..count { + let j = count - 1 - i; + res.push(self.byte(j)); + } + res + } + fn to_bytes_len(&self) -> usize { (self.bits() + 7) / 8 } + } + } +} + +impl_uint_to_bytes!(U256); +impl_uint_to_bytes!(U128); + #[derive(Debug, PartialEq, Eq)] pub enum FromBytesError { UnexpectedEnd @@ -101,6 +122,7 @@ pub type FromBytesResult = Result; /// implements "Sized", so the compiler can deducate the size /// of the return type +/// TODO: check size of bytes before conversation and return appropriate error pub trait FromBytes: Sized { fn from_bytes(bytes: &[u8]) -> FromBytesResult; } @@ -149,3 +171,16 @@ macro_rules! impl_map_from_bytes { impl_map_from_bytes!(usize, u64); impl_map_from_bytes!(u16, u64); impl_map_from_bytes!(u32, u64); + +macro_rules! impl_uint_from_bytes { + ($name: ident) => { + impl FromBytes for $name { + fn from_bytes(bytes: &[u8]) -> FromBytesResult<$name> { + Ok($name::from(bytes)) + } + } + } +} + +impl_uint_from_bytes!(U256); +impl_uint_from_bytes!(U128); diff --git a/src/rlp.rs b/src/rlp.rs index cd83a8c7e..03a10348c 100644 --- a/src/rlp.rs +++ b/src/rlp.rs @@ -522,8 +522,10 @@ impl Encoder for BasicEncoder { #[cfg(test)] mod tests { use std::{fmt, cmp}; + use std::str::FromStr; use rlp; use rlp::{Rlp, RlpStream, Decodable}; + use uint::U256; #[test] fn rlp_at() { @@ -643,6 +645,21 @@ mod tests { run_encode_tests(tests); } + #[test] + fn encode_u256() { + let tests = vec![ + ETestPair(U256::from(0u64), vec![0x80u8]), + ETestPair(U256::from(0x1000000u64), vec![0x84, 0x01, 0x00, 0x00, 0x00]), + ETestPair(U256::from(0xffffffffu64), vec![0x84, 0xff, 0xff, 0xff, 0xff]), + ETestPair(U256::from_str("8090a0b0c0d0e0f00910203040506077000000000000000100000000000012f0").unwrap(), + 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]) + ]; + run_encode_tests(tests); + } + #[test] fn encode_str() { let tests = vec![ @@ -769,6 +786,21 @@ mod tests { run_decode_tests(tests); } + #[test] + fn decode_u256() { + let tests = vec![ + DTestPair(U256::from(0u64), vec![0x80u8]), + DTestPair(U256::from(0x1000000u64), vec![0x84, 0x01, 0x00, 0x00, 0x00]), + DTestPair(U256::from(0xffffffffu64), vec![0x84, 0xff, 0xff, 0xff, 0xff]), + DTestPair(U256::from_str("8090a0b0c0d0e0f00910203040506077000000000000000100000000000012f0").unwrap(), + 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]) + ]; + run_decode_tests(tests); + } + #[test] fn decode_str() { let tests = vec![ diff --git a/src/uint.rs b/src/uint.rs index 149ff5efb..daba98b63 100644 --- a/src/uint.rs +++ b/src/uint.rs @@ -180,6 +180,12 @@ macro_rules! construct_uint { arr[index / 64] & (1 << (index % 64)) != 0 } + #[inline] + pub fn byte(&self, index: usize) -> u8 { + let &$name(ref arr) = self; + (arr[index / 8] >> ((index % 8)) * 8) as u8 + } + /// Multiplication by u32 fn mul_u32(self, other: u32) -> $name { let $name(ref arr) = self; @@ -507,6 +513,7 @@ mod tests { #[test] pub fn uint256_bits_test() { + assert_eq!(U256::from(0u64).bits(), 0); assert_eq!(U256::from(255u64).bits(), 8); assert_eq!(U256::from(256u64).bits(), 9); assert_eq!(U256::from(300u64).bits(), 9); @@ -523,11 +530,22 @@ mod tests { assert_eq!(shl.bits(), 0); //// Bit set check + //// 01010 assert!(!U256::from(10u8).bit(0)); assert!(U256::from(10u8).bit(1)); assert!(!U256::from(10u8).bit(2)); assert!(U256::from(10u8).bit(3)); assert!(!U256::from(10u8).bit(4)); + + //// byte check + assert_eq!(U256::from(10u8).byte(0), 10); + assert_eq!(U256::from(0xffu64).byte(0), 0xff); + assert_eq!(U256::from(0xffu64).byte(1), 0); + assert_eq!(U256::from(0x01ffu64).byte(0), 0xff); + assert_eq!(U256::from(0x01ffu64).byte(1), 0x1); + assert_eq!(U256([0u64, 0xfc, 0, 0]).byte(8), 0xfc); + assert_eq!(U256([0u64, 0, 0, u64::max_value()]).byte(31), 0xff); + assert_eq!(U256([0u64, 0, 0, (u64::max_value() >> 8) + 1]).byte(31), 0x01); } #[test] From 21a5d5418bdb9b3b8cc60149a801d300bf08e2e5 Mon Sep 17 00:00:00 2001 From: debris Date: Thu, 26 Nov 2015 15:43:52 +0100 Subject: [PATCH 23/26] added benchmarks and few optimisations for rlp encoding --- benches/rlp.rs | 50 ++++++++++++++++++++++++++++++++++++++++++-------- src/bytes.rs | 2 ++ src/uint.rs | 1 - 3 files changed, 44 insertions(+), 9 deletions(-) diff --git a/benches/rlp.rs b/benches/rlp.rs index 10397db09..8c1fa8d58 100644 --- a/benches/rlp.rs +++ b/benches/rlp.rs @@ -10,19 +10,53 @@ extern crate test; extern crate ethcore_util; use test::Bencher; -use ethcore_util::rlp; +use std::str::FromStr; use ethcore_util::rlp::{RlpStream, Rlp, Decodable}; +use ethcore_util::uint::U256; #[bench] -fn bench_stream_value(b: &mut Bencher) { +fn bench_stream_u64_value(b: &mut Bencher) { b.iter( || { //1029 let mut stream = RlpStream::new(); - stream.append(&1029u32); + stream.append(&1029u64); let _ = stream.out().unwrap(); }); } +#[bench] +fn bench_decode_u64_value(b: &mut Bencher) { + b.iter( || { + // 1029 + let data = vec![0x82, 0x04, 0x05]; + let rlp = Rlp::new(&data); + let _ = u64::decode(&rlp).unwrap(); + }); +} + +#[bench] +fn bench_stream_u256_value(b: &mut Bencher) { + b.iter( || { + //u256 + let mut stream = RlpStream::new(); + stream.append(&U256::from_str("8090a0b0c0d0e0f00910203040506077000000000000000100000000000012f0").unwrap()); + let _ = stream.out().unwrap(); + }); +} + +#[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::decode(&rlp).unwrap(); + }); +} + #[bench] fn bench_stream_nested_empty_lists(b: &mut Bencher) { b.iter( || { @@ -41,17 +75,17 @@ fn bench_decode_nested_empty_lists(b: &mut Bencher) { // [ [], [[]], [ [], [[]] ] ] let data = vec![0xc7, 0xc0, 0xc1, 0xc0, 0xc3, 0xc0, 0xc1, 0xc0]; let rlp = Rlp::new(&data); - let v0: Vec = Decodable::decode(&rlp.at(0).unwrap()).unwrap(); - let v1: Vec> = Decodable::decode(&rlp.at(1).unwrap()).unwrap(); - let v2a: Vec = Decodable::decode(&rlp.at(2).unwrap().at(0).unwrap()).unwrap(); - let v2b: Vec> = Decodable::decode(&rlp.at(2).unwrap().at(1).unwrap()).unwrap(); + let _v0: Vec = Decodable::decode(&rlp.at(0).unwrap()).unwrap(); + let _v1: Vec> = Decodable::decode(&rlp.at(1).unwrap()).unwrap(); + let _v2a: Vec = Decodable::decode(&rlp.at(2).unwrap().at(0).unwrap()).unwrap(); + let _v2b: Vec> = Decodable::decode(&rlp.at(2).unwrap().at(1).unwrap()).unwrap(); }); } #[bench] fn bench_stream_1000_empty_lists(b: &mut Bencher) { b.iter( || { - let mut stream = RlpStream::new(); + let mut stream = RlpStream::new_list(1000); for _ in 0..1000 { stream.append_list(0); } diff --git a/src/bytes.rs b/src/bytes.rs index 52dad3cb9..1b331cf15 100644 --- a/src/bytes.rs +++ b/src/bytes.rs @@ -60,6 +60,7 @@ impl ToBytes for u64 { fn to_bytes(&self) -> Vec { let mut res= vec![]; let count = self.to_bytes_len(); + res.reserve(count); for i in 0..count { let j = count - 1 - i; res.push((*self >> (j * 8)) as u8); @@ -89,6 +90,7 @@ macro_rules! impl_uint_to_bytes { fn to_bytes(&self) -> Vec { let mut res= vec![]; let count = self.to_bytes_len(); + res.reserve(count); for i in 0..count { let j = count - 1 - i; res.push(self.byte(j)); diff --git a/src/uint.rs b/src/uint.rs index daba98b63..bc333631b 100644 --- a/src/uint.rs +++ b/src/uint.rs @@ -233,7 +233,6 @@ macro_rules! construct_uint { type Err = FromHexError; fn from_str(value: &str) -> Result<$name, Self::Err> { - println!("{}", value); let bytes: &[u8] = &try!(value.from_hex()); Ok(From::from(bytes)) } From d7dc1e5f6f792a1d5692a01ecaa8279d3bbb0160 Mon Sep 17 00:00:00 2001 From: debris Date: Thu, 26 Nov 2015 16:15:57 +0100 Subject: [PATCH 24/26] fixes in benchmars --- benches/rlp.rs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/benches/rlp.rs b/benches/rlp.rs index 8c1fa8d58..73af76bbe 100644 --- a/benches/rlp.rs +++ b/benches/rlp.rs @@ -19,7 +19,7 @@ fn bench_stream_u64_value(b: &mut Bencher) { b.iter( || { //1029 let mut stream = RlpStream::new(); - stream.append(&1029u64); + stream.append(&0x1023456789abcdefu64); let _ = stream.out().unwrap(); }); } @@ -28,7 +28,7 @@ fn bench_stream_u64_value(b: &mut Bencher) { fn bench_decode_u64_value(b: &mut Bencher) { b.iter( || { // 1029 - let data = vec![0x82, 0x04, 0x05]; + let data = vec![0x88, 0x10, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef]; let rlp = Rlp::new(&data); let _ = u64::decode(&rlp).unwrap(); }); @@ -77,8 +77,9 @@ fn bench_decode_nested_empty_lists(b: &mut Bencher) { let rlp = Rlp::new(&data); let _v0: Vec = Decodable::decode(&rlp.at(0).unwrap()).unwrap(); let _v1: Vec> = Decodable::decode(&rlp.at(1).unwrap()).unwrap(); - let _v2a: Vec = Decodable::decode(&rlp.at(2).unwrap().at(0).unwrap()).unwrap(); - let _v2b: Vec> = Decodable::decode(&rlp.at(2).unwrap().at(1).unwrap()).unwrap(); + let nested_rlp = rlp.at(2).unwrap(); + let _v2a: Vec = Decodable::decode(&nested_rlp.at(0).unwrap()).unwrap(); + let _v2b: Vec> = Decodable::decode(&nested_rlp.at(1).unwrap()).unwrap(); }); } From 716c907dc2cd5c1289a60889c28d778464cd9fa8 Mon Sep 17 00:00:00 2001 From: debris Date: Thu, 26 Nov 2015 18:36:28 +0100 Subject: [PATCH 25/26] when rewriting the buffer, reserve enougth space --- src/rlp.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/rlp.rs b/src/rlp.rs index 03a10348c..3e29b783b 100644 --- a/src/rlp.rs +++ b/src/rlp.rs @@ -459,6 +459,8 @@ impl BasicEncoder { fn insert_list_len_at_pos(&mut self, len: usize, pos: usize) -> () { // new bytes let mut res: Vec = vec![]; + // reserve a space equal at least current space + space for length + res.reserve(self.bytes.len() + 1); { let (before_slice, after_slice) = self.bytes.split_at(pos); res.extend(before_slice); From 0b9620f3ec6580150501e9e93da66f3689264643 Mon Sep 17 00:00:00 2001 From: debris Date: Thu, 26 Nov 2015 19:09:14 +0100 Subject: [PATCH 26/26] rlp uses insert_slice --- src/lib.rs | 1 + src/rlp.rs | 30 +++++++++++------------------- src/vector.rs | 34 ++++++++++++++++++++++++++++++++++ 3 files changed, 46 insertions(+), 19 deletions(-) create mode 100644 src/vector.rs diff --git a/src/lib.rs b/src/lib.rs index ab8cac701..863f5d74c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -5,6 +5,7 @@ pub mod hash; pub mod uint; pub mod bytes; pub mod rlp; +pub mod vector; #[test] fn it_works() { diff --git a/src/rlp.rs b/src/rlp.rs index 3e29b783b..f70062457 100644 --- a/src/rlp.rs +++ b/src/rlp.rs @@ -48,6 +48,7 @@ use std::cell::Cell; use std::collections::LinkedList; use std::error::Error as StdError; use bytes::{ToBytes, FromBytes, FromBytesError}; +use vector::InsertSlice; /// rlp container #[derive(Debug)] @@ -455,27 +456,18 @@ impl BasicEncoder { } /// inserts list prefix at given position - /// TODO: optimise it, so it does not copy an array + /// TODO: optimise it further? fn insert_list_len_at_pos(&mut self, len: usize, pos: usize) -> () { - // new bytes - let mut res: Vec = vec![]; - // reserve a space equal at least current space + space for length - res.reserve(self.bytes.len() + 1); - { - let (before_slice, after_slice) = self.bytes.split_at(pos); - res.extend(before_slice); + let mut res = vec![]; + match len { + 0...55 => res.push(0xc0u8 + len as u8), + _ => { + res.push(0x7fu8 + len.to_bytes_len() as u8); + res.extend(len.to_bytes()); + } + }; - match len { - 0...55 => res.push(0xc0u8 + len as u8), - _ => { - res.push(0x7fu8 + len.to_bytes_len() as u8); - res.extend(len.to_bytes()); - } - }; - - res.extend(after_slice); - } - self.bytes = res; + self.bytes.insert_slice(pos, &res); } /// get encoded value diff --git a/src/vector.rs b/src/vector.rs new file mode 100644 index 000000000..ce891beba --- /dev/null +++ b/src/vector.rs @@ -0,0 +1,34 @@ + +use std::ptr; + +pub trait InsertSlice { + fn insert_slice(&mut self, index: usize, elements: &[T]); +} + +/// based on `insert` function implementation from standard library +impl InsertSlice for Vec { + fn insert_slice(&mut self, index: usize, elements: &[T]) { + let e_len = elements.len(); + if e_len == 0 { + return; + } + + let len = self.len(); + assert!(index <= len); + + // space for the new element + self.reserve(e_len); + + unsafe { + { + let p = self.as_mut_ptr().offset(index as isize); + let ep = elements.as_ptr().offset(0); + // shift everything by e_len, to make space + ptr::copy(p, p.offset(e_len as isize), len - index); + // write new element + ptr::copy(ep, p, e_len); + } + self.set_len(len + e_len); + } + } +}