1use std::ops::Deref;
2
3use syn::{self, DeriveInput};
4use quote::ToTokens;
5
6use proc_macro2::TokenStream;
7use field::{Field, Fields, FieldsKind};
8
9#[derive(Debug, Clone)]
10pub enum ItemInput {
11 Struct(syn::ItemStruct),
12 Enum(syn::ItemEnum),
13 Union(syn::ItemUnion),
14}
15
16impl From<DeriveInput> for ItemInput {
17 fn from(input: DeriveInput) -> Self {
18 match input.data {
19 syn::Data::Struct(v) => {
20 ItemInput::Struct(syn::ItemStruct {
21 attrs: input.attrs,
22 vis: input.vis,
23 struct_token: v.struct_token,
24 ident: input.ident,
25 generics: input.generics,
26 fields: v.fields,
27 semi_token: v.semi_token,
28 })
29 }
30 syn::Data::Enum(v) => {
31 ItemInput::Enum(syn::ItemEnum {
32 attrs: input.attrs,
33 vis: input.vis,
34 enum_token: v.enum_token,
35 ident: input.ident,
36 generics: input.generics,
37 brace_token: v.brace_token,
38 variants: v.variants,
39 })
40 }
41 syn::Data::Union(v) => {
42 ItemInput::Union(syn::ItemUnion {
43 attrs: input.attrs,
44 vis: input.vis,
45 ident: input.ident,
46 generics: input.generics,
47 union_token: v.union_token,
48 fields: v.fields,
49 })
50 }
51 }
52 }
53}
54
55macro_rules! getter {
56 ($name:ident -> [$($kind:tt)*] $field:ident $T:ty) => (
57 pub fn $name($($kind)* self) -> $T {
58 match self {
59 ItemInput::Struct(v) => $($kind)* v.$field,
60 ItemInput::Enum(v) => $($kind)* v.$field,
61 ItemInput::Union(v) => $($kind)* v.$field,
62 }
63 }
64 )
65}
66
67impl ItemInput {
68 getter!(attrs -> [&] attrs &[syn::Attribute]);
69 getter!(attrs_mut -> [&mut] attrs &mut Vec<syn::Attribute>);
70 getter!(vis -> [&] vis &syn::Visibility);
71 getter!(vis_mut -> [&mut] vis &mut syn::Visibility);
72 getter!(ident -> [&] ident &syn::Ident);
73 getter!(ident_mut -> [&mut] ident &mut syn::Ident);
74 getter!(generics -> [&] generics &syn::Generics);
75 getter!(generics_mut -> [&mut] generics &mut syn::Generics);
76}
77
78impl ToTokens for ItemInput {
79 fn to_tokens(&self, tokens: &mut TokenStream) {
80 match self {
81 ItemInput::Struct(v) => v.to_tokens(tokens),
82 ItemInput::Enum(v) => v.to_tokens(tokens),
83 ItemInput::Union(v) => v.to_tokens(tokens),
84 }
85 }
86}
87
88#[derive(Debug, Copy, Clone)]
89pub enum Input<'v> {
90 Struct(Struct<'v>),
91 Enum(Enum<'v>),
92 Union(Union<'v>)
93}
94
95impl<'v> From<&'v ItemInput> for Input<'v> {
96 fn from(input: &'v ItemInput) -> Self {
97 match input {
98 ItemInput::Struct(v) => Input::Struct(Derived::from(&v, input)),
99 ItemInput::Enum(v) => Input::Enum(Derived::from(&v, input)),
100 ItemInput::Union(v) => Input::Union(Derived::from(&v, input)),
101 }
102 }
103}
104
105impl ToTokens for Input<'_> {
106 fn to_tokens(&self, tokens: &mut TokenStream) {
107 match self {
108 Input::Struct(v) => v.parent.to_tokens(tokens),
109 Input::Enum(v) => v.parent.to_tokens(tokens),
110 Input::Union(v) => v.parent.to_tokens(tokens),
111 }
112 }
113}
114
115impl Deref for Input<'_> {
116 type Target = ItemInput;
117
118 fn deref(&self) -> &Self::Target {
119 match self {
120 Input::Struct(v) => v.parent,
121 Input::Enum(v) => v.parent,
122 Input::Union(v) => v.parent,
123 }
124 }
125}
126
127#[derive(Debug)]
128pub struct Derived<'p, T, P = &'p ItemInput> {
129 pub parent: P,
130 pub inner: &'p T,
131}
132
133pub type Variant<'v> = Derived<'v, syn::Variant, Enum<'v>>;
134
135pub type Struct<'v> = Derived<'v, syn::ItemStruct>;
136
137pub type Enum<'v> = Derived<'v, syn::ItemEnum>;
138
139pub type Union<'v> = Derived<'v, syn::ItemUnion>;
140
141impl<'p, T, P> Derived<'p, T, P> {
142 pub fn from(value: &'p T, parent: P) -> Self {
143 Derived { parent, inner: value }
144 }
145}
146
147impl<'p, T, P> Deref for Derived<'p, T, P> {
148 type Target = T;
149
150 fn deref(&self) -> &T {
151 self.inner
152 }
153}
154
155impl<'p, T: ToTokens, P> ToTokens for Derived<'p, T, P> {
156 fn to_tokens(&self, tokens: &mut TokenStream) {
157 self.inner.to_tokens(tokens)
158 }
159}
160
161impl<'p, T, P: Copy> Copy for Derived<'p, T, P> { }
162
163impl<'p, T, P: Clone> Clone for Derived<'p, T, P> {
164 fn clone(&self) -> Self {
165 Self { parent: self.parent.clone(), inner: self.inner, }
166 }
167}
168
169impl<'f> Variant<'f> {
170 pub fn builder<F: Fn(Field) -> TokenStream>(&self, f: F) -> TokenStream {
171 let variant = &self.ident;
172 let expression = self.fields().iter().map(f);
173 let enum_name = &self.parent.ident;
174 match self.fields().kind {
175 FieldsKind::Named(..) => {
176 let field_name = self.fields.iter()
177 .map(|f| f.ident.as_ref().unwrap());
178 quote! {
179 #enum_name::#variant { #(#field_name: #expression),* }
180 }
181 },
182 FieldsKind::Unnamed(..) => {
183 quote!( #enum_name::#variant(#(#expression),*) )
184 }
185 FieldsKind::Unit => quote!(#enum_name::#variant),
186 }
187 }
188
189 pub fn fields(self) -> Fields<'f> {
190 self.into()
191 }
192}
193
194impl<'p> Enum<'p> {
195 pub fn variants(self) -> impl Iterator<Item = Variant<'p>> + Clone {
196 self.inner.variants.iter()
197 .map(move |v| Derived::from(v, self))
198 }
199}
200
201impl<'p> Struct<'p> {
202 pub fn fields(self) -> Fields<'p> {
203 self.into()
204 }
205
206 pub fn builder<F: Fn(Field) -> TokenStream>(&self, f: F) -> TokenStream {
207 let expression = self.fields().iter().map(f);
208 let struct_name = &self.parent.ident();
209 match self.fields().kind {
210 FieldsKind::Named(..) => {
211 let field_name = self.fields.iter()
212 .map(|f| f.ident.as_ref().unwrap());
213
214 quote!(#struct_name { #(#field_name: #expression),* })
215 },
216 FieldsKind::Unnamed(..) => {
217 quote!(#struct_name ( #(#expression),* ))
218 }
219 FieldsKind::Unit => quote!(#struct_name),
220 }
221 }
222}