rust-gl-proc 0.1.6

Rust wrapper around webgl.
Documentation
use super::add_trait_bounds;
use proc_macro::TokenStream;
use quote::quote;
use syn::{parse_macro_input, parse_quote, Ident, Data, DeriveInput};
use convert_case::{Case, Casing};

pub fn gl_to_uniform(input: TokenStream) -> TokenStream {
    let ast = parse_macro_input!(input as DeriveInput);
    let name = &ast.ident;

    let module = format!{"mod{}", name};
    let module = module.to_case(Case::Snake);
    let module = Ident::new(&module, name.span());

    let mut generics =
        add_trait_bounds(ast.generics, vec![
            parse_quote!(::rust_gl::uniform::ToUniform),
            parse_quote!(::core::fmt::Debug),
            parse_quote!('static),
        ]);

    let wh = generics.make_where_clause();


    let mut types = Vec::new();
    let mut names = Vec::new();
    let mut strings = Vec::new();
    let mut cased = Vec::new();

    if let Data::Struct(ref data) = ast.data{
        for field in data.fields.iter(){
            let ty = &field.ty;
            let ident = field.ident.as_ref().unwrap();
            let string = ident.to_string();
            let temp = string.to_case(Case::Pascal);
            let case = Ident::new(&temp, ident.span());

            types.push(ty);
            names.push(ident);
            strings.push(string);
            cased.push(case);

            wh.predicates.push(parse_quote!(#ty : ::rust_gl::uniform::GLType))
        }
    }

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

    let out = quote! {
        pub mod #module {
            use super::*;
            pub struct ToUniformStruct #impl_generics #where_clause{#(
                pub #names : <#types as ::rust_gl::uniform::ToUniform>::Output,
            )*}

            #[derive(Debug)]
            pub enum Error #impl_generics #where_clause{#(
                #cased(<#types as ::rust_gl::uniform::ToUniform>::Error),
            )*}
            
            impl #impl_generics ::core::fmt::Display for Error #ty_generics #where_clause{
                fn fmt(&self, fmt: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
                    match self{
                        #(
                            Error::#cased(x) => write!{fmt, "Error in uniform '{}' : '{}'", #strings, x},
                        )*
                        _=>Ok(()),
                    }
                }
            }
            
            impl #impl_generics ::std::error::Error for Error #ty_generics #where_clause {}
            
            impl #impl_generics ::rust_gl::uniform::ToUniform for #name #ty_generics #where_clause{
                type Output = ToUniformStruct #ty_generics;
                type Error = Error #ty_generics;
                fn to_uniform(
                    self,
                    gl : ::std::rc::Rc<::rust_gl::GL>,
                    program : &::web_sys::WebGlProgram,
                    member : ::core::option::Option<::std::rc::Rc<::rust_gl::uniform::Member>>,
                    map : &mut ::std::collections::HashMap<String, ::web_sys::WebGlActiveInfo>,
                ) -> ::core::result::Result<Self::Output, Self::Error>{

                    let output = Self::Output{#(
                        #names : {
                            let new = ::rust_gl::uniform::Member::Member(member.clone(), #strings.to_string());
                            self.#names.to_uniform(gl.clone(), program, ::core::option::Option::Some(::std::rc::Rc::new(new)), map).map_err(Error::#cased)?
                        },
                    )*};
                    Ok(output)
                }
            }
        }
    };
    
    TokenStream::from(out)
}