Support for serde::Serialize

This commit is contained in:
Pantonshire committed 2021-05-20 18:56:54 +01:00
1 parent 867b09a1fe
commit 46dac98882
6 files changed
+120 -14

No files matched your search

+84 -2
View File
@@ -2,7 +2,6 @@
//! to strings and vice-versa.
use proc_macro::TokenStream;
use std::iter;
use proc_macro2::Ident;
use quote::quote;
@@ -10,7 +9,7 @@ use syn::{Data, DataEnum, DeriveInput};
use error::{MacroError, MacroResult};
use crate::enums::{Variant, VariantType, VariantConstructor};
use crate::enums::{Variant, VariantType};
mod enums;
mod attribute;
@@ -422,6 +421,89 @@ pub fn derive_try_unscribe(input: TokenStream) -> TokenStream {
)
}
#[cfg(feature = "serde")]
#[proc_macro_derive(EnumSerialize, attributes(enumscribe))]
pub fn derive_enum_serialize(input: TokenStream) -> TokenStream {
let input: DeriveInput = syn::parse(input)
.expect("failed to parse input");
let enum_data = proc_try!(get_enum_data(&input));
let parsed_enum = proc_try!(enums::parse_enum(enum_data));
let enum_ident = &input.ident;
let serializer_ident = quote! { __enumscribe_serializer };
let mut match_arms = Vec::new();
let mut ignore_variant = false;
for variant in parsed_enum.variants.iter() {
let variant_ident = &variant.data.ident;
match &variant.v_type {
VariantType::Ignore => ignore_variant = true,
VariantType::Named { name, constructor, .. } => {
let constructor_tokens = constructor.empty();
match_arms.push(quote! {
#enum_ident::#variant_ident #constructor_tokens =>
#serializer_ident.serialize_str(#name)
})
},
VariantType::Other { field_name } => {
match field_name {
Some(field_name) => {
match_arms.push(quote! {
#enum_ident::#variant_ident { #field_name } =>
#serializer_ident.serialize_str(&#field_name)
})
},
None => {
let field_name = quote! { __enumscribe_other_inner };
match_arms.push(quote! {
#enum_ident::#variant_ident(#field_name) =>
#serializer_ident.serialize_str(&#field_name)
})
}
}
}
}
}
let ignore_arm = if ignore_variant {
let err_string = format!(
"attempted to serialize an unserializable variant of {}",
enum_ident
);
quote! {
_ => ::std::result::Result::Err(
::serde::ser::Error::custom(#err_string)
)
}
} else {
quote! {}
};
(quote! {
impl ::serde::Serialize for #enum_ident {
fn serialize<S>(&self, #serializer_ident: S) -> ::std::result::Result<S::Ok, S::Error>
where S: ::serde::Serializer
{
match self {
#(#match_arms,)*
#ignore_arm
}
}
}
}).into()
}
#[cfg(feature = "serde")]
#[proc_macro_derive(EnumDeserialize, attributes(enumscribe))]
pub fn derive_enum_deserialize(input: TokenStream) -> TokenStream {
todo!()
}
fn get_enum_data(input: &DeriveInput) -> MacroResult<&DataEnum> {
let enum_data = match &input.data {
Data::Enum(enum_data) => enum_data,