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)
}