devise_core/
derived.rs

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}