1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
use proc_macro::TokenStream;
use proc_macro2::Span;
use quote::quote;

#[proc_macro_derive(Std140)]
pub fn std140(input: TokenStream) -> TokenStream{
    let ast: syn::DeriveInput = syn::parse(input).unwrap();
    let ident = ast.ident;
    let (impl_gen, ty_gen, where_clause) = ast.generics.split_for_impl();
    if let syn::Data::Struct(data_struct) = ast.data {
        let fields = data_struct.fields;
        match fields{
            syn::Fields::Named(fields) => {
                let field = fields.named.into_iter().map(|f| f.ident);
                quote!(
                    impl #impl_gen WriteStd140 for #ident #ty_gen #where_clause {
                        fn write_std140(&self, data: &mut Data) {
                            let len = data.bytes();
                            #(self.#field.write_std140(data);)*
                            let total = data.bytes() - len;
                            let rem = total % 16;
                            if rem != 0 {
                                let padding = 16 - rem;
                                data.pad_bytes(padding);
                            }
                        }
                    }
                ).into()
            }

            _ => syn::Error::new(Span::call_site(), "Std140 can only be implemented for named struct")
                .to_compile_error()
                .into()
        }
    }else{
        panic!("Std140 can only be derived for structs")
    }
}