diff --git a/serde_v8/src/de.rs b/serde_v8/src/de.rs index 44f94b2d6e..24023b05dd 100644 --- a/serde_v8/src/de.rs +++ b/serde_v8/src/de.rs @@ -375,7 +375,7 @@ impl<'de, 'a, 'b, 's, 'x> de::Deserializer<'de> // Regular struct let obj = v8::Local::::try_from(self.input) .map_err(|_| Error::ExpectedObject)?; - let map = ObjectAccess { + let struct_access = StructAccess { fields, obj, pos: 0, @@ -383,7 +383,7 @@ impl<'de, 'a, 'b, 's, 'x> de::Deserializer<'de> _cache: None, }; - visitor.visit_map(map) + visitor.visit_seq(struct_access) } /// To be compatible with `serde-json`, we expect enums to be: @@ -511,7 +511,7 @@ impl<'de> de::MapAccess<'de> for MapAccess<'_, '_, '_> { } } -struct ObjectAccess<'a, 'b, 's> { +struct StructAccess<'a, 'b, 's> { obj: v8::Local<'a, v8::Object>, scope: &'b mut v8::HandleScope<'s>, fields: &'static [&'static str], @@ -519,57 +519,31 @@ struct ObjectAccess<'a, 'b, 's> { _cache: Option<&'b mut KeyCache>, } -fn str_deserializer(s: &str) -> de::value::StrDeserializer { - de::IntoDeserializer::into_deserializer(s) -} - -impl<'de, 'a, 'b, 's> de::MapAccess<'de> for ObjectAccess<'a, 'b, 's> { +impl<'de> de::SeqAccess<'de> for StructAccess<'_, '_, '_> { type Error = Error; - fn next_key_seed>( + fn next_element_seed>( &mut self, - seed: K, - ) -> Result> { - Ok(match self.fields.get(self.pos) { - Some(&field) => Some(seed.deserialize(str_deserializer(field))?), - None => None, - }) - } - - fn next_value_seed>( - &mut self, - seed: V, - ) -> Result { - if self.pos >= self.fields.len() { - return Err(Error::LengthMismatch); - } - let field = self.fields[self.pos]; - self.pos += 1; - let key = v8_struct_key(self.scope, field).into(); - let v8_val = self.obj.get(self.scope, key).unwrap(); - let mut deserializer = Deserializer::new(self.scope, v8_val, None); - seed.deserialize(&mut deserializer) - } - - fn next_entry_seed< - K: de::DeserializeSeed<'de>, - V: de::DeserializeSeed<'de>, - >( - &mut self, - kseed: K, - vseed: V, - ) -> Result> { + seed: T, + ) -> Result> { if self.pos >= self.fields.len() { return Ok(None); } - let field = self.fields[self.pos]; + + let pos = self.pos; self.pos += 1; - Ok(Some((kseed.deserialize(str_deserializer(field))?, { - let key = v8_struct_key(self.scope, field).into(); - let v8_val = self.obj.get(self.scope, key).unwrap(); - let mut deserializer = Deserializer::new(self.scope, v8_val, None); - vseed.deserialize(&mut deserializer)? - }))) + + let field = self.fields[pos]; + let key = v8_struct_key(self.scope, field).into(); + let val = self.obj.get(self.scope, key).unwrap(); + let mut deserializer = Deserializer::new(self.scope, val, None); + match seed.deserialize(&mut deserializer) { + Ok(val) => Ok(Some(val)), + // Fallback to Ok(None) for #[serde(Default)] at cost of error quality ... + // TODO(@AaronO): double check that there's no better solution + Err(_) if val.is_undefined() => Ok(None), + Err(e) => Err(e), + } } } diff --git a/serde_v8/tests/de.rs b/serde_v8/tests/de.rs index fee5325186..da850b579f 100644 --- a/serde_v8/tests/de.rs +++ b/serde_v8/tests/de.rs @@ -271,3 +271,19 @@ detest!(de_bigint_i64, i64, "BigInt(-(2**59))", -(1 << 59)); defail!(defail_struct, MathOp, "123", |e| e == Err(Error::ExpectedObject)); + +#[derive(PartialEq, Debug, Deserialize)] +pub struct SomeThing { + pub a: String, + #[serde(default)] + pub b: String, +} +detest!( + de_struct_defaults, + SomeThing, + "({ a: 'hello' })", + SomeThing { + a: "hello".into(), + b: "".into() + } +);