1use quote::quote;
2
3#[proc_macro_derive(Vertex, attributes(vertex))]
4pub fn vert(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
5 let ast = syn::parse_macro_input!(input as syn::DeriveInput);
6 let ident = &ast.ident;
7
8 let fields = if let syn::Data::Struct(syn::DataStruct { fields, .. }) = &ast.data {
9 if let syn::Fields::Named(syn::FieldsNamed { named, .. }) = fields {
10 named
11 } else { unimplemented!("unnamed field") }
12 } else { unimplemented!("not struct") };
13
14 let attributed = fields.iter()
15 .filter_map(|f| {
16 let attr = f.attrs.iter()
17 .find(|a| {
18 a.path.segments.iter()
19 .find(|s| s.ident == "vertex")
20 .is_some()
21 });
22
23 match attr {
24 Some(a) => Some((f, a)),
25 None => None,
26 }
27 });
28
29 let attribute_descriptions = attributed
30 .map(|(f, attr)| {
31 let ident = f.ident.as_ref().unwrap();
32
33 let meta = attr.parse_meta().unwrap();
34 let location_nv = if let syn::Meta::List(p) = &meta {
35 p.nested.iter()
36 .find_map(|nm| {
37 if let syn::NestedMeta::Meta(m) = nm {
38 if let syn::Meta::NameValue(nv) = m {
39 match nv.path.segments.iter().any(|s| s.ident == "loc") {
40 true => Some(nv),
41 false => None,
42 }
43 } else { unimplemented!("not namevalue") }
44 } else { unimplemented!("not nested meta") }
45 })
46 .expect("no attr?")
47 } else { unreachable!() };
48 let location = if let syn::Lit::Int(i) = &location_nv.lit {
49 i
50 } else { unimplemented!("not int") };
51
52 let format_nv = if let syn::Meta::List(p) = &meta {
53 p.nested.iter()
54 .find_map(|nm| {
55 if let syn::NestedMeta::Meta(m) = nm {
56 if let syn::Meta::NameValue(nv) = m {
57 match nv.path.segments.iter().any(|s| s.ident == "format") {
58 true => Some(nv),
59 false => None,
60 }
61 } else { unimplemented!("not namevalue") }
62 } else { unimplemented!("not nested meta") }
63 })
64 .expect("no attr?")
65 } else { unreachable!() };
66 let format = if let syn::Lit::Str(s) = &format_nv.lit {
67 quote::format_ident!("{}", s.value())
68 } else { unimplemented!("not str") };
69
70 quote! {
71 plate::VertexAttributeDescription::new(0, #location, plate::memoffset::offset_of!(Self, #ident) as u32, plate::Format::#format)
72 }
73 });
74
75 quote! {
76 impl plate::VertexDescription for #ident {
77 fn binding_descriptions() -> Vec<plate::VertexBindingDescription> {
78 vec![
79 plate::VertexBindingDescription::new(0, std::mem::size_of::<Self>() as u32, plate::InputRate::VERTEX)
80 ]
81 }
82
83 fn attribute_descriptions() -> Vec<plate::VertexAttributeDescription> {
84 vec![
85 #(#attribute_descriptions),*
86 ]
87 }
88 }
89 }.into()
90}
91
92#[cfg(test)]
93mod tests {
94 #[test]
95 fn it_works() {
96 let result = 2 + 2;
97 assert_eq!(result, 4);
98 }
99
100 }