1
0
Fork 0
mirror of https://github.com/denoland/deno.git synced 2024-11-25 15:29:32 -05:00

fix(serde_v8): support #[serde(default)] (#13300)

This commit is contained in:
Aaron O'Mullan 2022-01-07 13:07:58 +01:00 committed by GitHub
parent 59f0eafd19
commit 12423e16b7
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 37 additions and 47 deletions

View file

@ -375,7 +375,7 @@ impl<'de, 'a, 'b, 's, 'x> de::Deserializer<'de>
// Regular struct // Regular struct
let obj = v8::Local::<v8::Object>::try_from(self.input) let obj = v8::Local::<v8::Object>::try_from(self.input)
.map_err(|_| Error::ExpectedObject)?; .map_err(|_| Error::ExpectedObject)?;
let map = ObjectAccess { let struct_access = StructAccess {
fields, fields,
obj, obj,
pos: 0, pos: 0,
@ -383,7 +383,7 @@ impl<'de, 'a, 'b, 's, 'x> de::Deserializer<'de>
_cache: None, _cache: None,
}; };
visitor.visit_map(map) visitor.visit_seq(struct_access)
} }
/// To be compatible with `serde-json`, we expect enums to be: /// 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>, obj: v8::Local<'a, v8::Object>,
scope: &'b mut v8::HandleScope<'s>, scope: &'b mut v8::HandleScope<'s>,
fields: &'static [&'static str], fields: &'static [&'static str],
@ -519,57 +519,31 @@ struct ObjectAccess<'a, 'b, 's> {
_cache: Option<&'b mut KeyCache>, _cache: Option<&'b mut KeyCache>,
} }
fn str_deserializer(s: &str) -> de::value::StrDeserializer<Error> { impl<'de> de::SeqAccess<'de> for StructAccess<'_, '_, '_> {
de::IntoDeserializer::into_deserializer(s)
}
impl<'de, 'a, 'b, 's> de::MapAccess<'de> for ObjectAccess<'a, 'b, 's> {
type Error = Error; type Error = Error;
fn next_key_seed<K: de::DeserializeSeed<'de>>( fn next_element_seed<T: de::DeserializeSeed<'de>>(
&mut self, &mut self,
seed: K, seed: T,
) -> Result<Option<K::Value>> { ) -> Result<Option<T::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>>(
&mut self,
seed: V,
) -> Result<V::Value> {
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<Option<(K::Value, V::Value)>> {
if self.pos >= self.fields.len() { if self.pos >= self.fields.len() {
return Ok(None); return Ok(None);
} }
let field = self.fields[self.pos];
let pos = self.pos;
self.pos += 1; self.pos += 1;
Ok(Some((kseed.deserialize(str_deserializer(field))?, {
let key = v8_struct_key(self.scope, field).into(); let field = self.fields[pos];
let v8_val = self.obj.get(self.scope, key).unwrap(); let key = v8_struct_key(self.scope, field).into();
let mut deserializer = Deserializer::new(self.scope, v8_val, None); let val = self.obj.get(self.scope, key).unwrap();
vseed.deserialize(&mut deserializer)? 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),
}
} }
} }

View file

@ -271,3 +271,19 @@ detest!(de_bigint_i64, i64, "BigInt(-(2**59))", -(1 << 59));
defail!(defail_struct, MathOp, "123", |e| e defail!(defail_struct, MathOp, "123", |e| e
== Err(Error::ExpectedObject)); == 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()
}
);