1
1
use proc_macro2:: TokenStream ;
2
2
use quote:: { format_ident, quote} ;
3
- use syn:: { parse_quote, Ident , ItemStruct , Type } ;
3
+ use syn:: { parse_quote, Field , Generics , Ident , ItemStruct , Type , TypePath } ;
4
4
5
5
use crate :: Result ;
6
6
7
7
pub ( crate ) fn impl_joined_value ( input_struct : & ItemStruct ) -> Result < TokenStream > {
8
8
let struct_ident = & input_struct. ident ;
9
9
let ( impl_generics, ty_generics, where_clause) = input_struct. generics . split_for_impl ( ) ;
10
- let ( field_ident, field_type) = get_fields_map ( & input_struct. fields ) ?;
11
- let BufferStructConfig {
12
- struct_name : buffer_struct_ident,
13
- } = BufferStructConfig :: from_data_struct ( & input_struct) ;
10
+ let StructConfig {
11
+ buffer_struct_name : buffer_struct_ident,
12
+ } = StructConfig :: from_data_struct ( & input_struct) ;
14
13
let buffer_struct_vis = & input_struct. vis ;
15
14
15
+ let ( field_ident, _, field_config) = get_fields_map ( & input_struct. fields ) ?;
16
+ let buffer_type: Vec < & Type > = field_config
17
+ . iter ( )
18
+ . map ( |config| & config. buffer_type )
19
+ . collect ( ) ;
20
+
16
21
let buffer_struct: ItemStruct = parse_quote ! {
17
22
#[ derive( Clone ) ]
18
23
#[ allow( non_camel_case_types) ]
19
24
#buffer_struct_vis struct #buffer_struct_ident #impl_generics #where_clause {
20
25
#(
21
- #buffer_struct_vis #field_ident: :: bevy_impulse :: Buffer <#field_type> ,
26
+ #buffer_struct_vis #field_ident: #buffer_type ,
22
27
) *
23
28
}
24
29
} ;
@@ -36,7 +41,7 @@ pub(crate) fn impl_joined_value(input_struct: &ItemStruct) -> Result<TokenStream
36
41
impl #impl_generics #struct_ident #ty_generics #where_clause {
37
42
fn select_buffers(
38
43
#(
39
- #field_ident: :: bevy_impulse :: Buffer <#field_type> ,
44
+ #field_ident: #buffer_type ,
40
45
) *
41
46
) -> #buffer_struct_ident #ty_generics {
42
47
#buffer_struct_ident {
@@ -55,14 +60,30 @@ pub(crate) fn impl_joined_value(input_struct: &ItemStruct) -> Result<TokenStream
55
60
Ok ( gen. into ( ) )
56
61
}
57
62
58
- struct BufferStructConfig {
59
- struct_name : Ident ,
63
+ /// Converts a list of generics to a [`PhantomData`] TypePath.
64
+ /// e.g. `::std::marker::PhantomData<(T,)>`
65
+ // Currently unused but could be used in the future
66
+ fn _to_phantom_data ( generics : & Generics ) -> TypePath {
67
+ let lifetimes: Vec < Type > = generics
68
+ . lifetimes ( )
69
+ . map ( |lt| {
70
+ let lt = & lt. lifetime ;
71
+ let ty: Type = parse_quote ! { & #lt ( ) } ;
72
+ ty
73
+ } )
74
+ . collect ( ) ;
75
+ let ty_params: Vec < & Ident > = generics. type_params ( ) . map ( |ty| & ty. ident ) . collect ( ) ;
76
+ parse_quote ! { :: std:: marker:: PhantomData <( #( #lifetimes, ) * #( #ty_params, ) * ) > }
77
+ }
78
+
79
+ struct StructConfig {
80
+ buffer_struct_name : Ident ,
60
81
}
61
82
62
- impl BufferStructConfig {
83
+ impl StructConfig {
63
84
fn from_data_struct ( data_struct : & ItemStruct ) -> Self {
64
85
let mut config = Self {
65
- struct_name : format_ident ! ( "__bevy_impulse_{}_Buffers" , data_struct. ident) ,
86
+ buffer_struct_name : format_ident ! ( "__bevy_impulse_{}_Buffers" , data_struct. ident) ,
66
87
} ;
67
88
68
89
let attr = data_struct
@@ -72,8 +93,39 @@ impl BufferStructConfig {
72
93
73
94
if let Some ( attr) = attr {
74
95
attr. parse_nested_meta ( |meta| {
75
- if meta. path . is_ident ( "struct_name" ) {
76
- config. struct_name = meta. value ( ) ?. parse ( ) ?;
96
+ if meta. path . is_ident ( "buffer_struct_name" ) {
97
+ config. buffer_struct_name = meta. value ( ) ?. parse ( ) ?;
98
+ }
99
+ Ok ( ( ) )
100
+ } )
101
+ // panic if attribute is malformed, this will result in a compile error which is intended.
102
+ . unwrap ( ) ;
103
+ }
104
+
105
+ config
106
+ }
107
+ }
108
+
109
+ struct FieldConfig {
110
+ buffer_type : Type ,
111
+ }
112
+
113
+ impl FieldConfig {
114
+ fn from_field ( field : & Field ) -> Self {
115
+ let ty = & field. ty ;
116
+ let mut config = Self {
117
+ buffer_type : parse_quote ! { :: bevy_impulse:: Buffer <#ty> } ,
118
+ } ;
119
+
120
+ let attr = field
121
+ . attrs
122
+ . iter ( )
123
+ . find ( |attr| attr. path ( ) . is_ident ( "buffers" ) ) ;
124
+
125
+ if let Some ( attr) = attr {
126
+ attr. parse_nested_meta ( |meta| {
127
+ if meta. path . is_ident ( "buffer_type" ) {
128
+ config. buffer_type = meta. value ( ) ?. parse ( ) ?;
77
129
}
78
130
Ok ( ( ) )
79
131
} )
@@ -85,20 +137,22 @@ impl BufferStructConfig {
85
137
}
86
138
}
87
139
88
- fn get_fields_map ( fields : & syn:: Fields ) -> Result < ( Vec < & Ident > , Vec < & Type > ) > {
140
+ fn get_fields_map ( fields : & syn:: Fields ) -> Result < ( Vec < & Ident > , Vec < & Type > , Vec < FieldConfig > ) > {
89
141
match fields {
90
142
syn:: Fields :: Named ( data) => {
91
143
let mut idents = Vec :: new ( ) ;
92
144
let mut types = Vec :: new ( ) ;
145
+ let mut configs = Vec :: new ( ) ;
93
146
for field in & data. named {
94
147
let ident = field
95
148
. ident
96
149
. as_ref ( )
97
150
. ok_or ( "expected named fields" . to_string ( ) ) ?;
98
151
idents. push ( ident) ;
99
152
types. push ( & field. ty ) ;
153
+ configs. push ( FieldConfig :: from_field ( field) ) ;
100
154
}
101
- Ok ( ( idents, types) )
155
+ Ok ( ( idents, types, configs ) )
102
156
}
103
157
_ => return Err ( "expected named fields" . to_string ( ) ) ,
104
158
}
@@ -113,7 +167,11 @@ fn impl_buffer_map_layout(
113
167
) -> Result < proc_macro2:: TokenStream > {
114
168
let struct_ident = & buffer_struct. ident ;
115
169
let ( impl_generics, ty_generics, where_clause) = buffer_struct. generics . split_for_impl ( ) ;
116
- let ( field_ident, field_type) = get_fields_map ( & item_struct. fields ) ?;
170
+ let ( field_ident, _, field_config) = get_fields_map ( & item_struct. fields ) ?;
171
+ let buffer_type: Vec < & Type > = field_config
172
+ . iter ( )
173
+ . map ( |config| & config. buffer_type )
174
+ . collect ( ) ;
117
175
let map_key: Vec < String > = field_ident. iter ( ) . map ( |v| v. to_string ( ) ) . collect ( ) ;
118
176
119
177
Ok ( quote ! {
@@ -128,16 +186,18 @@ fn impl_buffer_map_layout(
128
186
fn try_from_buffer_map( buffers: & :: bevy_impulse:: BufferMap ) -> Result <Self , :: bevy_impulse:: IncompatibleLayout > {
129
187
let mut compatibility = :: bevy_impulse:: IncompatibleLayout :: default ( ) ;
130
188
#(
131
- let #field_ident = if let Ok ( buffer) = compatibility. require_message_type :: <#field_type >( #map_key, buffers) {
189
+ let #field_ident = if let Ok ( buffer) = compatibility. require_buffer_type :: <#buffer_type >( #map_key, buffers) {
132
190
buffer
133
191
} else {
134
192
return Err ( compatibility) ;
135
193
} ;
136
194
) *
137
195
138
- Ok ( Self { #(
139
- #field_ident,
140
- ) * } )
196
+ Ok ( Self {
197
+ #(
198
+ #field_ident,
199
+ ) *
200
+ } )
141
201
}
142
202
}
143
203
}
@@ -154,7 +214,7 @@ fn impl_joined(
154
214
let struct_ident = & joined_struct. ident ;
155
215
let item_struct_ident = & item_struct. ident ;
156
216
let ( impl_generics, ty_generics, where_clause) = item_struct. generics . split_for_impl ( ) ;
157
- let ( field_ident, _) = get_fields_map ( & item_struct. fields ) ?;
217
+ let ( field_ident, _, _ ) = get_fields_map ( & item_struct. fields ) ?;
158
218
159
219
Ok ( quote ! {
160
220
impl #impl_generics :: bevy_impulse:: Joined for #struct_ident #ty_generics #where_clause {
0 commit comments