Skip to content

Commit

Permalink
Support deserializing from borrowed or owned bytes, too (#668)
Browse files Browse the repository at this point in the history
* Support deserializing from borrowed or owned bytes, too

* cargo fmt

* Fix comments

* H256 et al can deserialize u8 sequences, too

* add changelog entry and bump version ready for release

* propagate the bump

Co-authored-by: Andronik <write@reusable.software>
  • Loading branch information
jsdw and ordian committed Aug 31, 2022
1 parent 076ba7a commit 706c989
Show file tree
Hide file tree
Showing 6 changed files with 136 additions and 9 deletions.
2 changes: 1 addition & 1 deletion ethbloom/Cargo.toml
Expand Up @@ -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 }
Expand Down
2 changes: 1 addition & 1 deletion ethereum-types/Cargo.toml
Expand Up @@ -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 }
Expand Down
2 changes: 1 addition & 1 deletion primitive-types/Cargo.toml
Expand Up @@ -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 }
Expand Down
3 changes: 2 additions & 1 deletion primitive-types/impls/serde/CHANGELOG.md
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion 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 <admin@parity.io>"]
license = "MIT OR Apache-2.0"
homepage = "https://github.com/paritytech/parity-common"
Expand Down
134 changes: 130 additions & 4 deletions primitive-types/impls/serde/src/serialize.rs
Expand Up @@ -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()),
}
}
}
Expand All @@ -205,7 +205,7 @@ where
type Value = Vec<u8>;

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<E: de::Error>(self, v: &str) -> Result<Self::Value, E> {
Expand All @@ -215,6 +215,22 @@ where
fn visit_string<E: de::Error>(self, v: String) -> Result<Self::Value, E> {
self.visit_str(&v)
}

fn visit_bytes<E: de::Error>(self, v: &[u8]) -> Result<Self::Value, E> {
Ok(v.to_vec())
}

fn visit_byte_buf<E: de::Error>(self, v: Vec<u8>) -> Result<Self::Value, E> {
Ok(v)
}

fn visit_seq<A: de::SeqAccess<'b>>(self, mut seq: A) -> Result<Self::Value, A::Error> {
let mut bytes = vec![];
while let Some(n) = seq.next_element::<u8>()? {
bytes.push(n);
}
Ok(bytes)
}
}

deserializer.deserialize_str(Visitor)
Expand All @@ -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<E: de::Error>(self, v: &str) -> Result<Self::Value, E> {
Expand All @@ -261,6 +277,38 @@ where
fn visit_string<E: de::Error>(self, v: String) -> Result<Self::Value, E> {
self.visit_str(&v)
}

fn visit_bytes<E: de::Error>(self, v: &[u8]) -> Result<Self::Value, E> {
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<E: de::Error>(self, v: Vec<u8>) -> Result<Self::Value, E> {
self.visit_bytes(&v)
}

fn visit_seq<A: de::SeqAccess<'b>>(self, mut seq: A) -> Result<Self::Value, A::Error> {
let mut v = vec![];
while let Some(n) = seq.next_element::<u8>()? {
v.push(n);
}
self.visit_byte_buf(v)
}
}

deserializer.deserialize_str(Visitor { len })
Expand Down Expand Up @@ -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<u8> = 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<u8> = 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<u8> = 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]);
}
}

0 comments on commit 706c989

Please sign in to comment.