1extern crate proc_macro;
2
3use proc_macro2::TokenStream;
4use quote::quote;
5use syn::ItemStruct;
6
7#[proc_macro_attribute]
8pub fn attribute(
9 _attr: proc_macro::TokenStream,
10 item: proc_macro::TokenStream,
11) -> proc_macro::TokenStream {
12 let item: TokenStream = item.into();
13
14 let r = quote! {
15 #[repr(C)]
16 #[derive(Clone, Copy, limelight::Attribute, limelight::bytemuck::Pod, limelight::bytemuck::Zeroable)]
17 #item
18 };
19
20 r.into()
21}
22
23#[proc_macro_derive(Attribute)]
24pub fn vertex_attribute_derive(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
25 impl_vertex_attribute_derive(input.into()).into()
26}
27
28fn bind(field: &syn::Field) -> TokenStream {
29 let name = field.ident.as_ref().unwrap().to_string();
30 let kind = &field.ty;
31
32 quote! {
33 limelight::AttributeBinding {
34 variable_name: (#name).to_string(),
35 kind: <#kind as limelight::AsSizedDataType>::as_sized_data_type(),
36 }
37 }
38}
39
40fn impl_vertex_attribute_derive(input: TokenStream) -> TokenStream {
41 let ast: ItemStruct = syn::parse2(input).expect("Should decorate a struct.");
42
43 let name = &ast.ident;
44
45 let bindings: Vec<TokenStream> = match &ast.fields {
46 syn::Fields::Named(fields) => fields.named.iter().map(bind).collect(),
47 _ => panic!("Only structs with named fields can derive StateMachine currently."),
48 };
49
50 quote! {
51 impl limelight::Attribute for #name {
52 fn describe() -> Vec<limelight::AttributeBinding> {
53 vec![
54 #(#bindings),*
55 ]
56 }
57 }
58 }
59}