use proc_macro::TokenStream;
use quote::quote;
use syn::{
parse_macro_input, Data, DataEnum, DataStruct, DeriveInput, Fields, Lifetime, LifetimeParam,
};
#[proc_macro_derive(Serialize)]
pub fn derse_serialize_derive(input: TokenStream) -> TokenStream {
let ast = parse_macro_input!(input as DeriveInput);
let krate = get_crate_name();
let (impl_generics, ty_generics, where_clause) = ast.generics.split_for_impl();
let struct_type = &ast.ident;
let statements = match ast.data {
Data::Struct(DataStruct { fields, .. }) => {
let mut idents = fields
.iter()
.enumerate()
.map(|(i, f)| {
let index = syn::Index::from(i);
f.ident
.as_ref()
.map_or(quote! {#index}, |ident| quote! {#ident})
})
.collect::<Vec<_>>();
idents.reverse();
quote! { #( self.#idents.serialize_to(serializer)?; )* }
}
Data::Enum(DataEnum { variants, .. }) => {
let mut match_statements = Vec::new();
for variant in variants {
let ident = &variant.ident;
let name = ident.to_string();
let match_statement = match variant.fields {
Fields::Named(fields) => {
let mut idents = fields.named.iter().map(|f| &f.ident).collect::<Vec<_>>();
let list = quote! { #(#idents, )* };
idents.reverse();
quote! {
Self::#ident { #list } => {
#( #idents.serialize_to(serializer)?; )*
#name.serialize_to(serializer)?;
}
}
}
Fields::Unnamed(fields) => {
let mut idents = fields
.unnamed
.iter()
.enumerate()
.map(|(i, _)| {
syn::Ident::new(&format!("v{i}"), proc_macro2::Span::call_site())
})
.collect::<Vec<_>>();
let list = quote! { #(#idents, )* };
idents.reverse();
quote! {
Self::#ident ( #list ) => {
#( #idents.serialize_to(serializer)?; )*
#name.serialize_to(serializer)?;
}
}
}
Fields::Unit => quote! {
Self::#ident => {
#name.serialize_to(serializer)?;
}
},
};
match_statements.push(match_statement);
}
quote! {
match self {
#(#match_statements)*
}
}
}
_ => panic!("only struct and enum are supported"),
};
quote! {
impl #impl_generics #krate::Serialize for #struct_type #ty_generics #where_clause {
fn serialize_to<Serializer: #krate::Serializer>(&self, serializer: &mut Serializer) -> #krate::Result<()> {
let start = serializer.len();
#statements
let len = serializer.len() - start;
#krate::VarInt64(len as u64).serialize_to(serializer)
}
}
}.into()
}
#[proc_macro_derive(Deserialize)]
pub fn derse_deserialize_derive(input: TokenStream) -> TokenStream {
let ast = parse_macro_input!(input as DeriveInput);
let krate = get_crate_name();
let (impl_generics, ty_generics, where_clause) = ast.generics.split_for_impl();
let mut generics = ast.generics.clone();
let (impl_generics, lifetime) = if let Some(lifetime) = ast.generics.lifetimes().next().cloned()
{
(impl_generics, quote! { #lifetime })
} else {
let lifetime = Lifetime::new("'derse", proc_macro2::Span::call_site());
let lifetime_param = LifetimeParam::new(lifetime.clone());
let generic_param = syn::GenericParam::Lifetime(lifetime_param);
generics.params.insert(0, generic_param);
let (impl_generics, _, _) = generics.split_for_impl();
(impl_generics, quote! { #lifetime })
};
let struct_type = &ast.ident;
let struct_name = struct_type.to_string();
let deserialize_statements = match ast.data {
Data::Struct(DataStruct { fields, .. }) => {
let statements = fields
.iter()
.map(|f| {
let statement = quote! {
if buf.is_empty() {
Default::default()
} else {
derse::Deserialize::deserialize_from(buf)?
}
};
f.ident
.as_ref()
.map_or(statement.clone(), |ident| quote! {#ident: #statement})
})
.collect::<Vec<_>>();
match fields {
Fields::Named(_) => quote! { let result = Self { #(#statements, )* }; },
Fields::Unnamed(_) => quote! { let result = Self ( #(#statements, )* ); },
Fields::Unit => quote! { let result = Self; },
}
}
Data::Enum(DataEnum { variants, .. }) => {
let mut match_statements = Vec::new();
for variant in variants {
let ident = &variant.ident;
let variant_name = ident.to_string();
let statements = variant
.fields
.iter()
.map(|f| {
let statement = quote! {
if buf.is_empty() {
Default::default()
} else {
derse::Deserialize::deserialize_from(buf)?
}
};
f.ident
.as_ref()
.map_or(statement.clone(), |ident| quote! {#ident: #statement})
})
.collect::<Vec<_>>();
let match_statement = match variant.fields {
Fields::Named(_) => {
quote! { #variant_name => Self::#ident { #(#statements, )* }, }
}
Fields::Unnamed(_) => {
quote! { #variant_name => Self::#ident ( #(#statements, )* ), }
}
Fields::Unit => quote! { #variant_name => Self::#ident, },
};
match_statements.push(match_statement);
}
quote! {
let ty = <&str>::deserialize_from(buf)?;
let result = match ty {
#(#match_statements)*
_ => return Err(derse::Error::InvalidType(format!("{}::{}", #struct_name, ty))),
};
}
}
_ => panic!("only struct and enum are supported"),
};
quote! {
impl #impl_generics #krate::DetailedDeserialize<#lifetime> for #struct_type #ty_generics #where_clause {
fn deserialize_len<Deserializer: #krate::Deserializer<#lifetime>>(buf: &mut Deserializer) -> #krate::Result<usize> {
use #krate::Deserialize;
Ok(#krate::VarInt64::deserialize_from(buf)?.0 as usize)
}
fn deserialize_fields<Deserializer: #krate::Deserializer<#lifetime>>(buf: &mut Deserializer) -> #krate::Result<Self>
where
Self: Sized,
{
use #krate::Deserialize;
#deserialize_statements
Ok(result)
}
}
impl #impl_generics #krate::Deserialize<#lifetime> for #struct_type #ty_generics #where_clause {
fn deserialize_from<Deserializer: #krate::Deserializer<#lifetime>>(buf: &mut Deserializer) -> #krate::Result<Self>
where
Self: Sized,
{
use #krate::DetailedDeserialize;
let len = Self::deserialize_len(buf)?;
let mut buf = buf.advance(len)?;
Self::deserialize_fields(&mut buf)
}
}
}.into()
}
pub(crate) fn get_crate_name() -> proc_macro2::TokenStream {
let found_crate = proc_macro_crate::crate_name("derse").unwrap_or_else(|err| {
eprintln!("Warning: {}\n => defaulting to `crate`", err,);
proc_macro_crate::FoundCrate::Itself
});
match found_crate {
proc_macro_crate::FoundCrate::Itself => quote! { crate },
proc_macro_crate::FoundCrate::Name(name) => {
let ident = syn::Ident::new(&name, proc_macro2::Span::call_site());
quote! { ::#ident }
}
}
}