#![recursion_limit = "2048"]
extern crate proc_macro;
extern crate proc_macro2;
extern crate syn;
#[macro_use] extern crate quote;
use proc_macro::TokenStream;
use std::str::FromStr;
use std::iter;
fn impl_vertex_format(ast: &syn::DeriveInput) -> proc_macro2::TokenStream {
let name = &ast.ident;
let struct_data = match &ast.data{
&syn::Data::Enum(_) => panic!("Can't be derived for enums"),
&syn::Data::Struct(ref struct_data) => struct_data,
&syn::Data::Union(ref _union_data) => panic!("Can't be derived for unions yet"),
};
let field = match struct_data.fields{
syn::Fields::Named(ref fields) => &fields.named,
syn::Fields::Unnamed(ref fields) => &fields.unnamed,
syn::Fields::Unit => panic!("no fields")
};
let field = field.into_iter().filter_map(|field| field.ident.as_ref()).collect::<Vec<_>>();
let field_ = field.clone();
let field__= field.clone();
#[cfg(not(feature = "gles"))]
let supported_types = ["u8", "i8", "u16", "i16", "u32", "i32", "f32", "f64"].iter()
.map(|t| proc_macro2::TokenStream::from_str(t).unwrap())
.collect::<Vec<_>>();
#[cfg(not(feature = "gles"))]
let attr_types = ["U8", "I8", "U16", "I16", "U32", "I32", "Float", "Double"].iter()
.map(|t| proc_macro2::TokenStream::from_str(t).unwrap())
.collect::<Vec<_>>();
#[cfg(feature = "gles")]
let supported_types = ["u8", "i8", "u16", "i16", "u32", "i32", "f32"].iter()
.map(|t| proc_macro2::TokenStream::from_str(t).unwrap())
.collect::<Vec<_>>();
#[cfg(feature = "gles")]
let attr_types = ["U8", "I8", "U16", "I16", "U32", "I32", "Float"].iter()
.map(|t| proc_macro2::TokenStream::from_str(t).unwrap())
.collect::<Vec<_>>();
let supported_types1 = &supported_types;
let supported_types2 = &supported_types;
let supported_types3 = &supported_types;
let supported_types4 = &supported_types;
let supported_types5 = &supported_types;
let supported_types6 = &supported_types;
let supported_types7 = &supported_types;
let supported_types8 = &supported_types;
let supported_types9 = &supported_types;
let supported_types10 = &supported_types;
let supported_types11 = &supported_types;
let supported_types12 = &supported_types;
let supported_types13 = &supported_types;
let supported_types14 = &supported_types;
let supported_types15 = &supported_types;
let supported_types16 = &supported_types;
let supported_types17 = &supported_types;
let supported_types18 = &supported_types;
let supported_types19 = &supported_types;
let supported_types20 = &supported_types;
let attr_types1 = &attr_types;
let attr_types2 = &attr_types;
let attr_types3 = &attr_types;
let attr_types4 = &attr_types;
let attr_types5 = &attr_types;
quote! {
impl ::glin::VertexFormat for #name {
#[allow(unused_assignments)]
fn attributes_formats(bindings: &::glin::attributes::Bindings) -> Vec<::glin::attributes::Format>{
use ::glin::attributes::Type as AttrType;
use std::convert::AsRef;
trait TypeToAttrType{
fn to_attr_type(&self) -> AttrType;
fn num_coords(&self) -> usize;
}
#(
impl<'a> TypeToAttrType for &'a [#supported_types1]{
fn to_attr_type(&self) -> AttrType{
AttrType::#attr_types1
}
fn num_coords(&self) -> usize{
self.len()
}
}
impl<'a> TypeToAttrType for &'a [#supported_types2;1]{
fn to_attr_type(&self) -> AttrType{
AttrType::#attr_types2
}
fn num_coords(&self) -> usize{
self.len()
}
}
impl<'a> TypeToAttrType for &'a [#supported_types3;2]{
fn to_attr_type(&self) -> AttrType{
AttrType::#attr_types3
}
fn num_coords(&self) -> usize{
self.len()
}
}
impl<'a> TypeToAttrType for &'a [#supported_types4;3]{
fn to_attr_type(&self) -> AttrType{
AttrType::#attr_types4
}
fn num_coords(&self) -> usize{
self.len()
}
}
impl<'a> TypeToAttrType for &'a [#supported_types5;4]{
fn to_attr_type(&self) -> AttrType{
AttrType::#attr_types5
}
fn num_coords(&self) -> usize{
self.len()
}
}
impl AutoRef<[#supported_types7;1]> for #supported_types6{
fn reference(&self) -> &[#supported_types8;1]{
unsafe{
::std::mem::transmute(self)
}
}
}
impl<T: AsRef<[#supported_types9;2]>> AutoRef<[#supported_types10;2]> for T{
fn reference(&self) -> &[#supported_types11;2]{
self.as_ref()
}
}
impl<T: AsRef<[#supported_types12;3]>> AutoRef<[#supported_types13;3]> for T{
fn reference(&self) -> &[#supported_types14;3]{
self.as_ref()
}
}
impl<T: AsRef<[#supported_types15;4]>> AutoRef<[#supported_types16;4]> for T{
fn reference(&self) -> &[#supported_types17;4]{
self.as_ref()
}
}
impl<T: AsRef<[#supported_types18]>> AutoRef<[#supported_types19]> for T{
fn reference(&self) -> &[#supported_types20]{
self.as_ref()
}
}
)*
trait MatTypeToAttrType{
fn to_attr_type(&self) -> AttrType;
fn cols(&self) -> usize;
fn rows(&self) -> usize;
}
impl<'a> MatTypeToAttrType for &'a [[f32;4];4]{
fn to_attr_type(&self) -> AttrType{
AttrType::Float
}
fn cols(&self) -> usize{
4
}
fn rows(&self) -> usize{
4
}
}
trait AutoRef<T: ?Sized>{
fn reference(&self) -> &T;
}
impl<T: AsRef<[[f32;4];4]>> AutoRef<[[f32;4];4]> for T{
fn reference(&self) -> &[[f32;4];4]{
self.as_ref()
}
}
trait ToFormats<T: ?Sized>{
fn to_formats(&self, name: &'static str, offset: usize, location: Option<u32>) -> Vec<::glin::attributes::Format>;
}
impl<T: TypeToAttrType> ToFormats<TypeToAttrType> for T{
fn to_formats(&self, name: &'static str, offset: usize, location: Option<u32>) -> Vec<::glin::attributes::Format>{
location.map(|location|{
let ty = self.to_attr_type();
::glin::attributes::Format{
name: ::std::borrow::Cow::Borrowed(name),
location: location,
src_type: ty,
dst_type: ty,
num_coords: self.num_coords(),
offset_in_vertex: offset,
normalize: false,
}
})
.into_iter()
.collect()
}
}
impl<T: MatTypeToAttrType> ToFormats<MatTypeToAttrType> for T{
fn to_formats(&self, name: &'static str, offset: usize, location: Option<u32>) -> Vec<::glin::attributes::Format>{
location.map(|location|{
::glin::attributes::MatFormat{
name: ::std::borrow::Cow::Borrowed(name),
location: location,
cols: self.cols(),
rows: self.rows(),
offset_in_vertex: offset,
}.into_row_formats()
})
.into_iter()
.flat_map(|row_formats| row_formats)
.collect()
}
}
let dummy: #name = unsafe { ::std::mem::zeroed() };
let mut offset = 0;
let mut field_offset = 0;
let vec_of_vec = vec![#(
{
let autoattr = dummy.#field.reference();
let name = stringify!(#field_);
let location = bindings.attribute_location(name);
offset += field_offset;
field_offset = ::std::mem::size_of_val(&dummy.#field__);
autoattr.to_formats(name, offset, location)
},
)*];
vec_of_vec
.into_iter()
.flat_map(|vec| vec.into_iter())
.collect()
}
}
}
}
#[proc_macro_derive(VertexFormat)]
pub fn vertex_format(input: TokenStream) -> TokenStream {
let ast = syn::parse(input).unwrap();
let gen = impl_vertex_format(&ast);
gen.into()
}
#[proc_macro_derive(UniformsLocationCache)]
pub fn location_cache(input: TokenStream) -> TokenStream {
let ast = syn::parse(input).unwrap();
let gen = impl_location_cache(&ast);
gen.into()
}
fn impl_location_cache(ast: &syn::DeriveInput) -> proc_macro2::TokenStream {
let name = &ast.ident;
let struct_data = match &ast.data{
&syn::Data::Enum(_) => panic!("Can't be derived for enums"),
&syn::Data::Struct(ref struct_data) => struct_data,
&syn::Data::Union(ref _union_data) => panic!("Can't be derived for unions"),
};
let fields = match struct_data.fields{
syn::Fields::Named(ref fields) => &fields.named,
syn::Fields::Unnamed(ref fields) => &fields.unnamed,
syn::Fields::Unit => panic!("no fields")
};
let field = fields.into_iter()
.filter_map(|field| field.ident.as_ref())
.collect::<Vec<_>>();
let _field = field.clone();
let __field = field.clone();
let ___field = field.clone();
let ____field = field.clone();
let name_repeat = iter::repeat(name);
quote! {
impl #name {
pub fn from_program(program: &::glin::Program) -> #name{
#name {#(
#field: program.uniform_location(stringify!(#_field))
.or_else(|| {
warn!("Program doesn't contain uniform {} in {}", stringify!(#__field), stringify!(#name_repeat));
Some(-1i32 as u32)
})
.unwrap(),
)*}
}
pub fn from_program_non_strict(program: &::glin::Program) -> #name{
#name {#(
#___field: program.uniform_location(stringify!(#____field)).unwrap_or(-1i32 as u32),
)*}
}
}
}
}
#[proc_macro_derive(UniformsLocationCache2, attributes(not_uniform, uniform))]
pub fn location_cache2(input: TokenStream) -> TokenStream {
let ast = syn::parse(input).unwrap();
let gen = impl_location_cache2(&ast);
gen.into()
}
fn impl_location_cache2(ast: &syn::DeriveInput) -> proc_macro2::TokenStream {
let name = &ast.ident;
let struct_data = match &ast.data{
&syn::Data::Enum(_) => panic!("Can't be derived for enums"),
&syn::Data::Struct(ref struct_data) => struct_data,
&syn::Data::Union(ref _union_data) => panic!("Can't be derived for unions"),
};
let fields = match struct_data.fields{
syn::Fields::Named(ref fields) => &fields.named,
syn::Fields::Unnamed(ref fields) => &fields.unnamed,
syn::Fields::Unit => panic!("no fields")
};
let (field, uniform_name): (Vec<Option<&syn::Ident>>, Vec<Option<String>>) = fields.into_iter()
.filter(|field| {
let not_uniform = field.attrs.iter().find(|attr| {
match attr.style {
syn::AttrStyle::Outer => {}
_ => return false,
}
let meta = match attr.parse_meta() {
Ok(meta) => meta,
Err(err) => return false,
};
if meta.path().is_ident("not_uniform") {
true
}else{
false
}
}).is_some();
!not_uniform
})
.map(|field| {
let names = field.attrs.iter().flat_map(|attr| {
match attr.style {
syn::AttrStyle::Outer => {}
_ => return vec![],
}
let meta = match attr.parse_meta() {
Ok(meta) => meta,
Err(err) => return vec![],
};
if !meta.path().is_ident("uniform") {
return vec![]
}
let list = match meta {
syn::Meta::List(l) => l,
_ if meta.path().is_ident("uniform") => {
panic!("Invalid #[uniform] attribute, expected #[uniform(..)]");
}
_ => return vec![],
};
let mut result = vec![];
for item in list.nested.iter() {
match *item {
syn::NestedMeta::Meta(syn::Meta::Path(ref path)) => {
if path.is_ident("name") {
panic!("Invalid empty name attribute in uniform");
} else {
panic!("Invalid #[uniform] attribute: #[uniform(...)]");
}
},
syn::NestedMeta::Meta(syn::Meta::NameValue(ref kv)) => {
if let syn::Lit::Str(ref s) = kv.lit {
if kv.path.is_ident("name") {
result.push(s.value())
}
} else {
panic!("Non-string literal value in #[uniform] attribute");
}
},
syn::NestedMeta::Meta(syn::Meta::List(ref l)) => {
panic!("Invalid #[uniform] attribute: #[uniform(...(..))]");
},
syn::NestedMeta::Lit(_) => {
panic!("Invalid #[uniform] attribute: literal value in #[uniform(..)]");
}
}
}
result
}).collect::<Vec<_>>();
if names.len() > 1 {
panic!("Invalid #[uniform] attribute: more than one name: {:?}", names)
}
(field.ident.as_ref(), names.first().map(|n| n.clone()).or(field.ident.as_ref().map(|i| i.to_string())))
})
.unzip();
let _field = field.clone();
let __field = field.clone();
let ___field = field.clone();
let ____field = field.clone();
let _____field = field.clone();
let ______field = field.clone();
let _______field = field.clone();
let ________field = field.clone();
let _________field = field.clone();
let __________field = field.clone();
let ___________field = field.clone();
let _uniform_name = uniform_name.clone();
let __uniform_name = uniform_name.clone();
let name_repeat = iter::repeat(name);
quote! {#[macro_export]
pub struct UniformsLocationCache{
#(
#_____field: u32,
)*
}
impl #name {
pub fn from_program(program: &::glin::Program) -> UniformsLocationCache{
UniformsLocationCache {#(
#field: program.uniform_location(#uniform_name)
.or_else(|| {
warn!("Program doesn't contain uniform {} in {}", #_uniform_name, stringify!(#name_repeat));
Some(-1i32 as u32)
})
.unwrap(),
)*}
}
pub fn from_program_non_strict(program: &::glin::Program) -> UniformsLocationCache{
UniformsLocationCache {#(
#___field: program.uniform_location(#__uniform_name).unwrap_or(-1i32 as u32),
)*}
}
}
impl UniformsLocationCache{
pub fn uniforms(&self, parameters: &#name) -> impl Iterator<Item = ::glin::program::Uniform> {
vec![#(
if self.#______field == -1i32 as u32 {
None
}else{
Some(::glin::program::uniform_location(self.#_______field, ¶meters.#________field))
}
),*].into_iter().filter_map(|f| f)
}
pub fn set_uniforms(&self, parameters: &#name, program: &glin::Program) {
#(
if self.#_________field != -1i32 as u32 {
let _ = program.set_uniform(&::glin::program::uniform_location(
self.#__________field,
¶meters.#___________field));
}
)*
}
}
}
}