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_attribute(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::attribute::ToAttribute),
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::attribute::GLType))
}
}
let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
let out = quote! {
pub mod #module {
use super::*;
pub struct ToAttributeStruct #impl_generics #where_clause{#(
pub #names : <#types as ::rust_gl::attribute::ToAttribute>::Output,
)*}
#[derive(Debug)]
pub enum Error #impl_generics #where_clause{#(
#cased(<#types as ::rust_gl::attribute::ToAttribute>::Error),
)*}
impl #impl_generics ::std::fmt::Display for Error #ty_generics #where_clause{
fn fmt(&self, fmt: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
match self{
#(
Error::#cased(x) => write!{fmt, "Error in attribute '{}' : '{}'", #strings, x},
)*
_=>Ok(()),
}
}
}
impl #impl_generics ::std::error::Error for Error #ty_generics #where_clause {}
impl #impl_generics ::rust_gl::attribute::ToAttribute for #name #ty_generics #where_clause{
type Output = ToAttributeStruct #ty_generics;
type Error = Error #ty_generics;
fn to_attribute(
self,
gl : ::std::rc::Rc<::rust_gl::GL>,
program: &::web_sys::WebGlProgram,
name: &str,
map : &mut ::std::collections::HashMap<String, ::web_sys::WebGlActiveInfo>,
) -> Result<Self::Output, Self::Error>{
let output = Self::Output{#(
#names : self.#names.to_attribute(gl.clone(), program, #strings, map).map_err(Error::#cased)?,
)*};
Ok(output)
}
}
}
};
TokenStream::from(out)
}