yfunc_rust_macro/
lib.rs

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            // to json
20            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            // from json
38            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            // from name
54            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}