diff --git a/src/de.rs b/src/de.rs index b418c0c..30114e6 100644 --- a/src/de.rs +++ b/src/de.rs @@ -1,15 +1,21 @@ use crate::attr; -use crate::TagType; use crate::bound; +use crate::TagType; use proc_macro2::{Span, TokenStream}; use quote::quote; -use syn::{DataEnum, DeriveInput, Ident, Error, Fields, FieldsUnnamed, Result, parse_quote, Variant}; +use syn::{ + parse_quote, DataEnum, DeriveInput, Error, Fields, FieldsNamed, FieldsUnnamed, Ident, Result, + Variant, +}; pub fn derive(input: &DeriveInput, enumeration: &DataEnum) -> Result { let tag_type = attr::tag_type(&input.attrs, &enumeration)?; match &tag_type { TagType::External => deserialize_external(input, enumeration), - _ => Err(Error::new(Span::call_site(), "Only externally tagged enums are supported")), + _ => Err(Error::new( + Span::call_site(), + "Only externally tagged enums are supported", + )), } } @@ -22,13 +28,22 @@ pub fn deserialize_external(input: &DeriveInput, enumeration: &DataEnum) -> Resu let bound = parse_quote!(miniserde::Deserialize); let bounded_where_clause = bound::where_clause_with_bound(&input.generics, bound); - let (unit_variants, struct_variants): (Vec<_>, Vec<_>) = enumeration - .variants - .iter() - .partition(|v| if let Fields::Unit = &v.fields {true} else {false}); + let (unit_variants, struct_variants): (Vec<_>, Vec<_>) = + enumeration.variants.iter().partition(|v| { + if let Fields::Unit = &v.fields { + true + } else { + false + } + }); let struct_names = struct_variants .iter() - .map(|variant| Ident::new(&format!("__{}_{}_Struct", ident, variant.ident), Span::call_site())) + .map(|variant| { + Ident::new( + &format!("__{}_{}_Struct", ident, variant.ident), + Span::call_site(), + ) + }) .collect::>(); let struct_variant_names = struct_variants .iter() @@ -44,17 +59,14 @@ pub fn deserialize_external(input: &DeriveInput, enumeration: &DataEnum) -> Resu .zip(struct_names.iter()) .map(|(variant, ident)| variant_as_struct(variant, ident, &input.ident)) .collect::>>()?; - let unit_variant_idents = unit_variants - .iter() - .map(|v| &v.ident) - .collect::>(); + let unit_variant_idents = unit_variants.iter().map(|v| &v.ident).collect::>(); let unit_variant_names = unit_variants .iter() .cloned() .map(attr::name_of_variant) .collect::>>()?; - Ok(quote!{ + Ok(quote! { const _: () = { struct __Visitor #impl_generics #where_clause { __out: miniserde::export::Option<#ident #ty_generics>, @@ -123,21 +135,34 @@ pub fn deserialize_external(input: &DeriveInput, enumeration: &DataEnum) -> Resu }) } -pub fn variant_as_struct(variant: &Variant, ident: &Ident, enum_ident: &Ident) -> Result { +pub fn variant_as_struct( + variant: &Variant, + ident: &Ident, + enum_ident: &Ident, +) -> Result { + match &variant.fields { + Fields::Named(fields) => named_fields_as_struct(variant, fields, ident, enum_ident), + Fields::Unnamed(fields) => unnamed_fields_as_struct(variant, fields, ident, enum_ident), + _ => unreachable!(), + } +} + +pub fn named_fields_as_struct( + variant: &Variant, + fields: &FieldsNamed, + ident: &Ident, + enum_ident: &Ident, +) -> Result { let variant_ident = &variant.ident; - let as_enum = match &variant.fields { - Fields::Named(fields) => { - let fieldname = fields.named.iter().map(|f| &f.ident).collect::>(); - quote!{ - #enum_ident::#variant_ident { - #( - #fieldname: self.#fieldname, + let as_enum = { + let fieldname = fields.named.iter().map(|f| &f.ident).collect::>(); + quote! { + #enum_ident::#variant_ident { + #( + #fieldname: self.#fieldname, )* - } } } - Fields::Unnamed(fields) => return unnamed_fields_as_struct(variant, fields, ident, enum_ident), - _ => quote!(unimplemented!()), }; let as_struct = syn::ItemStruct { attrs: variant.attrs.clone(), @@ -148,7 +173,7 @@ pub fn variant_as_struct(variant: &Variant, ident: &Ident, enum_ident: &Ident) - fields: variant.fields.clone(), semi_token: None, }; - Ok(quote!{ + Ok(quote! { #[derive(Deserialize)] #as_struct @@ -160,23 +185,25 @@ pub fn variant_as_struct(variant: &Variant, ident: &Ident, enum_ident: &Ident) - }) } -pub fn unnamed_fields_as_struct(variant: &Variant, fields: &FieldsUnnamed, ident: &Ident, enum_ident: &Ident) -> Result { +pub fn unnamed_fields_as_struct( + variant: &Variant, + fields: &FieldsUnnamed, + ident: &Ident, + enum_ident: &Ident, +) -> Result { let variant_ident = &variant.ident; let field_idents = (0..fields.unnamed.len()) .map(|x| Ident::new(&format!("__f{}", x), Span::call_site())) .collect::>(); - let field_types = fields.unnamed - .iter() - .map(|f| &f.ty) - .collect::>(); - let as_struct = quote!{ + let field_types = fields.unnamed.iter().map(|f| &f.ty).collect::>(); + let as_struct = quote! { struct #ident { #(#field_idents: #field_types,)* } }; let de_impl = if fields.unnamed.len() == 1 { let ty = field_types[0]; - quote!{ + quote! { impl miniserde::Deserialize for #ident { fn begin(__out: &mut miniserde::export::Option) -> &mut dyn miniserde::de::Visitor { <#ty as miniserde::Deserialize>::begin(unsafe {&mut *{__out as *mut miniserde::export::Option as *mut miniserde::export::Option<#ty>}}) @@ -185,7 +212,7 @@ pub fn unnamed_fields_as_struct(variant: &Variant, fields: &FieldsUnnamed, ident } } else { let index = 0usize..; - quote!{ + quote! { struct __Visitor { __out: miniserde::export::Option<#ident>, } @@ -239,7 +266,7 @@ pub fn unnamed_fields_as_struct(variant: &Variant, fields: &FieldsUnnamed, ident } } }; - Ok(quote!{ + Ok(quote! { #as_struct impl #ident { diff --git a/src/lib.rs b/src/lib.rs index fc33d5d..23f408e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,9 +1,9 @@ extern crate proc_macro; pub(crate) mod attr; -mod ser; -mod de; mod bound; +mod de; +mod ser; use std::convert::From; use syn::{parse_macro_input, Data, DeriveInput, Error}; diff --git a/src/ser.rs b/src/ser.rs index 13ea481..4ef55f3 100644 --- a/src/ser.rs +++ b/src/ser.rs @@ -1,9 +1,9 @@ use crate::attr; -use crate::TagType; use crate::bound; +use crate::TagType; use proc_macro2::{Span, TokenStream}; use quote::quote; -use syn::{DataEnum, DeriveInput, Ident, Fields, FieldsNamed, FieldsUnnamed, Result, parse_quote}; +use syn::{parse_quote, DataEnum, DeriveInput, Fields, FieldsNamed, FieldsUnnamed, Ident, Result}; pub fn derive(input: &DeriveInput, enumeration: &DataEnum) -> Result { let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl(); @@ -23,7 +23,7 @@ pub fn derive(input: &DeriveInput, enumeration: &DataEnum) -> Result { let implementation = serialize_unit(name, &tag_type)?; - quote!{ + quote! { #ident::#var_ident => {#implementation} } } @@ -35,7 +35,7 @@ pub fn derive(input: &DeriveInput, enumeration: &DataEnum) -> Result>(); - quote!{ + quote! { #ident::#var_ident{#(#field_ident),*} => { #implementation } @@ -46,17 +46,19 @@ pub fn derive(input: &DeriveInput, enumeration: &DataEnum) -> Result>(); - let implementation = serialize_unnamed(input, fields, &field_ident, name, &tag_type)?; - quote!{ + let implementation = + serialize_unnamed(input, fields, &field_ident, name, &tag_type)?; + quote! { #ident::#var_ident(#(#field_ident),*) => { #implementation } } } }) - }).collect::>>()?; + }) + .collect::>>()?; - Ok(quote!{ + Ok(quote! { const _: () = { impl #impl_generics miniserde::Serialize for #ident #ty_generics #where_clause { fn begin(&self) -> miniserde::ser::Fragment { @@ -71,7 +73,7 @@ pub fn derive(input: &DeriveInput, enumeration: &DataEnum) -> Result Result { Ok(if let TagType::Internal(tag) = &tag_type { - quote!{ + quote! { struct __Map { state: miniserde::export::usize, } @@ -93,7 +95,7 @@ fn serialize_unit(variant_name: &str, tag_type: &TagType) -> Result miniserde::ser::Fragment::Map(miniserde::export::Box::new(__Map {state: 0})) } } else { - quote!{miniserde::ser::Fragment::Str(miniserde::export::Cow::Borrowed(#variant_name))} + quote! {miniserde::ser::Fragment::Str(miniserde::export::Cow::Borrowed(#variant_name))} }) } @@ -126,7 +128,7 @@ fn serialize_named( let cow = quote!(miniserde::export::Cow); let some = quote!(miniserde::export::Some); if let TagType::External = tag_type { - Ok(quote!{ + Ok(quote! { use miniserde::Serialize; #[derive(Serialize)] struct __AsStruct #wrapper_impl_generics #where_clause { @@ -156,12 +158,15 @@ fn serialize_named( }) } else { let (start, tag_arm) = if let TagType::Internal(ref tag) = &tag_type { - (0, quote!{0 => #some((#cow::Borrowed(#tag), &#variant_name)),}) + ( + 0, + quote! {0 => #some((#cow::Borrowed(#tag), &#variant_name)),}, + ) } else { (1usize, quote!()) }; let index = 1usize..; - Ok(quote!{ + Ok(quote! { struct __Map #wrapper_impl_generics { #(#field_ident: &'__b #field_type),*, state: miniserde::export::usize, @@ -212,9 +217,9 @@ fn serialize_unnamed( let index = 0usize..; let ex = quote!(miniserde::export); let seq = if field_ident.len() == 1 { - quote!{ #(#field_ident.begin())* } + quote! { #(#field_ident.begin())* } } else { - quote!{ + quote! { struct __Seq #wrapper_impl_generics #where_clause { #(#field_ident: &'__b #field_type),*, state: miniserde::export::usize, @@ -238,7 +243,7 @@ fn serialize_unnamed( } }; Ok(if let TagType::External = tag_type { - quote!{ + quote! { struct __AsStruct #wrapper_impl_generics (#(&'__b #field_type),*) #where_clause; impl #wrapper_impl_generics miniserde::Serialize for __AsStruct #wrapper_ty_generics #bounded_where_clause { @@ -269,7 +274,7 @@ fn serialize_unnamed( })) } } else { - quote!{ + quote! { #seq } }) diff --git a/tests/serialize.rs b/tests/serialize.rs index 9009d2f..a163f0e 100644 --- a/tests/serialize.rs +++ b/tests/serialize.rs @@ -63,11 +63,11 @@ fn test_untagged() { fn generic_named() { #[derive(Serialize_enum)] enum Gen { - A{t: T}, + A { t: T }, B, } use Gen::*; - let example = [A{t: "abc"}, B]; + let example = [A { t: "abc" }, B]; let actual = json::to_string(&example[..]); let expected = r#"[{"A":{"t":"abc"}},"B"]"#; assert_eq!(actual, expected);