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}