1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
use proc_macro::TokenStream;
use quote::{quote, ToTokens};
use syn::{punctuated::Punctuated, Data, Lit, Meta, MetaNameValue, Token};
use syn::{DeriveInput, Expr};
use crate::utils::{non_enum_error, non_serde_rename_error};
pub(crate) fn derive_all_variants_renamings_inner(input: DeriveInput) -> syn::Result<TokenStream> {
let struct_identifier = &input.ident;
let mut implementation = quote! {
let mut variants: Vec<String> = Vec::new();
};
// search for only inputs that are enums
match input.data {
Data::Enum(d) => {
// iterate over variants that have attributes serde, if there is no serde attribute with rename field, return an error
for v in d.variants.iter() {
let mut renamed_variant_name = Option::<String>::None;
for attr in v.attrs.iter() {
if attr.path.is_ident("serde") {
let nested =
attr.parse_args_with(Punctuated::<Meta, Token![,]>::parse_terminated)?;
for meta in nested {
match meta {
Meta::NameValue(MetaNameValue {
path,
lit: Lit::Str(string_literal),
..
}) if path.is_ident("rename") => {
renamed_variant_name = Some(string_literal.value());
}
_ => {}
}
}
}
if let Some(ref variant_name) = renamed_variant_name {
implementation.extend(quote! {
variants.push(#variant_name.to_string());
});
} else {
return Err(non_serde_rename_error());
}
}
}
}
_ => return Err(non_enum_error()),
}
Ok(quote! {impl #struct_identifier {
pub fn all_variants_serde_renames() -> Vec<String>{
#implementation
variants
}
}}
.into())
}
pub(crate) fn derive_variant_name_inner(input: DeriveInput) -> syn::Result<TokenStream> {
let enum_identifier = &input.ident;
let mut variants_cases = Vec::new();
let mut variants_names = Vec::new();
match input.data {
Data::Enum(d) => {
// iterate over variants that have attributes serde, if there is no serde attribute with rename field, return an error
for v in d.variants.iter() {
let mut renamed_variant_name = Option::<String>::None;
for attr in v.attrs.iter() {
if attr.path.is_ident("serde") {
let nested =
attr.parse_args_with(Punctuated::<Meta, Token![,]>::parse_terminated)?;
for meta in nested {
match meta {
Meta::NameValue(MetaNameValue {
path,
lit: Lit::Str(string_literal),
..
}) if path.is_ident("rename") => {
renamed_variant_name = Some(string_literal.value());
}
_ => {}
}
}
}
if let Some(ref variant_name) = renamed_variant_name {
match v.fields {
syn::Fields::Unit => variants_cases.push(v.ident.to_token_stream()),
_ => {
variants_cases.push(
syn::parse_str::<Expr>(&format!("{}(_)", v.ident))?
.to_token_stream(),
);
}
}
variants_names.push(variant_name.clone());
} else {
return Err(non_serde_rename_error());
}
}
}
}
_ => return Err(non_enum_error()),
}
let expanded = quote! {
impl #enum_identifier {
pub fn variant_name(&self) -> &str {
match self {
#(#enum_identifier::#variants_cases => #variants_names),*
}
}
}
};
Ok(expanded.into())
}