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
extern crate proc_macro;
use proc_macro::TokenStream;
use proc_macro2::Span;
use proc_macro_crate::{crate_name, FoundCrate};
use proc_quote::quote;
use syn::parse_macro_input;
use syn::DeriveInput;
use syn::{Data, DataStruct, Fields, Ident, Type};
#[proc_macro_derive(Animatable, attributes(tag))]
pub fn animatable_derive(input: TokenStream) -> TokenStream {
let input = parse_macro_input!(input as DeriveInput);
expand_derive(input)
.unwrap_or_else(syn::Error::into_compile_error)
.into()
}
fn expand_derive(input: DeriveInput) -> syn::Result<proc_macro2::TokenStream> {
let anim = get_crate()?;
let fields = get_fields(input.data)
.unwrap()
.iter()
.map(|(field_name, _)| {
Ok(quote! {
res.#field_name = #anim::Animatable::animate(&self.#field_name,&to.#field_name, time);
})
})
.collect::<syn::Result<proc_macro2::TokenStream>>()?;
let st_name = input.ident;
let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();
Ok(quote! {
impl #impl_generics #anim::Animatable for #st_name #ty_generics #where_clause
{
#[inline]
fn animate(&self, to: &Self, time: f64) -> Self{
let mut res = self.clone();
#fields
res
}
}
})
}
fn get_crate() -> syn::Result<Ident> {
let anim = match crate_name("anim") {
Ok(found) => match found {
FoundCrate::Itself => Ident::new("crate", Span::call_site()),
FoundCrate::Name(name) => Ident::new(&name, Span::call_site()),
},
Err(_) => Ident::new("crate", Span::call_site()),
};
Ok(anim)
}
fn get_fields(data: Data) -> syn::Result<Vec<(Ident, Type)>> {
let fields = match data {
Data::Struct(DataStruct {
fields: Fields::Named(fields),
..
}) => fields.named,
_ => panic!("this derive macro only works on structs with named fields"),
};
let items = fields
.into_iter()
.map(|f| {
let field_name = f.ident.unwrap();
let ty = f.ty;
(field_name, ty)
})
.collect();
Ok(items)
}