picodraw_derive/
lib.rs

1use quote::quote;
2use syn::{parse_macro_input, DeriveInput, Ident};
3
4#[proc_macro_derive(ShaderData)]
5pub fn derive_shader_data(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
6    let input = parse_macro_input!(input as DeriveInput);
7    let name = input.ident;
8    let vis = input.vis;
9
10    let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();
11
12    let str = match input.data {
13        syn::Data::Struct(s) => s,
14        _ => panic!("struct expected"),
15    };
16
17    let shader_vars_name = Ident::new(&format!("{}__ShaderVars", name), name.span());
18    let (shader_vars, shader_collect, shader_write) = match str.fields {
19        syn::Fields::Named(fields) => {
20            let shader_vars_fields = fields
21                .named
22                .iter()
23                .map(|x| {
24                    let vis = &x.vis;
25                    let ident = x.ident.as_ref().unwrap();
26                    let ty = &x.ty;
27                    quote! { #vis #ident: <#ty as picodraw::ShaderData>::ShaderVars }
28                })
29                .collect::<Vec<_>>();
30
31            let shader_collect_fields = fields
32                .named
33                .iter()
34                .map(|x| {
35                    let ident = x.ident.as_ref().unwrap();
36                    let ident_str = ident.to_string();
37                    let ty = &x.ty;
38                    quote! { #ident: <#ty as picodraw::ShaderData>::shader_vars(&mut picodraw::prefix_vars(vars, #ident_str)) }
39                })
40                .collect::<Vec<_>>();
41
42            let shader_write_fields = fields
43                .named
44                .iter()
45                .map(|x| {
46                    let ident = x.ident.as_ref().unwrap();
47                    let ident_str = ident.to_string();
48                    let ty = &x.ty;
49                    quote! { <#ty as picodraw::ShaderData>::write(&self.#ident, &mut picodraw::prefix_writer(writer, #ident_str)); }
50                })
51                .collect::<Vec<_>>();
52
53            (
54                quote! {
55                    #vis struct #shader_vars_name {
56                        #(#shader_vars_fields),*
57                    }
58                },
59                quote! {
60                    #shader_vars_name {
61                        #(#shader_collect_fields),*
62                    }
63                },
64                quote! {
65                    #(#shader_write_fields)*
66                },
67            )
68        }
69
70        syn::Fields::Unnamed(fields) => {
71            let shader_vars_fields = fields
72                .unnamed
73                .iter()
74                .map(|x| {
75                    let vis = &x.vis;
76                    let ty = &x.ty;
77                    quote! { #vis <#ty as picodraw::ShaderData>::ShaderVars }
78                })
79                .collect::<Vec<_>>();
80
81            let shader_collect_fields = fields
82                .unnamed
83                .iter()
84                .enumerate()
85                .map(|(id, x)| {
86                    let ty = &x.ty;
87                    quote! { <#ty as picodraw::ShaderData>::shader_vars(&mut picodraw::prefix_vars(vars, stringify!(#id))) }
88                })
89                .collect::<Vec<_>>();
90
91            let shader_write_fields = fields
92                .unnamed
93                .iter()
94                .enumerate()
95                .map(|(id, x)| {
96                    let ty = &x.ty;
97                    quote! { <#ty as picodraw::ShaderData>::write(&self.#id, &mut picodraw::prefix_writer(writer, stringify!(#id))); }
98                })
99                .collect::<Vec<_>>();
100
101            (
102                quote! {
103                    #vis struct #shader_vars_name (#(#shader_vars_fields),*);
104                },
105                quote! {
106                    #shader_vars_name (#(#shader_collect_fields),*)
107                },
108                quote! {
109                    #(#shader_write_fields)*
110                },
111            )
112        }
113
114        syn::Fields::Unit => (
115            quote! { #vis struct #shader_vars_name; },
116            quote! { let _ = vars; () },
117            quote! { let _ = writer; },
118        ),
119    };
120
121    quote! {
122        #[allow(non_camel_case_types)]
123        #shader_vars
124
125        impl #impl_generics picodraw::ShaderData for #name #ty_generics #where_clause {
126            type ShaderVars = #shader_vars_name;
127            fn shader_vars(vars: &mut dyn picodraw::ShaderVars) -> Self::ShaderVars {
128                #shader_collect
129            }
130            fn write(&self, writer: &mut dyn picodraw::ShaderDataWriter) {
131                #shader_write
132            }
133        }
134    }
135    .into()
136}