From 90a3ada499a8d84009975e57e23ad03917d062ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Fri, 2 Feb 2018 13:42:25 +0100 Subject: [PATCH] Stack-based allocation for serialization. --- ethbloom/src/lib.rs | 30 ++++++++++++++++-------------- ethereum-types/src/hash.rs | 3 ++- ethereum-types/src/uint.rs | 3 ++- serialize/src/lib.rs | 36 ++++++++++++++++++++---------------- 4 files changed, 40 insertions(+), 32 deletions(-) diff --git a/ethbloom/src/lib.rs b/ethbloom/src/lib.rs index 71caf86..2991a87 100644 --- a/ethbloom/src/lib.rs +++ b/ethbloom/src/lib.rs @@ -52,8 +52,9 @@ use tiny_keccak::keccak256; // 3 according to yellowpaper const BLOOM_BITS: u32 = 3; +const BLOOM_SIZE: usize = 256; -construct_hash!(Bloom, 256); +construct_hash!(Bloom, BLOOM_SIZE); /// Returns log2. fn log2(x: usize) -> u32 { @@ -175,20 +176,20 @@ impl Bloom { pub fn accrue_bloom<'a, B>(&mut self, bloom: B) where BloomRef<'a>: From { let bloom_ref: BloomRef = bloom.into(); - assert_eq!(self.0.len(), 256); - assert_eq!(bloom_ref.0.len(), 256); - for i in 0..256 { + assert_eq!(self.0.len(), BLOOM_SIZE); + assert_eq!(bloom_ref.0.len(), BLOOM_SIZE); + for i in 0..BLOOM_SIZE { self.0[i] |= bloom_ref.0[i]; } } - pub fn data(&self) -> &[u8; 256] { + pub fn data(&self) -> &[u8; BLOOM_SIZE] { &self.0 } } #[derive(Clone, Copy)] -pub struct BloomRef<'a>(&'a [u8; 256]); +pub struct BloomRef<'a>(&'a [u8; BLOOM_SIZE]); impl<'a> BloomRef<'a> { pub fn is_empty(&self) -> bool { @@ -202,9 +203,9 @@ impl<'a> BloomRef<'a> { pub fn contains_bloom<'b, B>(&self, bloom: B) -> bool where BloomRef<'b>: From { let bloom_ref: BloomRef = bloom.into(); - assert_eq!(self.0.len(), 256); - assert_eq!(bloom_ref.0.len(), 256); - for i in 0..256 { + assert_eq!(self.0.len(), BLOOM_SIZE); + assert_eq!(bloom_ref.0.len(), BLOOM_SIZE); + for i in 0..BLOOM_SIZE { let a = self.0[i]; let b = bloom_ref.0[i]; if (a & b) != b { @@ -214,13 +215,13 @@ impl<'a> BloomRef<'a> { true } - pub fn data(&self) -> &'a [u8; 256] { + pub fn data(&self) -> &'a [u8; BLOOM_SIZE] { self.0 } } -impl<'a> From<&'a [u8; 256]> for BloomRef<'a> { - fn from(data: &'a [u8; 256]) -> Self { +impl<'a> From<&'a [u8; BLOOM_SIZE]> for BloomRef<'a> { + fn from(data: &'a [u8; BLOOM_SIZE]) -> Self { BloomRef(data) } } @@ -234,14 +235,15 @@ impl<'a> From<&'a Bloom> for BloomRef<'a> { #[cfg(feature="serialize")] impl Serialize for Bloom { fn serialize(&self, serializer: S) -> Result where S: Serializer { - ethereum_types_serialize::serialize(&self.0, serializer) + let mut slice = [0u8; 2 + 2 * BLOOM_SIZE]; + ethereum_types_serialize::serialize(&mut slice, &self.0, serializer) } } #[cfg(feature="serialize")] impl<'de> Deserialize<'de> for Bloom { fn deserialize(deserializer: D) -> Result where D: Deserializer<'de> { - let mut bytes = [0; 256]; + let mut bytes = [0; BLOOM_SIZE]; ethereum_types_serialize::deserialize_check_len(deserializer, ethereum_types_serialize::ExpectedLen::Exact(&mut bytes))?; Ok(Bloom(bytes)) } diff --git a/ethereum-types/src/hash.rs b/ethereum-types/src/hash.rs index 2919523..f0c4c81 100644 --- a/ethereum-types/src/hash.rs +++ b/ethereum-types/src/hash.rs @@ -81,7 +81,8 @@ macro_rules! impl_serde { #[cfg(feature="serialize")] impl Serialize for $name { fn serialize(&self, serializer: S) -> Result where S: Serializer { - ethereum_types_serialize::serialize(&self.0, serializer) + let mut slice = [0u8; 2 + 2 * $len]; + ethereum_types_serialize::serialize(&mut slice, &self.0, serializer) } } diff --git a/ethereum-types/src/uint.rs b/ethereum-types/src/uint.rs index f76fcdc..a8ca234 100644 --- a/ethereum-types/src/uint.rs +++ b/ethereum-types/src/uint.rs @@ -334,9 +334,10 @@ macro_rules! impl_serde { #[cfg(feature="serialize")] impl Serialize for $name { fn serialize(&self, serializer: S) -> Result where S: Serializer { + let mut slice = [0u8; 2 + 2 * $len * 8]; let mut bytes = [0u8; $len * 8]; self.to_big_endian(&mut bytes); - ethereum_types_serialize::serialize_uint(&bytes, serializer) + ethereum_types_serialize::serialize_uint(&mut slice, &bytes, serializer) } } diff --git a/serialize/src/lib.rs b/serialize/src/lib.rs index 94ea196..e3a1873 100644 --- a/serialize/src/lib.rs +++ b/serialize/src/lib.rs @@ -5,38 +5,43 @@ use serde::{de, Serializer, Deserializer}; static CHARS: &'static[u8] = b"0123456789abcdef"; -fn to_hex(bytes: &[u8], skip_leading_zero: bool) -> String { - let mut v = Vec::with_capacity(2 + bytes.len() * 2); - v.push('0' as u8); - v.push('x' as u8); +fn to_hex<'a>(v: &'a mut [u8], bytes: &[u8], skip_leading_zero: bool) -> &'a str { + assert!(v.len() > 1 + bytes.len() * 2); + v[0] = '0' as u8; + v[1] = 'x' as u8; + + let mut idx = 2; let first_nibble = bytes[0] >> 4; if first_nibble != 0 || !skip_leading_zero { - v.push(CHARS[first_nibble as usize]); + v[idx] = CHARS[first_nibble as usize]; + idx += 1; } - v.push(CHARS[(bytes[0] & 0xf) as usize]); + v[idx] = CHARS[(bytes[0] & 0xf) as usize]; + idx += 1; for &byte in bytes.iter().skip(1) { - v.push(CHARS[(byte >> 4) as usize]); - v.push(CHARS[(byte & 0xf) as usize]); + v[idx] = CHARS[(byte >> 4) as usize]; + v[idx + 1] = CHARS[(byte & 0xf) as usize]; + idx += 2; } - unsafe { - String::from_utf8_unchecked(v) - } + ::std::str::from_utf8(&v[0..idx]).expect("All characters are coming from CHARS") } /// Serializes a slice of bytes. -pub fn serialize(bytes: &[u8], serializer: S) -> Result where +pub fn serialize(slice: &mut [u8], bytes: &[u8], serializer: S) -> Result where S: Serializer, { - serializer.serialize_str(&to_hex(bytes, false)) + let mut v = Vec::with_capacity(2 + bytes.len() * 2); + v.resize(2 + bytes.len() * 2, 0); + serializer.serialize_str(to_hex(slice, bytes, false)) } /// Serialize a slice of bytes as uint. /// /// The representation will have all leading zeros trimmed. -pub fn serialize_uint(bytes: &[u8], serializer: S) -> Result where +pub fn serialize_uint(slice: &mut [u8], bytes: &[u8], serializer: S) -> Result where S: Serializer, { let non_zero = bytes.iter().take_while(|b| **b == 0).count(); @@ -45,8 +50,7 @@ pub fn serialize_uint(bytes: &[u8], serializer: S) -> Result return serializer.serialize_str("0x0"); } - let string = to_hex(bytes, true); - serializer.serialize_str(&*string) + serializer.serialize_str(to_hex(slice, bytes, true)) } /// Expected length of bytes vector.