1extern crate proc_macro;
7extern crate syn;
8#[macro_use]
9extern crate quote;
10
11use proc_macro::TokenStream;
12use syn::{parse_macro_input, Data, DeriveInput, Fields};
13
14#[proc_macro_derive(Animate)]
16pub fn animate_derive(input: TokenStream) -> TokenStream {
17 let input = parse_macro_input!(input as DeriveInput);
19
20 let name = input.ident;
22 let data = input.data;
23
24 let Data::Struct(data_struct) = data else {
26 panic!("Animate can only be derived for structs");
27 };
28
29 let Fields::Named(fields) = data_struct.fields else {
30 panic!("Animate can only be derived for structs with named fields");
31 };
32
33 let component_fields = fields.named.iter().map(|f| {
34 let ty = &f.ty;
35 quote! {
36 total += <#ty as ::iced_anim::Animate>::components();
37 }
38 });
39
40 let update_fields = fields.named.iter().map(|f| {
41 let name = &f.ident;
42 quote! {
43 ::iced_anim::Animate::update(&mut self.#name, components);
44 }
45 });
46
47 let distance_fields = fields.named.iter().map(|f| {
48 let name = &f.ident;
49 quote! {
50 distances.push(::iced_anim::Animate::distance_to(&self.#name, &end.#name));
51 }
52 });
53
54 let lerp_fields = fields.named.iter().map(|f| {
55 let name = &f.ident;
56 quote! {
57 ::iced_anim::Animate::lerp(&mut self.#name, &start.#name, &end.#name, progress);
58 }
59 });
60
61 let impl_gen = quote! {
62 impl ::iced_anim::Animate for #name {
63 fn components() -> usize {
64 let mut total = 0;
65 #(#component_fields)*
66 total
67 }
68
69 fn update(&mut self, components: &mut impl Iterator<Item = ::core::primitive::f32>) {
70 #(#update_fields)*
71 }
72
73 fn distance_to(&self, end: &Self) -> ::std::vec::Vec<::core::primitive::f32> {
74 let mut distances = ::std::vec::Vec::with_capacity(Self::components());
75 #(#distance_fields)*
76 distances.concat()
77 }
78
79 fn lerp(&mut self, start: &Self, end: &Self, progress: ::core::primitive::f32) {
80 #(#lerp_fields)*
81 }
82 }
83 };
84
85 TokenStream::from(impl_gen)
86}