plate_macros/
lib.rs

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    //test not struct
101    //unnamed field
102    //non attributed field
103    //wrong attribute field
104    //other macros attributes
105}