crevice-derive 0.18.0

Derive crate for the 'crevice' crate
Documentation
use proc_macro2::{Literal, TokenStream};
use quote::quote;
use syn::{parse_quote, Data, DeriveInput, Fields, Path};

pub fn emit(input: DeriveInput) -> TokenStream {
    let fields = match &input.data {
        Data::Struct(data) => match &data.fields {
            Fields::Named(fields) => fields,
            Fields::Unnamed(_) => panic!("Tuple structs are not supported"),
            Fields::Unit => panic!("Unit structs are not supported"),
        },
        Data::Enum(_) | Data::Union(_) => panic!("Only structs are supported"),
    };

    let base_trait_path: Path = parse_quote!(::crevice::glsl::Glsl);
    let struct_trait_path: Path = parse_quote!(::crevice::glsl::GlslStruct);

    let name = input.ident;
    let name_str = Literal::string(&name.to_string());

    let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();

    let glsl_fields = fields.named.iter().map(|field| {
        let field_ty = &field.ty;
        let field_name_str = Literal::string(&field.ident.as_ref().unwrap().to_string());

        quote! {
            ::crevice::glsl::GlslField {
                ty: <#field_ty as ::crevice::glsl::Glsl>::NAME,
                name: #field_name_str,
            }
        }
    });

    quote! {
        unsafe impl #impl_generics #base_trait_path for #name #ty_generics #where_clause {
            const NAME: &'static str = #name_str;
        }

        unsafe impl #impl_generics #struct_trait_path for #name #ty_generics #where_clause {
            const FIELDS: &'static [::crevice::glsl::GlslField] = &[
                #( #glsl_fields, )*
            ];
        }
    }
}