1
1
use bevy_macro_utils:: ensure_no_collision;
2
2
use proc_macro:: TokenStream ;
3
3
use proc_macro2:: { Ident , Span } ;
4
- use quote:: { quote, ToTokens } ;
4
+ use quote:: { format_ident , quote, ToTokens } ;
5
5
use syn:: {
6
6
parse:: { Parse , ParseStream } ,
7
7
parse_macro_input, parse_quote,
8
8
punctuated:: Punctuated ,
9
- Attribute , Data , DataStruct , DeriveInput , Field , Fields ,
9
+ Attribute , Data , DataStruct , DeriveInput , Field , Index ,
10
10
} ;
11
11
12
12
use crate :: bevy_ecs_path;
@@ -116,34 +116,49 @@ pub fn derive_world_query_impl(input: TokenStream) -> TokenStream {
116
116
fetch_struct_name. clone ( )
117
117
} ;
118
118
119
+ let marker_name =
120
+ ensure_no_collision ( format_ident ! ( "_world_query_derive_marker" ) , tokens. clone ( ) ) ;
121
+
119
122
// Generate a name for the state struct that doesn't conflict
120
123
// with the struct definition.
121
124
let state_struct_name = Ident :: new ( & format ! ( "{struct_name}State" ) , Span :: call_site ( ) ) ;
122
125
let state_struct_name = ensure_no_collision ( state_struct_name, tokens) ;
123
126
124
- let fields = match & ast. data {
125
- Data :: Struct ( DataStruct {
126
- fields : Fields :: Named ( fields) ,
127
- ..
128
- } ) => & fields. named ,
129
- _ => panic ! ( "Expected a struct with named fields" ) ,
127
+ let Data :: Struct ( DataStruct { fields, .. } ) = & ast. data else {
128
+ return syn:: Error :: new (
129
+ Span :: call_site ( ) ,
130
+ "#[derive(WorldQuery)]` only supports structs" ,
131
+ )
132
+ . into_compile_error ( )
133
+ . into ( )
130
134
} ;
131
135
132
136
let mut field_attrs = Vec :: new ( ) ;
133
137
let mut field_visibilities = Vec :: new ( ) ;
134
138
let mut field_idents = Vec :: new ( ) ;
139
+ let mut named_field_idents = Vec :: new ( ) ;
135
140
let mut field_types = Vec :: new ( ) ;
136
141
let mut read_only_field_types = Vec :: new ( ) ;
137
-
138
- for field in fields {
142
+ for ( i, field) in fields. iter ( ) . enumerate ( ) {
139
143
let attrs = match read_world_query_field_info ( field) {
140
144
Ok ( WorldQueryFieldInfo { attrs } ) => attrs,
141
145
Err ( e) => return e. into_compile_error ( ) . into ( ) ,
142
146
} ;
143
147
148
+ let named_field_ident = field
149
+ . ident
150
+ . as_ref ( )
151
+ . cloned ( )
152
+ . unwrap_or_else ( || format_ident ! ( "f{i}" ) ) ;
153
+ let i = Index :: from ( i) ;
154
+ let field_ident = field
155
+ . ident
156
+ . as_ref ( )
157
+ . map_or ( quote ! { #i } , |i| quote ! { #i } ) ;
158
+ field_idents. push ( field_ident) ;
159
+ named_field_idents. push ( named_field_ident) ;
144
160
field_attrs. push ( attrs) ;
145
161
field_visibilities. push ( field. vis . clone ( ) ) ;
146
- field_idents. push ( field. ident . as_ref ( ) . unwrap ( ) . clone ( ) ) ;
147
162
let field_ty = field. ty . clone ( ) ;
148
163
field_types. push ( quote ! ( #field_ty) ) ;
149
164
read_only_field_types. push ( quote ! ( <#field_ty as #path:: query:: WorldQuery >:: ReadOnly ) ) ;
@@ -176,15 +191,34 @@ pub fn derive_world_query_impl(input: TokenStream) -> TokenStream {
176
191
& field_types
177
192
} ;
178
193
179
- let item_struct = quote ! {
180
- #derive_macro_call
181
- #[ doc = "Automatically generated [`WorldQuery`] item type for [`" ]
182
- #[ doc = stringify!( #struct_name) ]
183
- #[ doc = "`], returned when iterating over query results." ]
184
- #[ automatically_derived]
185
- #visibility struct #item_struct_name #user_impl_generics_with_world #user_where_clauses_with_world {
186
- #( #( #field_attrs) * #field_visibilities #field_idents: <#field_types as #path:: query:: WorldQuery >:: Item <' __w>, ) *
187
- }
194
+ let item_struct = match fields {
195
+ syn:: Fields :: Named ( _) => quote ! {
196
+ #derive_macro_call
197
+ #[ doc = "Automatically generated [`WorldQuery`] item type for [`" ]
198
+ #[ doc = stringify!( #struct_name) ]
199
+ #[ doc = "`], returned when iterating over query results." ]
200
+ #[ automatically_derived]
201
+ #visibility struct #item_struct_name #user_impl_generics_with_world #user_where_clauses_with_world {
202
+ #( #( #field_attrs) * #field_visibilities #field_idents: <#field_types as #path:: query:: WorldQuery >:: Item <' __w>, ) *
203
+ }
204
+ } ,
205
+ syn:: Fields :: Unnamed ( _) => quote ! {
206
+ #derive_macro_call
207
+ #[ doc = "Automatically generated [`WorldQuery`] item type for [`" ]
208
+ #[ doc = stringify!( #struct_name) ]
209
+ #[ doc = "`], returned when iterating over query results." ]
210
+ #[ automatically_derived]
211
+ #visibility struct #item_struct_name #user_impl_generics_with_world #user_where_clauses_with_world(
212
+ #( #field_visibilities <#field_types as #path:: query:: WorldQuery >:: Item <' __w>, ) *
213
+ ) ;
214
+ } ,
215
+ syn:: Fields :: Unit => quote ! {
216
+ #[ doc = "Automatically generated [`WorldQuery`] item type for [`" ]
217
+ #[ doc = stringify!( #struct_name) ]
218
+ #[ doc = "`], returned when iterating over query results." ]
219
+ #[ automatically_derived]
220
+ #visibility type #item_struct_name #user_ty_generics_with_world = #struct_name #user_ty_generics;
221
+ } ,
188
222
} ;
189
223
190
224
let query_impl = quote ! {
@@ -194,7 +228,8 @@ pub fn derive_world_query_impl(input: TokenStream) -> TokenStream {
194
228
#[ doc = "`], used to define the world data accessed by this query." ]
195
229
#[ automatically_derived]
196
230
#visibility struct #fetch_struct_name #user_impl_generics_with_world #user_where_clauses_with_world {
197
- #( #field_idents: <#field_types as #path:: query:: WorldQuery >:: Fetch <' __w>, ) *
231
+ #( #named_field_idents: <#field_types as #path:: query:: WorldQuery >:: Fetch <' __w>, ) *
232
+ #marker_name: & ' __w ( ) ,
198
233
}
199
234
200
235
// SAFETY: `update_component_access` and `update_archetype_component_access` are called on every field
@@ -223,14 +258,15 @@ pub fn derive_world_query_impl(input: TokenStream) -> TokenStream {
223
258
_this_run: #path:: component:: Tick ,
224
259
) -> <Self as #path:: query:: WorldQuery >:: Fetch <' __w> {
225
260
#fetch_struct_name {
226
- #( #field_idents :
261
+ #( #named_field_idents :
227
262
<#field_types>:: init_fetch(
228
263
_world,
229
- & state. #field_idents ,
264
+ & state. #named_field_idents ,
230
265
_last_run,
231
266
_this_run,
232
267
) ,
233
268
) *
269
+ #marker_name: & ( ) ,
234
270
}
235
271
}
236
272
@@ -239,8 +275,9 @@ pub fn derive_world_query_impl(input: TokenStream) -> TokenStream {
239
275
) -> <Self as #path:: query:: WorldQuery >:: Fetch <' __w> {
240
276
#fetch_struct_name {
241
277
#(
242
- #field_idents : <#field_types>:: clone_fetch( & _fetch. #field_idents ) ,
278
+ #named_field_idents : <#field_types>:: clone_fetch( & _fetch. #named_field_idents ) ,
243
279
) *
280
+ #marker_name: & ( ) ,
244
281
}
245
282
}
246
283
@@ -256,7 +293,7 @@ pub fn derive_world_query_impl(input: TokenStream) -> TokenStream {
256
293
_archetype: & ' __w #path:: archetype:: Archetype ,
257
294
_table: & ' __w #path:: storage:: Table
258
295
) {
259
- #( <#field_types>:: set_archetype( & mut _fetch. #field_idents , & _state. #field_idents , _archetype, _table) ; ) *
296
+ #( <#field_types>:: set_archetype( & mut _fetch. #named_field_idents , & _state. #named_field_idents , _archetype, _table) ; ) *
260
297
}
261
298
262
299
/// SAFETY: we call `set_table` for each member that implements `Fetch`
@@ -266,7 +303,7 @@ pub fn derive_world_query_impl(input: TokenStream) -> TokenStream {
266
303
_state: & Self :: State ,
267
304
_table: & ' __w #path:: storage:: Table
268
305
) {
269
- #( <#field_types>:: set_table( & mut _fetch. #field_idents , & _state. #field_idents , _table) ; ) *
306
+ #( <#field_types>:: set_table( & mut _fetch. #named_field_idents , & _state. #named_field_idents , _table) ; ) *
270
307
}
271
308
272
309
/// SAFETY: we call `fetch` for each member that implements `Fetch`.
@@ -277,7 +314,7 @@ pub fn derive_world_query_impl(input: TokenStream) -> TokenStream {
277
314
_table_row: #path:: storage:: TableRow ,
278
315
) -> <Self as #path:: query:: WorldQuery >:: Item <' __w> {
279
316
Self :: Item {
280
- #( #field_idents: <#field_types>:: fetch( & mut _fetch. #field_idents , _entity, _table_row) , ) *
317
+ #( #field_idents: <#field_types>:: fetch( & mut _fetch. #named_field_idents , _entity, _table_row) , ) *
281
318
}
282
319
}
283
320
@@ -288,11 +325,11 @@ pub fn derive_world_query_impl(input: TokenStream) -> TokenStream {
288
325
_entity: #path:: entity:: Entity ,
289
326
_table_row: #path:: storage:: TableRow ,
290
327
) -> bool {
291
- true #( && <#field_types>:: filter_fetch( & mut _fetch. #field_idents , _entity, _table_row) ) *
328
+ true #( && <#field_types>:: filter_fetch( & mut _fetch. #named_field_idents , _entity, _table_row) ) *
292
329
}
293
330
294
331
fn update_component_access( state: & Self :: State , _access: & mut #path:: query:: FilteredAccess <#path:: component:: ComponentId >) {
295
- #( <#field_types>:: update_component_access( & state. #field_idents , _access) ; ) *
332
+ #( <#field_types>:: update_component_access( & state. #named_field_idents , _access) ; ) *
296
333
}
297
334
298
335
fn update_archetype_component_access(
@@ -301,18 +338,18 @@ pub fn derive_world_query_impl(input: TokenStream) -> TokenStream {
301
338
_access: & mut #path:: query:: Access <#path:: archetype:: ArchetypeComponentId >
302
339
) {
303
340
#(
304
- <#field_types>:: update_archetype_component_access( & state. #field_idents , _archetype, _access) ;
341
+ <#field_types>:: update_archetype_component_access( & state. #named_field_idents , _archetype, _access) ;
305
342
) *
306
343
}
307
344
308
345
fn init_state( world: & mut #path:: world:: World ) -> #state_struct_name #user_ty_generics {
309
346
#state_struct_name {
310
- #( #field_idents : <#field_types>:: init_state( world) , ) *
347
+ #( #named_field_idents : <#field_types>:: init_state( world) , ) *
311
348
}
312
349
}
313
350
314
351
fn matches_component_set( state: & Self :: State , _set_contains_id: & impl Fn ( #path:: component:: ComponentId ) -> bool ) -> bool {
315
- true #( && <#field_types>:: matches_component_set( & state. #field_idents , _set_contains_id) ) *
352
+ true #( && <#field_types>:: matches_component_set( & state. #named_field_idents , _set_contains_id) ) *
316
353
}
317
354
}
318
355
} ;
@@ -328,7 +365,7 @@ pub fn derive_world_query_impl(input: TokenStream) -> TokenStream {
328
365
#[ doc = "`]." ]
329
366
#[ automatically_derived]
330
367
#visibility struct #read_only_struct_name #user_impl_generics #user_where_clauses {
331
- #( #field_visibilities #field_idents : #read_only_field_types, ) *
368
+ #( #field_visibilities #named_field_idents : #read_only_field_types, ) *
332
369
}
333
370
334
371
#readonly_state
@@ -374,7 +411,7 @@ pub fn derive_world_query_impl(input: TokenStream) -> TokenStream {
374
411
#[ doc = "`], used for caching." ]
375
412
#[ automatically_derived]
376
413
#visibility struct #state_struct_name #user_impl_generics #user_where_clauses {
377
- #( #field_idents : <#field_types as #path:: query:: WorldQuery >:: State , ) *
414
+ #( #named_field_idents : <#field_types as #path:: query:: WorldQuery >:: State , ) *
378
415
}
379
416
380
417
#mutable_impl
0 commit comments