Skip to content
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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions primitive-types/impls/serde/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "impl-serde"
version = "0.2.1"
version = "0.2.2"
authors = ["Parity Technologies <[email protected]>"]
license = "Apache-2.0/MIT"
homepage = "https://github.com/paritytech/parity-common"
Expand All @@ -11,8 +11,9 @@ serde = "1.0"

[dev-dependencies]
criterion = "0.3.0"
uint = "0.8.1"
serde_derive = "1.0"
serde_json = "1.0.40"
uint = "0.8.1"

[[bench]]
name = "impl_serde"
Expand Down
41 changes: 40 additions & 1 deletion primitive-types/impls/serde/src/serialize.rs
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ pub fn deserialize<'de, D>(deserializer: D) -> Result<Vec<u8>, D::Error> where

let bytes_len = v.len() - 2;
let mut modulus = bytes_len % 2;
let mut bytes = vec![0u8; bytes_len / 2];
let mut bytes = vec![0u8; (bytes_len + 1) / 2];
Copy link
Contributor

@niklasad1 niklasad1 Oct 21, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why bother with this complex logic?
Isn't better to use Vec::new() / Vec::with_capacity() and Vec::push?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well, it's a performance optimization (hopefuly measureable), which is justified, since this code might be on a hot path.
Also this logic is not that complex imho, seems it was just untested properly.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I for one kind of agree with Niklas here: it's a bit odd and I'm surprised to learn it's faster to init a vec with vec![0u8; 123] than Vec::with_capacity(123).

(No action needed here, I'm just curious)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm about to add benches for Bytes to be continued :P

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wow, thanks for making me realize this is actually a vec. I was pretty sure that we just allocate an array here (but obviously we don't cause it's not a constant size)
I'm really curious about the performance indeed, as just using push instead of direct access seems way less error prone, and with_capacity should ensure that there are no re-allocations.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I really hope there's no difference in performance! :)

let mut buf = 0;
let mut pos = 0;
for (idx, byte) in v.bytes().enumerate().skip(2) {
Expand Down Expand Up @@ -217,3 +217,42 @@ pub fn deserialize_check_len<'a, 'de, D>(deserializer: D, len: ExpectedLen<'a>)

deserializer.deserialize_str(Visitor { len })
}

#[cfg(test)]
mod tests {
extern crate serde_derive;

use self::serde_derive::Deserialize;

#[derive(Deserialize)]
struct Bytes(#[serde(with="super")] Vec<u8>);

#[test]
fn should_not_fail_on_short_string() {
let a: Bytes = serde_json::from_str("\"0x\"").unwrap();
let b: Bytes = serde_json::from_str("\"0x1\"").unwrap();
let c: Bytes = serde_json::from_str("\"0x12\"").unwrap();
let d: Bytes = serde_json::from_str("\"0x123\"").unwrap();
let e: Bytes = serde_json::from_str("\"0x1234\"").unwrap();
let f: Bytes = serde_json::from_str("\"0x12345\"").unwrap();

assert!(a.0.is_empty());
assert_eq!(b.0, vec![1]);
assert_eq!(c.0, vec![0x12]);
assert_eq!(d.0, vec![0x1, 0x23]);
assert_eq!(e.0, vec![0x12, 0x34]);
assert_eq!(f.0, vec![0x1, 0x23, 0x45]);
}


#[test]
fn should_not_fail_on_other_strings() {
let a: Bytes = serde_json::from_str("\"0x7f864e18e3dd8b58386310d2fe0919eef27c6e558564b7f67f22d99d20f587\"").unwrap();
let b: Bytes = serde_json::from_str("\"0x7f864e18e3dd8b58386310d2fe0919eef27c6e558564b7f67f22d99d20f587b\"").unwrap();
let c: Bytes = serde_json::from_str("\"0x7f864e18e3dd8b58386310d2fe0919eef27c6e558564b7f67f22d99d20f587b4\"").unwrap();

assert_eq!(a.0.len(), 31);
assert_eq!(b.0.len(), 32);
assert_eq!(c.0.len(), 32);
}
}