add default serde serialization to ethereum-types
This commit is contained in:
parent
87912d868f
commit
d053c5b6bf
|
@ -1,7 +1,7 @@
|
|||
[package]
|
||||
name = "ethbloom"
|
||||
version = "0.3.0"
|
||||
authors = ["debris <marek.kotewicz@gmail.com>"]
|
||||
authors = ["Parity Technologies <admin@parity.io>"]
|
||||
description = "Ethereum bloom filter"
|
||||
license = "MIT"
|
||||
documentation = "https://docs.rs/ethbloom"
|
||||
|
@ -12,12 +12,15 @@ repository = "https://github.com/debris/ethbloom"
|
|||
tiny-keccak = "1.4"
|
||||
crunchy = { version = "0.1.6", features = ["limit_256"] }
|
||||
fixed-hash = { version = "0.1.1", path = "../fixed-hash" }
|
||||
ethereum-types-serialize = { version = "0.1", path = "../serialize", optional = true }
|
||||
serde = { version = "1.0", optional = true }
|
||||
|
||||
[dev-dependencies]
|
||||
rand = "0.4"
|
||||
rustc-hex = "1.0"
|
||||
|
||||
[features]
|
||||
default = ["std", "heapsizeof"]
|
||||
default = ["std", "heapsizeof", "serialize"]
|
||||
std = ["fixed-hash/std"]
|
||||
heapsizeof = ["fixed-hash/heapsizeof"]
|
||||
serialize = ["std", "ethereum-types-serialize", "serde"]
|
||||
|
|
|
@ -40,6 +40,15 @@ extern crate crunchy;
|
|||
#[macro_use]
|
||||
extern crate fixed_hash;
|
||||
|
||||
#[cfg(feature="serialize")]
|
||||
extern crate ethereum_types_serialize;
|
||||
|
||||
#[cfg(feature="serialize")]
|
||||
extern crate serde;
|
||||
|
||||
#[cfg(feature="serialize")]
|
||||
use serde::{Serialize, Serializer, Deserialize, Deserializer};
|
||||
|
||||
use core::{ops, mem, str};
|
||||
use tiny_keccak::keccak256;
|
||||
|
||||
|
@ -224,6 +233,19 @@ impl<'a> From<&'a Bloom> for BloomRef<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de> Deserialize<'de> for Bloom {
|
||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> where D: Deserializer<'de> {
|
||||
ethereum_types_serialize::deserialize_check_len(deserializer, ethereum_types_serialize::ExpectedLen::Exact(256))
|
||||
.map(|x| (&*x).into())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
extern crate rustc_hex;
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
[package]
|
||||
name = "ethereum-types"
|
||||
version = "0.1.4"
|
||||
authors = ["debris <marek.kotewicz@gmail.com>"]
|
||||
authors = ["Parity Technologies <admin@parity.io>"]
|
||||
license = "MIT"
|
||||
homepage = "https://github.com/paritytech/primitives"
|
||||
description = "Ethereum types"
|
||||
|
@ -14,8 +14,11 @@ uint = { path = "../uint", version = "0.1" }
|
|||
fixed-hash = { path = "../fixed-hash", version = "0.1.1" }
|
||||
ethbloom = { path = "../ethbloom", version = "0.3" }
|
||||
crunchy = "0.1.5"
|
||||
ethereum-types-serialize = { version = "0.1", path = "../serialize", optional = true }
|
||||
serde = { version = "1.0", optional = true }
|
||||
|
||||
[features]
|
||||
default = ["std", "heapsizeof"]
|
||||
default = ["std", "heapsizeof", "serialize"]
|
||||
std = ["uint/std", "fixed-hash/std", "ethbloom/std"]
|
||||
heapsizeof = ["uint/heapsizeof", "fixed-hash/heapsizeof", "ethbloom/heapsizeof"]
|
||||
serialize = ["std", "ethereum-types-serialize", "serde", "ethbloom/serialize"]
|
||||
|
|
|
@ -1,5 +1,11 @@
|
|||
use U256;
|
||||
|
||||
#[cfg(feature="serialize")]
|
||||
use serde::{Serialize, Serializer, Deserialize, Deserializer};
|
||||
|
||||
#[cfg(feature="serialize")]
|
||||
use ethereum_types_serialize;
|
||||
|
||||
construct_hash!(H32, 4);
|
||||
construct_hash!(H64, 8);
|
||||
construct_hash!(H128, 16);
|
||||
|
@ -70,3 +76,31 @@ impl<'a> From<&'a H160> for H256 {
|
|||
}
|
||||
}
|
||||
|
||||
macro_rules! impl_serde {
|
||||
($name: ident, $len: expr) => {
|
||||
#[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)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature="serialize")]
|
||||
impl<'de> Deserialize<'de> for $name {
|
||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> where D: Deserializer<'de> {
|
||||
ethereum_types_serialize::deserialize_check_len(deserializer, ethereum_types_serialize::ExpectedLen::Exact($len))
|
||||
.map(|x| (&*x).into())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl_serde!(H32, 4);
|
||||
impl_serde!(H64, 8);
|
||||
impl_serde!(H128, 16);
|
||||
impl_serde!(H160, 20);
|
||||
impl_serde!(H256, 32);
|
||||
impl_serde!(H264, 33);
|
||||
impl_serde!(H512, 64);
|
||||
impl_serde!(H520, 65);
|
||||
impl_serde!(H1024, 128);
|
||||
|
|
|
@ -12,6 +12,11 @@ extern crate uint as uint_crate;
|
|||
extern crate fixed_hash;
|
||||
extern crate ethbloom;
|
||||
|
||||
#[cfg(feature="serialize")]
|
||||
extern crate ethereum_types_serialize;
|
||||
#[cfg(feature="serialize")]
|
||||
extern crate serde;
|
||||
|
||||
mod hash;
|
||||
mod uint;
|
||||
|
||||
|
|
|
@ -1,3 +1,9 @@
|
|||
#[cfg(feature="serialize")]
|
||||
use serde::{Serialize, Serializer, Deserialize, Deserializer};
|
||||
|
||||
#[cfg(feature="serialize")]
|
||||
use ethereum_types_serialize;
|
||||
|
||||
construct_uint!(U128, 2);
|
||||
construct_uint!(U256, 4);
|
||||
construct_uint!(U512, 8);
|
||||
|
@ -322,3 +328,28 @@ impl From<U512> for [u8; 64] {
|
|||
arr
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! impl_serde {
|
||||
($name: ident, $len: expr) => {
|
||||
#[cfg(feature="serialize")]
|
||||
impl Serialize for $name {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where S: Serializer {
|
||||
let mut bytes = [0u8; $len * 8];
|
||||
self.to_big_endian(&mut bytes);
|
||||
ethereum_types_serialize::serialize_uint(&bytes, serializer)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature="serialize")]
|
||||
impl<'de> Deserialize<'de> for $name {
|
||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> where D: Deserializer<'de> {
|
||||
ethereum_types_serialize::deserialize_check_len(deserializer, ethereum_types_serialize::ExpectedLen::Between(0, $len * 8))
|
||||
.map(|x| (&*x).into())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl_serde!(U128, 2);
|
||||
impl_serde!(U256, 4);
|
||||
impl_serde!(U512, 8);
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
[package]
|
||||
name = "fixed-hash"
|
||||
version = "0.1.2"
|
||||
authors = ["debris <marek.kotewicz@gmail.com>"]
|
||||
authors = ["Parity Technologies <admin@parity.io>"]
|
||||
license = "MIT"
|
||||
homepage = "https://github.com/paritytech/primitives"
|
||||
description = "Fixed-size hashes"
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
[package]
|
||||
name = "ethereum-types-serialize"
|
||||
version = "0.1.0"
|
||||
authors = ["Parity Technologies <admin@parity.io>"]
|
||||
|
||||
[dependencies]
|
||||
serde = "1.0"
|
||||
rustc-hex = "1.0"
|
|
@ -0,0 +1,112 @@
|
|||
extern crate serde;
|
||||
extern crate rustc_hex;
|
||||
|
||||
use std::fmt;
|
||||
|
||||
use serde::{de, Serializer, Deserializer};
|
||||
use rustc_hex::{ToHex, FromHex};
|
||||
|
||||
/// Serializes a slice of bytes.
|
||||
pub fn serialize<S>(bytes: &[u8], serializer: S) -> Result<S::Ok, S::Error> where
|
||||
S: Serializer,
|
||||
{
|
||||
let hex = ToHex::to_hex(bytes);
|
||||
serializer.serialize_str(&format!("0x{}", hex))
|
||||
}
|
||||
|
||||
/// 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
|
||||
S: Serializer,
|
||||
{
|
||||
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 = ToHex::to_hex(bytes);
|
||||
let has_leading_zero = !hex.is_empty() && &hex[0..1] == "0";
|
||||
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<Vec<u8>, D::Error> where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
deserialize_check_len(deserializer, ExpectedLen::Any)
|
||||
}
|
||||
|
||||
/// Deserialize into vector of bytes with additional size check.
|
||||
pub fn deserialize_check_len<'de, D>(deserializer: D, len: ExpectedLen) -> Result<Vec<u8>, D::Error> where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
struct Visitor {
|
||||
len: ExpectedLen,
|
||||
}
|
||||
|
||||
impl<'a> de::Visitor<'a> for Visitor {
|
||||
type Value = Vec<u8>;
|
||||
|
||||
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(formatter, "a 0x-prefixed hex string with {}", self.len)
|
||||
}
|
||||
|
||||
fn visit_str<E: de::Error>(self, v: &str) -> Result<Self::Value, E> {
|
||||
if v.len() < 2 || &v[0..2] != "0x" {
|
||||
return Err(E::custom("prefix is missing"))
|
||||
}
|
||||
|
||||
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,
|
||||
};
|
||||
|
||||
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 => {
|
||||
FromHex::from_hex(&*format!("0{}", &v[2..]))
|
||||
},
|
||||
_ => FromHex::from_hex(&v[2..])
|
||||
};
|
||||
|
||||
bytes.map_err(|e| E::custom(&format!("invalid hex value: {:?}", e)))
|
||||
}
|
||||
|
||||
fn visit_string<E: de::Error>(self, v: String) -> Result<Self::Value, E> {
|
||||
self.visit_str(&v)
|
||||
}
|
||||
}
|
||||
// TODO [ToDr] Use raw bytes if we switch to RLP / binencoding
|
||||
// (visit_bytes, visit_bytes_buf)
|
||||
deserializer.deserialize_str(Visitor { len })
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
[package]
|
||||
name = "tests"
|
||||
version = "0.1.0"
|
||||
authors = ["debris <marek.kotewicz@gmail.com>"]
|
||||
authors = ["Parity Technologies <admin@parity.io>"]
|
||||
|
||||
[build-dependencies]
|
||||
rustc_version = "0.2"
|
||||
|
|
Loading…
Reference in New Issue