#![allow(non_snake_case)]
#![allow(non_upper_case_globals)]
#![allow(unused)]
extern crate proc_macro;
use proc_macro::TokenStream;
use quote::quote;
use syn::{parse_macro_input, Attribute, Data, DeriveInput, Fields};
#[proc_macro_attribute]
pub fn yfunc(attr: TokenStream, input: TokenStream) -> TokenStream {
let input = parse_macro_input!(input as DeriveInput);
let class_name = &input.ident;
let generics = input.generics.clone();
let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
let mut generated_token = quote! {};
match &input.data {
Data::Struct(data) => {
let token__to_json = quote! {
impl #impl_generics #class_name #ty_generics #where_clause {
pub fn to_json_str(&self) -> YRes<String> {
serde_json::to_string(self).map_err(|e|
err!("failed to serialize {} to json string", stringify!(#class_name)).trace(ctx!(e))
)
}
pub fn to_pretty_json_str(&self) -> YRes<String> {
serde_json::to_string_pretty(self).map_err(|e|
err!("failed to serialize {} to pretty json string", stringify!(#class_name)).trace(ctx!(e))
)
}
}
};
if input.attrs.iter().any(|it| has_derive(it, "Serialize")) {
generated_token.extend(token__to_json);
}
let token__from_json = quote! {
impl #impl_generics #class_name #ty_generics #where_clause {
pub fn from_json_str(json_string: &str) -> YRes<Self> {
Ok(serde_json::from_str(json_string).map_err(|e|
err!("failed to deserialize json string to {}", stringify!(#class_name)).trace(ctx!(e))
)?)
}
}
};
if input.attrs.iter().any(|it| has_derive(it, "Deserialize")) {
generated_token.extend(token__from_json);
}
},
Data::Enum(data) => {
let variants = &data.variants;
let tokens__from_name__match_variant = variants.iter().filter_map(|variant| {
let variant_name = &variant.ident;
match &variant.fields {
Fields::Unit => Some(quote! { stringify!(#variant_name) => Ok(#class_name::#variant_name), }),
_ => None,
}
});
let token__from_name = quote! {
impl #impl_generics #class_name #ty_generics #where_clause {
pub fn from_name(variant_name: &str) -> YRes<Self> {
match variant_name {
#(#tokens__from_name__match_variant)*
_ => Err(err!("enum {} has no variant called {}", stringify!(#class_name), variant_name)),
}
}
}
};
generated_token.extend(token__from_name);
},
Data::Union(data) => {},
}
let output = quote! {
#input
#generated_token
};
TokenStream::from(output)
}
fn has_derive(attr: &Attribute, name: &str) -> bool {
if !attr.path().is_ident("derive") {
return false;
}
let mut ret = false;
let _ = attr.parse_nested_meta(|meta| {
if meta.path.is_ident(name) {
ret = true;
}
Ok(())
});
ret
}