bevy_2dviewangle_macro/
lib.rs1use proc_macro::TokenStream;
4use std::collections::HashMap;
5
6use quote::{format_ident, quote};
7use syn::punctuated::Punctuated;
8use syn::{Data, Expr, ExprLit, Fields, Lit, Meta, Token};
9
10macro_rules! enumize {
11 ($k: expr, $e: expr, $m: expr, $c: expr, $v: expr) => {{
12 let num;
13 let key_str = capitalize_first_letter(&$k.value());
14 if $m.contains_key(&key_str) {
15 num = *$m.get(&key_str).unwrap();
16 } else {
17 $c += 1;
18 let variant_name = syn::Ident::new(&key_str, $k.span());
19 $e.push(quote! {#variant_name});
20 $m.insert(key_str, $c);
21 num = $c;
22 }
23 $v = quote! {Some(#num)};
24 }}
25}
26
27fn capitalize_first_letter(s: &str) -> String {
28 let mut c = s.chars();
29 match c.next() {
30 None => String::new(),
31 Some(f) => f.to_uppercase().collect::<String>() + c.as_str(),
32 }
33}
34
35const TEXTUREVIEW_ATTRIBUTE: &str = "textureview";
36#[proc_macro_derive(View2dCollection, attributes(textureview))]
37pub fn actors_textures_derive(input: TokenStream) -> TokenStream {
38 let ast: syn::DeriveInput = syn::parse(input).unwrap();
39 impl_actors_textures(ast).unwrap_or_default().into()
40}
41
42fn impl_actors_textures(ast: syn::DeriveInput) -> Result<proc_macro2::TokenStream, Vec<syn::Error>> {
43 let struct_name = &ast.ident;
44
45 if let Data::Struct(data_struct) = &ast.data {
46 if let Fields::Named(fields) = &data_struct.fields {
47 let mut fields_info = Vec::new();
48 let mut actor_enum = Vec::new();
49 let mut actor_map = HashMap::new();
50 let mut actor_count: u64 = 0;
51 let mut action_enum = Vec::new();
52 let mut action_map = HashMap::new();
53 let mut action_count: u16 = 0;
54
55 for field in fields.named.iter() {
56 let field_name = field.ident.as_ref().unwrap();
57 let mut actor_value = quote! {None};
58 let mut action_value = quote! {None};
59 let mut angle_value = quote! {None};
60 let mut image_value = quote! {None};
61 let mut atlas_layout_value = quote! {None};
62
63 for attr in field
64 .attrs
65 .iter()
66 .filter(|attribute| attribute.path().is_ident(TEXTUREVIEW_ATTRIBUTE))
67 {
68 let view_meta_list = attr.parse_args_with(Punctuated::<Meta, Token![,]>::parse_terminated);
69
70 for attribute in view_meta_list.unwrap() {
71 match attribute {
72 Meta::NameValue(named_value) if named_value.path.is_ident("actor") => {
73 if let Expr::Lit(ExprLit { lit: Lit::Str(key), .. }) = &named_value.value {
74 enumize!(key, actor_enum, actor_map, actor_count, actor_value);
75 }
76 }
77 Meta::NameValue(named_value) if named_value.path.is_ident("action") => {
78 if let Expr::Lit(ExprLit { lit: Lit::Str(key), .. }) = &named_value.value {
79 enumize!(key, action_enum, action_map, action_count, action_value);
80 }
81 }
82 Meta::NameValue(named_value) if named_value.path.is_ident("angle") => {
83 if let Expr::Lit(ExprLit { lit: Lit::Str(key), .. }) = &named_value.value {
84 let key_str = capitalize_first_letter(&key.value());
85 let variant_name = syn::Ident::new(&key_str, key.span());
86 angle_value = quote! {Some(Angle::#variant_name)};
87 }
88 }
89 _ => {}
90 }
91 }
92 }
93
94 match &field.ty {
95 ty if quote!(#ty).to_string() == "Handle < Image >" => {
96 image_value = quote! {Some(&self.#field_name)}
97 }
98 ty if quote!(#ty).to_string() == "Handle < TextureAtlasLayout >" => {
99 atlas_layout_value = quote! {Some(&self.#field_name)}
100 }
101 _ => {}
102 }
103
104 let field_info = quote! {
105 (
106 #actor_value,
107 #action_value,
108 #angle_value,
109 #image_value,
110 #atlas_layout_value,
111 )
112 };
113
114 fields_info.push(field_info);
115 }
116
117 let actor_enum_name = format_ident!("Actor{}", struct_name);
118 let action_enum_name = format_ident!("Action{}", struct_name);
119 let expanded = quote! {
120 use bevy_2dviewangle::*;
121
122 #[derive(Default, Eq, PartialEq)]
123 #[repr(u64)]
124 pub enum #actor_enum_name {
125 #[default]
126 Any,
127 #( #actor_enum ),*
128 }
129
130 impl From<#actor_enum_name> for u64 {
131 fn from(actor: #actor_enum_name) -> Self {
132 actor as u64
133 }
134 }
135
136 #[derive(Default, Eq, PartialEq)]
137 #[repr(u16)]
138 pub enum #action_enum_name {
139 #[default]
140 Any,
141 #( #action_enum ),*
142 }
143
144 impl From<#action_enum_name> for u16 {
145 fn from(action: #action_enum_name) -> Self {
146 action as u16
147 }
148 }
149
150 #[automatically_derived]
151 impl View2dCollection for #struct_name {
152 fn get_all(&self) -> Vec<(
153 Option<u64>,
154 Option<u16>,
155 Option<Angle>,
156 Option<&Handle<Image>>,
157 Option<&Handle<TextureAtlasLayout>>,
158 )> {
159 vec![#( #fields_info ),*]
160 }
161 }
162 };
163 return Ok(expanded);
164 }
165 }
166
167 Err(vec![])
168}