Skip to content

Commit

Permalink
fix(serde_v8): support #[serde(default)] (#13300)
Browse files Browse the repository at this point in the history
  • Loading branch information
AaronO committed Jan 7, 2022
1 parent 59f0eaf commit 12423e1
Show file tree
Hide file tree
Showing 2 changed files with 36 additions and 46 deletions.
66 changes: 20 additions & 46 deletions serde_v8/src/de.rs
Original file line number Diff line number Diff line change
Expand Up @@ -375,15 +375,15 @@ impl<'de, 'a, 'b, 's, 'x> de::Deserializer<'de>
// Regular struct
let obj = v8::Local::<v8::Object>::try_from(self.input)
.map_err(|_| Error::ExpectedObject)?;
let map = ObjectAccess {
let struct_access = StructAccess {
fields,
obj,
pos: 0,
scope: self.scope,
_cache: None,
};

visitor.visit_map(map)
visitor.visit_seq(struct_access)
}

/// To be compatible with `serde-json`, we expect enums to be:
Expand Down Expand Up @@ -511,65 +511,39 @@ 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],
pos: usize,
_cache: Option<&'b mut KeyCache>,
}

fn str_deserializer(s: &str) -> de::value::StrDeserializer<Error> {
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<K: de::DeserializeSeed<'de>>(
&mut self,
seed: K,
) -> Result<Option<K::Value>> {
Ok(match self.fields.get(self.pos) {
Some(&field) => Some(seed.deserialize(str_deserializer(field))?),
None => None,
})
}

fn next_value_seed<V: de::DeserializeSeed<'de>>(
fn next_element_seed<T: de::DeserializeSeed<'de>>(
&mut self,
seed: V,
) -> Result<V::Value> {
seed: T,
) -> Result<Option<T::Value>> {
if self.pos >= self.fields.len() {
return Err(Error::LengthMismatch);
return Ok(None);
}
let field = self.fields[self.pos];

let pos = 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<Option<(K::Value, V::Value)>> {
if self.pos >= self.fields.len() {
return Ok(None);
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),
}
let field = self.fields[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)?
})))
}
}

Expand Down
16 changes: 16 additions & 0 deletions serde_v8/tests/de.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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()
}
);

0 comments on commit 12423e1

Please sign in to comment.