Skip to content

Commit

Permalink
Use field indices for struct deserialization
Browse files Browse the repository at this point in the history
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%.
  • Loading branch information
RReverser committed Dec 9, 2023
1 parent a7e4c5b commit ce7669e
Show file tree
Hide file tree
Showing 2 changed files with 14 additions and 11 deletions.
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ categories = ["development-tools::ffi", "wasm", "encoding"]
keywords = ["serde", "serialization", "javascript", "wasm", "webassembly"]

[dependencies]
serde = { version = "^1.0", features = ["derive"] }
serde = { version = "1.0.193", features = ["derive"] }
js-sys = "^0.3"
wasm-bindgen = "0.2.83"

Expand Down
23 changes: 13 additions & 10 deletions src/de.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,39 +65,40 @@ impl<'de> de::MapAccess<'de> for MapAccess {

struct ObjectAccess {
obj: ObjectExt,
fields: std::slice::Iter<'static, &'static str>,
fields: std::iter::Enumerate<std::slice::Iter<'static, &'static str>>,
next_value: Option<Deserializer>,
}

impl ObjectAccess {
fn new(obj: ObjectExt, fields: &'static [&'static str]) -> Self {
Self {
obj,
fields: fields.iter(),
fields: fields.iter().enumerate(),
next_value: None,
}
}
}

fn str_deserializer(s: &str) -> de::value::StrDeserializer<Error> {
de::IntoDeserializer::into_deserializer(s)
}

impl<'de> de::MapAccess<'de> for ObjectAccess {
type Error = Error;

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

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

Expand Down Expand Up @@ -127,8 +128,10 @@ impl<'de> de::SeqAccess<'de> for PreservedValueAccess {
match this {
Self::OnMagic(value) => {
*self = Self::OnValue(value);
seed.deserialize(str_deserializer(PRESERVED_VALUE_MAGIC))
.map(Some)
seed.deserialize(de::IntoDeserializer::into_deserializer(
PRESERVED_VALUE_MAGIC,
))
.map(Some)
}
Self::OnValue(value) => seed
.deserialize(Deserializer {
Expand Down

0 comments on commit ce7669e

Please sign in to comment.