Full support for deserializing externally tagged enums

This commit is contained in:
etwyniel
2019-11-18 11:04:11 +01:00
parent 6db11c37cb
commit b7993b516e
2 changed files with 40 additions and 15 deletions

View File

@@ -171,7 +171,7 @@ pub fn unnamed_fields_as_struct(variant: &Variant, fields: &FieldsUnnamed, ident
.collect::<Vec<_>>(); .collect::<Vec<_>>();
let as_struct = quote!{ let as_struct = quote!{
struct #ident { struct #ident {
#(#field_idents: Option<#field_types>,)* #(#field_idents: #field_types,)*
} }
}; };
let de_impl = if fields.unnamed.len() == 1 { let de_impl = if fields.unnamed.len() == 1 {
@@ -184,6 +184,7 @@ pub fn unnamed_fields_as_struct(variant: &Variant, fields: &FieldsUnnamed, ident
} }
} }
} else { } else {
let index = 0usize..;
quote!{ quote!{
struct __Visitor { struct __Visitor {
__out: miniserde::export::Option<#ident>, __out: miniserde::export::Option<#ident>,
@@ -201,23 +202,49 @@ pub fn unnamed_fields_as_struct(variant: &Variant, fields: &FieldsUnnamed, ident
} }
impl miniserde::de::Visitor for __Visitor { impl miniserde::de::Visitor for __Visitor {
fn seq(&mut self) -> miniserde::Result<miniserde::export::Box<dyn miniserde::de::Seq + '_>> {
Ok(miniserde::export::Box::new(__State {
#(#field_idents: None,)*
__state: 0,
__out: &mut self.__out,
}))
}
}
struct __State<'a> {
#(#field_idents: miniserde::export::Option<#field_types>,)*
__state: usize,
__out: &'a mut miniserde::export::Option<#ident>,
}
impl<'a> miniserde::de::Seq for __State<'a> {
fn element(&mut self) -> miniserde::Result<&mut dyn miniserde::de::Visitor> {
let state = self.__state;
self.__state += 1;
match state {
#(#index => Ok(<#field_types as miniserde::Deserialize>::begin(&mut self.#field_idents)),)*
_ => Err(miniserde::Error),
}
}
fn finish(&mut self) -> miniserde::Result<()> {
*self.__out = Some(#ident{
#(#field_idents: match self.#field_idents.take() {
Some(f) => f,
None => return Err(miniserde::Error),
},)*
});
Ok(())
}
} }
} }
}; };
let as_enum = if fields.unnamed.len() == 1 {
quote!{
#enum_ident::#variant_ident(self.__f0.unwrap())
}
} else {
quote!(unimplemented!())
};
Ok(quote!{ Ok(quote!{
#as_struct #as_struct
impl #ident { impl #ident {
fn as_enum(self) -> #enum_ident { fn as_enum(self) -> #enum_ident {
#as_enum #enum_ident::#variant_ident(#(self.#field_idents,)*)
} }
} }

View File

@@ -6,18 +6,16 @@ fn test_external() {
#[derive(Deserialize_enum, Debug, PartialEq)] #[derive(Deserialize_enum, Debug, PartialEq)]
enum External { enum External {
A(i32), A(i32),
// #[serde(rename = "renamedB")] #[serde(rename = "renamedB")]
// B(i32, String), B(i32, String),
C { C {
x: i32, x: i32,
}, },
D, D,
} }
use External::*; use External::*;
// let example = r#"[{"A":21},{"renamedB":[42,"everything"]},{"C":{"x":2}},"D"]"#; let example = r#"[{"A":21},{"renamedB":[42,"everything"]},{"C":{"x":2}},"D"]"#;
let example = r#"[{"A":21},{"C":{"x":2}},"D"]"#;
let actual: Vec<External> = json::from_str(example).unwrap(); let actual: Vec<External> = json::from_str(example).unwrap();
// let expected = [A(21), B(42, "everything".to_string()), C { x: 2 }, D]; let expected = [A(21), B(42, "everything".to_string()), C { x: 2 }, D];
let expected = vec![A(21), C { x: 2 }, D];
assert_eq!(actual, expected); assert_eq!(actual, expected);
} }