From 2d08a51f8a7656089b6b720750e78fdde32ec2b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Sat, 11 Nov 2017 12:29:49 +0100 Subject: [PATCH] Fix naming and code. --- substrate/primitives/src/bytes.rs | 95 +++++++++++++++++++------------ substrate/primitives/src/hash.rs | 10 +--- substrate/primitives/src/uint.rs | 12 +--- 3 files changed, 65 insertions(+), 52 deletions(-) diff --git a/substrate/primitives/src/bytes.rs b/substrate/primitives/src/bytes.rs index efe21da706..ab69d36e70 100644 --- a/substrate/primitives/src/bytes.rs +++ b/substrate/primitives/src/bytes.rs @@ -18,7 +18,7 @@ use std::fmt; use serde::{de, Serializer, Deserializer}; -/// Serializes a slice of bytes into a most compact form. +/// Serializes a slice of bytes. pub fn serialize(bytes: &[u8], serializer: S) -> Result where S: Serializer, { @@ -26,47 +26,66 @@ pub fn serialize(bytes: &[u8], serializer: S) -> Result wher serializer.serialize_str(&format!("0x{}", hex)) } -pub fn serialize_compact(bytes: &[u8], serializer: S) -> Result where +/// 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 S: Serializer, { - let mut non_zero = bytes.len(); - for (i, b) in bytes.iter().enumerate() { - if *b != 0 { - non_zero = i; - break; - } - } - - if non_zero == bytes.len() { + let non_zero = bytes.iter().take_while(|b| **b == 0).count(); + let bytes = &bytes[non_zero..]; + if bytes.is_empty() { return serializer.serialize_str("0x0"); } - let hex = ::rustc_hex::ToHex::to_hex(&bytes[non_zero..]); + let hex = ::rustc_hex::ToHex::to_hex(bytes); let has_leading_zero = !hex.is_empty() && &hex[0..1] == "0"; - return serializer.serialize_str(&format!("0x{}", if has_leading_zero { &hex[1..] } else { &hex })); + serializer.serialize_str( + &format!("0x{}", if has_leading_zero { &hex[1..] } else { &hex }) + ) } +/// Expected length of bytes vector. +#[derive(Debug, PartialEq, Eq)] +pub enum ExpectedLen { + /// Any length in bytes. + Any, + /// Exact length in bytes. + Exact(usize), + /// A bytes length between (min; max]. + Between(usize, usize), +} + +impl fmt::Display for ExpectedLen { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + match *self { + ExpectedLen::Any => write!(fmt, "even length"), + ExpectedLen::Exact(v) => write!(fmt, "length of {}", v * 2), + ExpectedLen::Between(min, max) => write!(fmt, "length between ({}; {}]", min * 2, max * 2), + } + } +} + +/// Deserialize into vector of bytes. pub fn deserialize<'de, D>(deserializer: D) -> Result, D::Error> where D: Deserializer<'de>, { - deserialize_with_check(deserializer, |_| Ok(())) + deserialize_check_len(deserializer, ExpectedLen::Any) } -pub fn deserialize_with_check<'de, D, F>(deserializer: D, check: F) -> Result, D::Error> where +/// Deserialize into vector of bytes with additional size check. +pub fn deserialize_check_len<'de, D>(deserializer: D, len: ExpectedLen) -> Result, D::Error> where D: Deserializer<'de>, - F: Fn(&str) -> Result<(), ErrorKind>, { - struct Visitor { - check: F, + struct Visitor { + len: ExpectedLen, } - impl<'a, F> de::Visitor<'a> for Visitor where - F: Fn(&str) -> Result<(), ErrorKind>, - { + impl<'a> de::Visitor<'a> for Visitor { type Value = Vec; fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - write!(formatter, "a 0x-prefixed hex string") + write!(formatter, "a 0x-prefixed hex string with {}", self.len) } fn visit_str(self, v: &str) -> Result { @@ -74,14 +93,25 @@ pub fn deserialize_with_check<'de, D, F>(deserializer: D, check: F) -> Result E::invalid_length(len, &self), - })?; + let is_len_valid = match self.len { + // just make sure that we have all nibbles + ExpectedLen::Any => v.len() % 2 == 0, + ExpectedLen::Exact(len) => v.len() == 2 * len + 2, + ExpectedLen::Between(min, max) => v.len() <= 2 * max + 2 && v.len() > 2 * min + 2, + }; - let v = if v.len() % 2 == 0 { v[2..].to_owned() } else { format!("0{}", &v[2..]) }; - let bytes = ::rustc_hex::FromHex::from_hex(v.as_str()) - .map_err(|e| E::custom(&format!("invalid hex value: {:?}", e)))?; - Ok(bytes) + if !is_len_valid { + return Err(E::invalid_length(v.len() - 2, &self)) + } + + let bytes = match self.len { + ExpectedLen::Between(..) if v.len() % 2 != 0 => { + ::rustc_hex::FromHex::from_hex(&*format!("0{}", &v[2..])) + }, + _ => ::rustc_hex::FromHex::from_hex(&v[2..]) + }; + + bytes.map_err(|e| E::custom(&format!("invalid hex value: {:?}", e))) } fn visit_string(self, v: String) -> Result { @@ -90,10 +120,5 @@ pub fn deserialize_with_check<'de, D, F>(deserializer: D, check: F) -> Result Deserialize<'de> for $name { fn deserialize(deserializer: D) -> Result where D: Deserializer<'de> { - bytes::deserialize_with_check(deserializer, |v: &str| { - // 0x + len - if v.len() != 2 + $len * 2 { - Err(bytes::ErrorKind::InvalidLength(v.len() - 2)) - } else { - Ok(()) - } - }).map(|x| (&*x).into()) + bytes::deserialize_check_len(deserializer, bytes::ExpectedLen::Exact($len)) + .map(|x| (&*x).into()) } } } diff --git a/substrate/primitives/src/uint.rs b/substrate/primitives/src/uint.rs index 8f1c07bde1..cecf69dd2a 100644 --- a/substrate/primitives/src/uint.rs +++ b/substrate/primitives/src/uint.rs @@ -26,20 +26,14 @@ macro_rules! impl_serde { fn serialize(&self, serializer: S) -> Result where S: Serializer { let mut bytes = [0u8; $len * 8]; self.to_big_endian(&mut bytes); - bytes::serialize_compact(&bytes, serializer) + bytes::serialize_uint(&bytes, serializer) } } impl<'de> Deserialize<'de> for $name { fn deserialize(deserializer: D) -> Result where D: Deserializer<'de> { - bytes::deserialize_with_check(deserializer, |v: &str| { - // 0x + len - if v.len() > 2 + $len * 16 || v.len() == 2 { - Err(bytes::ErrorKind::InvalidLength(v.len() - 2)) - } else { - Ok(()) - } - }).map(|bytes| (&*bytes).into()) + bytes::deserialize_check_len(deserializer, bytes::ExpectedLen::Between(0, $len * 8)) + .map(|x| (&*x).into()) } } }