diff --git a/ethbloom/Cargo.toml b/ethbloom/Cargo.toml index 95a84eebb..df2b546a0 100644 --- a/ethbloom/Cargo.toml +++ b/ethbloom/Cargo.toml @@ -14,7 +14,7 @@ rust-version = "1.56.1" tiny-keccak = { version = "2.0", features = ["keccak"] } crunchy = { version = "0.2.2", default-features = false, features = ["limit_256"] } fixed-hash = { path = "../fixed-hash", version = "0.7", default-features = false } -impl-serde = { path = "../primitive-types/impls/serde", version = "0.3", default-features = false, optional = true } +impl-serde = { path = "../primitive-types/impls/serde", version = "0.4", default-features = false, optional = true } impl-rlp = { path = "../primitive-types/impls/rlp", version = "0.3", default-features = false, optional = true } impl-codec = { version = "0.6.0", path = "../primitive-types/impls/codec", default-features = false, optional = true } scale-info = { version = ">=1.0, <3", features = ["derive"], default-features = false, optional = true } diff --git a/ethereum-types/Cargo.toml b/ethereum-types/Cargo.toml index 3449beccd..596e8364f 100644 --- a/ethereum-types/Cargo.toml +++ b/ethereum-types/Cargo.toml @@ -13,7 +13,7 @@ ethbloom = { path = "../ethbloom", version = "0.12", default-features = false } fixed-hash = { path = "../fixed-hash", version = "0.7", default-features = false, features = ["byteorder", "rustc-hex"] } uint-crate = { path = "../uint", package = "uint", version = "0.9", default-features = false } primitive-types = { path = "../primitive-types", version = "0.11", features = ["byteorder", "rustc-hex"], default-features = false } -impl-serde = { path = "../primitive-types/impls/serde", version = "0.3.2", default-features = false, optional = true } +impl-serde = { path = "../primitive-types/impls/serde", version = "0.4.0", default-features = false, optional = true } impl-rlp = { path = "../primitive-types/impls/rlp", version = "0.3", default-features = false, optional = true } impl-codec = { version = "0.6.0", path = "../primitive-types/impls/codec", default-features = false, optional = true } scale-info = { version = ">=1.0, <3", features = ["derive"], default-features = false, optional = true } diff --git a/primitive-types/Cargo.toml b/primitive-types/Cargo.toml index f65c10507..5eb5ec049 100644 --- a/primitive-types/Cargo.toml +++ b/primitive-types/Cargo.toml @@ -11,7 +11,7 @@ rust-version = "1.60.0" [dependencies] fixed-hash = { version = "0.7", path = "../fixed-hash", default-features = false } uint = { version = "0.9.0", path = "../uint", default-features = false } -impl-serde = { version = "0.3.1", path = "impls/serde", default-features = false, optional = true } +impl-serde = { version = "0.4.0", path = "impls/serde", default-features = false, optional = true } impl-codec = { version = "0.6.0", path = "impls/codec", default-features = false, optional = true } impl-num-traits = { version = "0.1.0", path = "impls/num-traits", default-features = false, optional = true } impl-rlp = { version = "0.3", path = "impls/rlp", default-features = false, optional = true } diff --git a/primitive-types/impls/serde/CHANGELOG.md b/primitive-types/impls/serde/CHANGELOG.md index 5d143f916..43c06ddf5 100644 --- a/primitive-types/impls/serde/CHANGELOG.md +++ b/primitive-types/impls/serde/CHANGELOG.md @@ -4,7 +4,8 @@ The format is based on [Keep a Changelog]. [Keep a Changelog]: http://keepachangelog.com/en/1.0.0/ -## [Unreleased] +## [0.4.0] - 2022-08-31 +- Support deserializing H256 et al from bytes or sequences of bytes, too. [#668](https://github.com/paritytech/parity-common/pull/668) - Migrated to 2021 edition, enforcing MSRV of `1.56.1`. [#601](https://github.com/paritytech/parity-common/pull/601) ## [0.3.2] - 2021-11-10 diff --git a/primitive-types/impls/serde/Cargo.toml b/primitive-types/impls/serde/Cargo.toml index f94c754ac..91915edf9 100644 --- a/primitive-types/impls/serde/Cargo.toml +++ b/primitive-types/impls/serde/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "impl-serde" -version = "0.3.2" +version = "0.4.0" authors = ["Parity Technologies "] license = "MIT OR Apache-2.0" homepage = "https://github.com/paritytech/parity-common" diff --git a/primitive-types/impls/serde/src/serialize.rs b/primitive-types/impls/serde/src/serialize.rs index ee3a57c05..1426d3ddf 100644 --- a/primitive-types/impls/serde/src/serialize.rs +++ b/primitive-types/impls/serde/src/serialize.rs @@ -187,8 +187,8 @@ pub enum ExpectedLen<'a> { impl<'a> fmt::Display for ExpectedLen<'a> { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { match *self { - ExpectedLen::Exact(ref v) => write!(fmt, "length of {}", v.len() * 2), - ExpectedLen::Between(min, ref v) => write!(fmt, "length between ({}; {}]", min * 2, v.len() * 2), + ExpectedLen::Exact(ref v) => write!(fmt, "{} bytes", v.len()), + ExpectedLen::Between(min, ref v) => write!(fmt, "between ({}; {}] bytes", min, v.len()), } } } @@ -205,7 +205,7 @@ where type Value = Vec; fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - write!(formatter, "a (both 0x-prefixed or not) hex string") + write!(formatter, "a (both 0x-prefixed or not) hex string or byte array") } fn visit_str(self, v: &str) -> Result { @@ -215,6 +215,22 @@ where fn visit_string(self, v: String) -> Result { self.visit_str(&v) } + + fn visit_bytes(self, v: &[u8]) -> Result { + Ok(v.to_vec()) + } + + fn visit_byte_buf(self, v: Vec) -> Result { + Ok(v) + } + + fn visit_seq>(self, mut seq: A) -> Result { + let mut bytes = vec![]; + while let Some(n) = seq.next_element::()? { + bytes.push(n); + } + Ok(bytes) + } } deserializer.deserialize_str(Visitor) @@ -234,7 +250,7 @@ where type Value = usize; fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - write!(formatter, "a (both 0x-prefixed or not) hex string with {}", self.len) + write!(formatter, "a (both 0x-prefixed or not) hex string or byte array containing {}", self.len) } fn visit_str(self, v: &str) -> Result { @@ -261,6 +277,38 @@ where fn visit_string(self, v: String) -> Result { self.visit_str(&v) } + + fn visit_bytes(self, v: &[u8]) -> Result { + let len = v.len(); + let is_len_valid = match self.len { + ExpectedLen::Exact(ref slice) => len == slice.len(), + ExpectedLen::Between(min, ref slice) => len <= slice.len() && len > min, + }; + + if !is_len_valid { + return Err(E::invalid_length(v.len(), &self)) + } + + let bytes = match self.len { + ExpectedLen::Exact(slice) => slice, + ExpectedLen::Between(_, slice) => slice, + }; + + bytes[..len].copy_from_slice(v); + Ok(len) + } + + fn visit_byte_buf(self, v: Vec) -> Result { + self.visit_bytes(&v) + } + + fn visit_seq>(self, mut seq: A) -> Result { + let mut v = vec![]; + while let Some(n) = seq.next_element::()? { + v.push(n); + } + self.visit_byte_buf(v) + } } deserializer.deserialize_str(Visitor { len }) @@ -367,4 +415,82 @@ mod tests { assert_eq!(from_hex("102"), Ok(vec![1, 2])); assert_eq!(from_hex("f"), Ok(vec![0xf])); } + + #[test] + fn should_deserialize_from_owned_bytes() { + type BytesDeserializer<'a> = serde::de::value::BytesDeserializer<'a, serde::de::value::Error>; + + // using `deserialize` to decode owned bytes. + let des = BytesDeserializer::new(&[1, 2, 3, 4, 5]); + let deserialized: Vec = deserialize(des).unwrap(); + assert_eq!(deserialized, vec![1, 2, 3, 4, 5]); + + // using `deserialize` to decode owned bytes into buffer with fixed length. + let des = BytesDeserializer::new(&[1, 2, 3, 4, 5]); + let mut output = vec![0, 0, 0, 0, 0]; + let expected_len = ExpectedLen::Exact(&mut *output); + let n = deserialize_check_len(des, expected_len).unwrap(); + assert_eq!(n, 5); + assert_eq!(output, vec![1, 2, 3, 4, 5]); + + // using `deserialize` to decode owned bytes into buffer with min/max length. + let des = BytesDeserializer::new(&[1, 2, 3]); + let mut output = vec![0, 0, 0, 0, 0]; + let expected_len = ExpectedLen::Between(2, &mut *output); + let n = deserialize_check_len(des, expected_len).unwrap(); + assert_eq!(n, 3); + assert_eq!(output, vec![1, 2, 3, 0, 0]); + } + + #[test] + fn should_deserialize_from_borrowed_bytes() { + type BytesDeserializer<'a> = serde::de::value::BorrowedBytesDeserializer<'a, serde::de::value::Error>; + + // using `deserialize` to decode borrowed bytes. + let des = BytesDeserializer::new(&[1, 2, 3, 4, 5]); + let deserialized: Vec = deserialize(des).unwrap(); + assert_eq!(deserialized, vec![1, 2, 3, 4, 5]); + + // using `deserialize` to decode borrowed bytes into buffer with fixed length. + let des = BytesDeserializer::new(&[1, 2, 3, 4, 5]); + let mut output = vec![0, 0, 0, 0, 0]; + let expected_len = ExpectedLen::Exact(&mut *output); + let n = deserialize_check_len(des, expected_len).unwrap(); + assert_eq!(n, 5); + assert_eq!(output, vec![1, 2, 3, 4, 5]); + + // using `deserialize` to decode borrowed bytes into buffer with min/max length. + let des = BytesDeserializer::new(&[1, 2, 3]); + let mut output = vec![0, 0, 0, 0, 0]; + let expected_len = ExpectedLen::Between(2, &mut *output); + let n = deserialize_check_len(des, expected_len).unwrap(); + assert_eq!(n, 3); + assert_eq!(output, vec![1, 2, 3, 0, 0]); + } + + #[test] + fn should_deserialize_from_u8_sequence() { + use serde::de::value::SeqDeserializer; + + // using `deserialize` to decode a sequence of bytes. + let des = SeqDeserializer::<_, serde::de::value::Error>::new([1u8, 2, 3, 4, 5].into_iter()); + let deserialized: Vec = deserialize(des).unwrap(); + assert_eq!(deserialized, vec![1, 2, 3, 4, 5]); + + // using `deserialize` to decode a sequence of bytes into a buffer with fixed length. + let des = SeqDeserializer::<_, serde::de::value::Error>::new([1u8, 2, 3, 4, 5].into_iter()); + let mut output = vec![0, 0, 0, 0, 0]; + let expected_len = ExpectedLen::Exact(&mut *output); + let n = deserialize_check_len(des, expected_len).unwrap(); + assert_eq!(n, 5); + assert_eq!(output, vec![1, 2, 3, 4, 5]); + + // using `deserialize` to decode a sequence of bytes into a buffer with min/max length. + let des = SeqDeserializer::<_, serde::de::value::Error>::new([1u8, 2, 3].into_iter()); + let mut output = vec![0, 0, 0, 0, 0]; + let expected_len = ExpectedLen::Between(2, &mut *output); + let n = deserialize_check_len(des, expected_len).unwrap(); + assert_eq!(n, 3); + assert_eq!(output, vec![1, 2, 3, 0, 0]); + } }