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
118
119
120
121
122
123
124
125
126
127
128
129
use super::super::{super::utils::*, attributes::*};
use {deluxe::*, proc_macro2::*, quote::*};
//
// EnumGenerator
//
/// Generator for `#[derive(Resolve)]` on enums.
#[derive(Default)]
pub struct EnumGenerator {
/// Name of the enum for which we are generating.
pub enum_name: TokenStream,
/// The generics of the enum for which we are generating.
pub enum_generics: syn::Generics,
/// Enum-level attribute.
pub enum_attribute: EnumAttribute,
/// The variants that should be selected for.
pub select_variants: Vec<Variant>,
/// Will try to resolve to just this optional variant first as a "single" notation.
pub single_variant: Option<Variant>,
/// Human-readable variant key list.
pub human_readable_key_list: String,
}
impl EnumGenerator {
/// Generate.
pub fn generate(input: &mut syn::DeriveInput) -> syn::Result<TokenStream> {
let generator = Self::new(input)?;
let stream = generator.generate_impl_resolve();
Ok(stream)
}
/// Constructor.
pub fn new(input: &mut syn::DeriveInput) -> syn::Result<Self> {
let mut generator = Self::default();
generator.enum_name = input.ident.to_token_stream();
generator.enum_generics = input.generics.clone();
generator.enum_attribute = extract_attributes(input)?;
match &mut input.data {
syn::Data::Enum(data) => {
for variant in data.variants.iter_mut() {
if attributes_have_ident(&variant.attrs, "resolve") {
match &variant.fields {
syn::Fields::Unnamed(fields) => {
if fields.unnamed.len() != 1 {
return Err(syn::Error::new(
variant.ident.span(),
"`Resolve`: variants with more than 1 unnamed field are not supported",
));
}
}
syn::Fields::Named(_) => {
return Err(syn::Error::new(
variant.ident.span(),
"`Resolve`: variants with named fields are not supported",
));
}
syn::Fields::Unit => {}
}
let variant_attribute: VariantAttribute = extract_attributes(variant)?;
let variant_name = &variant.ident;
let key = match &variant_attribute.key {
Some(key) => key.to_token_stream(),
None => (&variant_name.to_string()).to_token_stream(), // will add quotation marks
};
if variant_attribute.single {
if generator.single_variant.is_some() {
return Err(syn::Error::new(
variant.ident.span(),
"`resolve` attribute: only one variant may specify `single`",
));
} else {
generator.single_variant = Some(Variant {
key: key.clone(),
name: variant_name.to_token_stream(),
has_fields: !variant.fields.is_empty(),
});
}
}
if !generator.human_readable_key_list.is_empty() {
generator.human_readable_key_list += " or ";
}
generator.human_readable_key_list += &key.to_string();
generator.select_variants.push(Variant {
key,
name: variant_name.to_token_stream(),
has_fields: !variant.fields.is_empty(),
});
}
}
}
_ => return Err(syn::Error::new(input.ident.span(), "`Resolve`: not an enum")),
}
Ok(generator)
}
}
//
// Variant
//
/// Generator variant.
pub struct Variant {
// Variant key.
pub key: TokenStream,
/// Variant name.
pub name: TokenStream,
/// Whether the variant has fields.
pub has_fields: bool,
}