Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support deserializing from borrowed or owned bytes, too #668

Merged
merged 6 commits into from Aug 31, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
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]);
}
}