vert_macros/
lib.rs

1use proc_macro::TokenStream;
2use quote::{quote, ToTokens};
3use syn::{parse_quote, TypePath};
4
5///
6/// A struct like this:
7/// ```rust,no-run
8/// pub struct RendererDependencies {
9///     scheduler: Handle<Scheduler>,
10///     graphics: Handle<GraphicsContext>,
11/// }
12/// ```
13/// Will be expanded into this:
14/// ```rust,no-run
15/// impl Dependencies for RendererDependencies {
16///     fn type_ids() -> Vec<crate::app::ModuleId> {
17///         let mut ids = ::alloc::vec::Vec::new();
18///         ids.extend(<Handle<Scheduler> as Dependencies>::type_ids());
19///         ids.extend(<Handle<GraphicsContext> as Dependencies>::type_ids());
20///         ids
21///     }
22///     fn from_untyped_handles(ptrs: &[crate::app::UntypedHandle]) -> Self {
23///         let mut offset: usize = 0;
24///         let ids = <Handle<Scheduler> as Dependencies>::type_ids();
25///         let range_0 = offset..(offset + ids.len());
26///         offset += ids.len();
27///         let ids = <Handle<GraphicsContext> as Dependencies>::type_ids();
28///         let range_1 = offset..(offset + ids.len());
29///         offset += ids.len();
30///         Self {
31///             scheduler: <Handle<
32///                 Scheduler,
33///             > as Dependencies>::from_untyped_handles(&ptrs[range_0]),
34///             graphics: <Handle<
35///                 GraphicsContext,
36///             > as Dependencies>::from_untyped_handles(&ptrs[range_1]),
37///         }
38///     }
39/// }
40/// ```   
41#[proc_macro_derive(Dependencies)]
42pub fn derive_dependencies(input: TokenStream) -> TokenStream {
43    let derive_input: syn::DeriveInput = syn::parse(input).unwrap();
44    let stru = match &derive_input.data {
45        syn::Data::Struct(s) => s,
46        _ => panic!("Only derive Dependencies on structs"),
47    };
48    let stru_ident = derive_input.ident;
49    // let fields: Vec<TypePath>
50    // s.fields.iter().map(|e|)
51
52    let mut field_type_paths: Vec<&TypePath> = vec![];
53
54    for e in stru.fields.iter() {
55        let path = match &e.ty {
56            syn::Type::Path(path) => path,
57            _ => panic!(
58                "field {:?} is not a Handle! ",
59                e.to_token_stream().to_string()
60            ),
61        };
62        field_type_paths.push(path);
63    }
64
65    let extend_ids = field_type_paths
66        .iter()
67        .map(|path| quote!(ids.extend(<#path as Dependencies>::type_ids());))
68        .collect::<Vec<proc_macro2::TokenStream>>();
69
70    let declare_element_ranges = field_type_paths
71        .iter()
72        .enumerate()
73        .map(|(i, path)| {
74            let range_i: syn::Ident = syn::parse_str(&format!("range_{i}")).unwrap();
75
76            let declare_offset_if_first = if i == 0 {
77                Some(quote!(let mut offset: usize = 0;))
78            } else {
79                None
80            };
81            quote!(
82                #declare_offset_if_first
83
84                let ids = <#path as Dependencies>::type_ids();
85                let #range_i = offset..(offset + ids.len());
86                offset += ids.len();
87
88            )
89        })
90        .collect::<Vec<proc_macro2::TokenStream>>();
91
92    let self_construction_from_ranges = match &stru.fields {
93        syn::Fields::Unit => quote!(Self),
94        syn::Fields::Named(named_fields) => {
95            assert_eq!(field_type_paths.len(), named_fields.named.len());
96            let set_fields = named_fields
97                .named
98                .iter()
99                .zip(field_type_paths.iter())
100                .enumerate()
101                .map(|(i, (field, path))| {
102                    let range_i: syn::Ident = syn::parse_str(&format!("range_{i}")).unwrap();
103                    let field_ident = field.ident.as_ref().unwrap();
104                    quote!(#field_ident: <#path as Dependencies>::from_untyped_handles(&ptrs[#range_i]))
105                });
106
107            quote!(
108                Self {
109                    #( #set_fields ),*
110                }
111            )
112        }
113        syn::Fields::Unnamed(unnamed_fields) => {
114            assert_eq!(field_type_paths.len(), unnamed_fields.unnamed.len());
115
116            let set_fields = field_type_paths.iter().enumerate().map(|(i, path)| {
117                let range_i: syn::Ident = syn::parse_str(&format!("range_{i}")).unwrap();
118                quote!(<#path as Dependencies>::from_untyped_handles(&ptrs[#range_i]))
119            });
120
121            quote!(
122                Self (
123                    #( #set_fields ),*
124                )
125            )
126        }
127    };
128
129    let trait_impl: proc_macro2::TokenStream = quote!(
130        impl Dependencies for #stru_ident {
131            fn type_ids() -> Vec<crate::app::ModuleId> {
132                let mut ids = vec![];
133                #( #extend_ids )*
134                ids
135            }
136
137            fn from_untyped_handles(ptrs: &[crate::app::UntypedHandle]) -> Self {
138                #( #declare_element_ranges)*
139
140                #self_construction_from_ranges
141            }
142        }
143    );
144
145    trait_impl.into()
146}
147
148/// Derives the Lerp trait for a struct where each field implements Lerp.
149/// For example the Struct:
150/// ```rust,no-run
151/// struct Color{
152///     r: f32,
153///     g: f32,
154///     b: f32,
155/// }
156/// ```
157///
158/// Will get a lerp implementation that is:
159///
160/// ```rust,no-run
161/// impl Lerp for Color{
162///     fn lerp(&self, other: &Self, factor: f32) -> Self {
163///         Color {
164///             r: self.r.lerp(&other.r, factor),
165///             g: self.g.lerp(&other.g, factor),
166///             b: self.b.lerp(&other.b, factor),
167///         }
168///     }
169/// }
170/// ```
171///
172/// Don't use this Derive Macro if the fields should not be lerped independently.
173#[proc_macro_derive(Lerp)]
174pub fn derive_lerp(input: TokenStream) -> TokenStream {
175    let derive_input: syn::DeriveInput = syn::parse(input).unwrap();
176    let stru = match &derive_input.data {
177        syn::Data::Struct(s) => s,
178        _ => panic!("Only derive Dependencies on structs"),
179    };
180    let stru_ident = derive_input.ident;
181    // let fields: Vec<TypePath>
182    // s.fields.iter().map(|e|)
183
184    let lerp_impl_body = match &stru.fields {
185        syn::Fields::Named(_) => {
186            let field_iter = stru.fields.iter().map(|field| {
187                let ident = field.ident.as_ref().unwrap();
188                quote!(#ident : self.#ident.lerp(&other.#ident, factor))
189            });
190            quote!(#stru_ident{#(#field_iter),*})
191        }
192        syn::Fields::Unnamed(_) => {
193            let field_iter = stru
194                .fields
195                .iter()
196                .enumerate()
197                .map(|(i, _)| quote!(self.#i.lerp(&other.#i, factor)));
198            quote!(#stru_ident(#(#field_iter),*))
199        }
200        syn::Fields::Unit => {
201            quote!(#stru_ident)
202        }
203    };
204
205    quote!(
206        impl Lerp for #stru_ident {
207            fn lerp(&self, other: &Self, factor: f32) -> Self {
208                #lerp_impl_body
209            }
210        }
211    )
212    .into()
213}