1#![allow(non_snake_case)]
2#![allow(non_upper_case_globals)]
3#![allow(unused)]
4
5extern crate proc_macro;
6use proc_macro::TokenStream;
7use quote::quote;
8use syn::{parse_macro_input, Attribute, Data, DeriveInput, Fields};
9
10#[proc_macro_attribute]
11pub fn yfunc(attr: TokenStream, input: TokenStream) -> TokenStream {
12 let input = parse_macro_input!(input as DeriveInput);
13 let class_name = &input.ident;
14 let generics = input.generics.clone();
15 let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
16 let mut generated_token = quote! {};
17 match &input.data {
18 Data::Struct(data) => {
19 let token__to_json = quote! {
21 impl #impl_generics #class_name #ty_generics #where_clause {
22 pub fn to_json_str(&self) -> YRes<String> {
23 serde_json::to_string(self).map_err(|e|
24 err!("failed to serialize {} to json string", stringify!(#class_name)).trace(ctx!(e))
25 )
26 }
27 pub fn to_pretty_json_str(&self) -> YRes<String> {
28 serde_json::to_string_pretty(self).map_err(|e|
29 err!("failed to serialize {} to pretty json string", stringify!(#class_name)).trace(ctx!(e))
30 )
31 }
32 }
33 };
34 if input.attrs.iter().any(|it| has_derive(it, "Serialize")) {
35 generated_token.extend(token__to_json);
36 }
37 let token__from_json = quote! {
39 impl #impl_generics #class_name #ty_generics #where_clause {
40 pub fn from_json_str(json_string: &str) -> YRes<Self> {
41 Ok(serde_json::from_str(json_string).map_err(|e|
42 err!("failed to deserialize json string to {}", stringify!(#class_name)).trace(ctx!(e))
43 )?)
44 }
45 }
46 };
47 if input.attrs.iter().any(|it| has_derive(it, "Deserialize")) {
48 generated_token.extend(token__from_json);
49 }
50 },
51 Data::Enum(data) => {
52 let variants = &data.variants;
53 let tokens__from_name__match_variant = variants.iter().filter_map(|variant| {
55 let variant_name = &variant.ident;
56 match &variant.fields {
57 Fields::Unit => Some(quote! { stringify!(#variant_name) => Ok(#class_name::#variant_name), }),
58 _ => None,
59 }
60 });
61 let token__from_name = quote! {
62 impl #impl_generics #class_name #ty_generics #where_clause {
63 pub fn from_name(variant_name: &str) -> YRes<Self> {
64 match variant_name {
65 #(#tokens__from_name__match_variant)*
66 _ => Err(err!("enum {} has no variant called {}", stringify!(#class_name), variant_name)),
67 }
68 }
69 }
70 };
71 generated_token.extend(token__from_name);
72 },
73 Data::Union(data) => {},
74 }
75 let output = quote! {
76 #input
77 #generated_token
78 };
79 TokenStream::from(output)
80}
81
82fn has_derive(attr: &Attribute, name: &str) -> bool {
83 if !attr.path().is_ident("derive") {
84 return false;
85 }
86 let mut ret = false;
87 let _ = attr.parse_nested_meta(|meta| {
88 if meta.path.is_ident(name) {
89 ret = true;
90 }
91 Ok(())
92 });
93 ret
94}