Stack-based allocation for serialization.

This commit is contained in:
Tomasz Drwięga 2018-02-02 13:42:25 +01:00
parent 1320986642
commit 90a3ada499
No known key found for this signature in database
GPG Key ID: B2BA26B1C688F8FC
4 changed files with 40 additions and 32 deletions

View File

@ -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<B> {
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<B> {
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<S>(&self, serializer: S) -> Result<S::Ok, S::Error> 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<D>(deserializer: D) -> Result<Self, D::Error> 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))
}

View File

@ -81,7 +81,8 @@ macro_rules! impl_serde {
#[cfg(feature="serialize")]
impl Serialize for $name {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> 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)
}
}

View File

@ -334,9 +334,10 @@ macro_rules! impl_serde {
#[cfg(feature="serialize")]
impl Serialize for $name {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> 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)
}
}

View File

@ -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<S>(bytes: &[u8], serializer: S) -> Result<S::Ok, S::Error> where
pub fn serialize<S>(slice: &mut [u8], bytes: &[u8], serializer: S) -> Result<S::Ok, S::Error> 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<S>(bytes: &[u8], serializer: S) -> Result<S::Ok, S::Error> where
pub fn serialize_uint<S>(slice: &mut [u8], bytes: &[u8], serializer: S) -> Result<S::Ok, S::Error> where
S: Serializer,
{
let non_zero = bytes.iter().take_while(|b| **b == 0).count();
@ -45,8 +50,7 @@ pub fn serialize_uint<S>(bytes: &[u8], serializer: S) -> Result<S::Ok, S::Error>
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.