Skip to content

Commit ce7669e

Browse files
committedDec 9, 2023
Use field indices for struct deserialization
Serde allows to deserialize fields in structs by returning an index instead of the name as a string. This saves another 1.7% off benchmark size and speeds up CitmCatalog and twitter parsing benchmarks by 7-10%.
1 parent a7e4c5b commit ce7669e

File tree

2 files changed

+14
-11
lines changed

2 files changed

+14
-11
lines changed
 

‎Cargo.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ categories = ["development-tools::ffi", "wasm", "encoding"]
1111
keywords = ["serde", "serialization", "javascript", "wasm", "webassembly"]
1212

1313
[dependencies]
14-
serde = { version = "^1.0", features = ["derive"] }
14+
serde = { version = "1.0.193", features = ["derive"] }
1515
js-sys = "^0.3"
1616
wasm-bindgen = "0.2.83"
1717

‎src/de.rs

+13-10
Original file line numberDiff line numberDiff line change
@@ -65,39 +65,40 @@ impl<'de> de::MapAccess<'de> for MapAccess {
6565

6666
struct ObjectAccess {
6767
obj: ObjectExt,
68-
fields: std::slice::Iter<'static, &'static str>,
68+
fields: std::iter::Enumerate<std::slice::Iter<'static, &'static str>>,
6969
next_value: Option<Deserializer>,
7070
}
7171

7272
impl ObjectAccess {
7373
fn new(obj: ObjectExt, fields: &'static [&'static str]) -> Self {
7474
Self {
7575
obj,
76-
fields: fields.iter(),
76+
fields: fields.iter().enumerate(),
7777
next_value: None,
7878
}
7979
}
8080
}
8181

82-
fn str_deserializer(s: &str) -> de::value::StrDeserializer<Error> {
83-
de::IntoDeserializer::into_deserializer(s)
84-
}
85-
8682
impl<'de> de::MapAccess<'de> for ObjectAccess {
8783
type Error = Error;
8884

8985
fn next_key_seed<K: de::DeserializeSeed<'de>>(&mut self, seed: K) -> Result<Option<K::Value>> {
9086
debug_assert!(self.next_value.is_none());
9187

92-
for field in &mut self.fields {
88+
for (i, &field) in &mut self.fields {
9389
let js_field = static_str_to_js(field);
9490
let next_value = self.obj.get_with_ref_key(&js_field);
9591
// If this value is `undefined`, it might be actually a missing field;
9692
// double-check with an `in` operator if so.
9793
let is_missing_field = next_value.is_undefined() && !js_field.js_in(&self.obj);
9894
if !is_missing_field {
9995
self.next_value = Some(Deserializer::from(next_value));
100-
return Ok(Some(seed.deserialize(str_deserializer(field))?));
96+
// Serde can deserialize struct fields from their indices.
97+
// Using them allows for more efficient deserialization as it
98+
// avoids string comparisons.
99+
return Ok(Some(seed.deserialize(
100+
de::IntoDeserializer::<Error>::into_deserializer(i),
101+
)?));
101102
}
102103
}
103104

@@ -127,8 +128,10 @@ impl<'de> de::SeqAccess<'de> for PreservedValueAccess {
127128
match this {
128129
Self::OnMagic(value) => {
129130
*self = Self::OnValue(value);
130-
seed.deserialize(str_deserializer(PRESERVED_VALUE_MAGIC))
131-
.map(Some)
131+
seed.deserialize(de::IntoDeserializer::into_deserializer(
132+
PRESERVED_VALUE_MAGIC,
133+
))
134+
.map(Some)
132135
}
133136
Self::OnValue(value) => seed
134137
.deserialize(Deserializer {

0 commit comments

Comments
 (0)