@@ -90,6 +90,11 @@ pub fn derive_world_query_impl(ast: DeriveInput) -> TokenStream {
90
90
user_generics_with_world. split_for_impl ( ) ;
91
91
92
92
let struct_name = ast. ident . clone ( ) ;
93
+ let read_only_struct_name = if fetch_struct_attributes. is_mutable {
94
+ Ident :: new ( & format ! ( "{}ReadOnly" , struct_name) , Span :: call_site ( ) )
95
+ } else {
96
+ struct_name. clone ( )
97
+ } ;
93
98
94
99
let item_struct_name = Ident :: new ( & format ! ( "{}Item" , struct_name) , Span :: call_site ( ) ) ;
95
100
let read_only_item_struct_name = if fetch_struct_attributes. is_mutable {
@@ -178,7 +183,8 @@ pub fn derive_world_query_impl(ast: DeriveInput) -> TokenStream {
178
183
#( #ignored_field_idents: #ignored_field_types, ) *
179
184
}
180
185
181
- impl #user_impl_generics_with_world #path:: query:: Fetch <' __w>
186
+ // SAFETY: `update_component_access` and `update_archetype_component_access` are called on every field
187
+ unsafe impl #user_impl_generics_with_world #path:: query:: Fetch <' __w>
182
188
for #fetch_struct_name #user_ty_generics_with_world #user_where_clauses_with_world {
183
189
184
190
type Item = #item_struct_name #user_ty_generics_with_world;
@@ -248,6 +254,17 @@ pub fn derive_world_query_impl(ast: DeriveInput) -> TokenStream {
248
254
unsafe fn archetype_filter_fetch( & mut self , _archetype_index: usize ) -> bool {
249
255
true #( && self . #field_idents. archetype_filter_fetch( _archetype_index) ) *
250
256
}
257
+
258
+ fn update_component_access( state: & Self :: State , _access: & mut #path:: query:: FilteredAccess <#path:: component:: ComponentId >) {
259
+ #( #path:: query:: #fetch_type_alias:: <' static , #field_types> :: update_component_access( & state. #field_idents, _access) ; ) *
260
+ }
261
+
262
+ fn update_archetype_component_access( state: & Self :: State , _archetype: & #path:: archetype:: Archetype , _access: & mut #path:: query:: Access <#path:: archetype:: ArchetypeComponentId >) {
263
+ #(
264
+ #path:: query:: #fetch_type_alias:: <' static , #field_types>
265
+ :: update_archetype_component_access( & state. #field_idents, _archetype, _access) ;
266
+ ) *
267
+ }
251
268
}
252
269
}
253
270
} ;
@@ -262,23 +279,14 @@ pub fn derive_world_query_impl(ast: DeriveInput) -> TokenStream {
262
279
#( #ignored_field_idents: #ignored_field_types, ) *
263
280
}
264
281
265
- // SAFETY: `update_component_access` and `update_archetype_component_access` are called for each item in the struct
266
- unsafe impl #user_impl_generics #path:: query:: FetchState for #state_struct_name #user_ty_generics #user_where_clauses {
282
+ impl #user_impl_generics #path:: query:: FetchState for #state_struct_name #user_ty_generics #user_where_clauses {
267
283
fn init( world: & mut #path:: world:: World ) -> Self {
268
284
#state_struct_name {
269
285
#( #field_idents: <<#field_types as #path:: query:: WorldQuery >:: State as #path:: query:: FetchState >:: init( world) , ) *
270
286
#( #ignored_field_idents: Default :: default ( ) , ) *
271
287
}
272
288
}
273
289
274
- fn update_component_access( & self , _access: & mut #path:: query:: FilteredAccess <#path:: component:: ComponentId >) {
275
- #( self . #field_idents. update_component_access( _access) ; ) *
276
- }
277
-
278
- fn update_archetype_component_access( & self , _archetype: & #path:: archetype:: Archetype , _access: & mut #path:: query:: Access <#path:: archetype:: ArchetypeComponentId >) {
279
- #( self . #field_idents. update_archetype_component_access( _archetype, _access) ; ) *
280
- }
281
-
282
290
fn matches_component_set( & self , _set_contains_id: & impl Fn ( #path:: component:: ComponentId ) -> bool ) -> bool {
283
291
true #( && self . #field_idents. matches_component_set( _set_contains_id) ) *
284
292
@@ -290,29 +298,66 @@ pub fn derive_world_query_impl(ast: DeriveInput) -> TokenStream {
290
298
impl_fetch (
291
299
true ,
292
300
read_only_fetch_struct_name. clone ( ) ,
293
- read_only_item_struct_name,
301
+ read_only_item_struct_name. clone ( ) ,
294
302
)
295
303
} else {
296
304
quote ! { }
297
305
} ;
298
306
307
+ let read_only_world_query_impl = if fetch_struct_attributes. is_mutable {
308
+ quote ! {
309
+ #[ automatically_derived]
310
+ #visibility struct #read_only_struct_name #user_impl_generics #user_where_clauses {
311
+ #( #field_idents: < #field_types as #path:: query:: WorldQuery >:: ReadOnly , ) *
312
+ #( #( #ignored_field_attrs) * #ignored_field_visibilities #ignored_field_idents: #ignored_field_types, ) *
313
+ }
314
+
315
+ // SAFETY: `ROQueryFetch<Self>` is the same as `QueryFetch<Self>`
316
+ unsafe impl #user_impl_generics #path:: query:: WorldQuery for #read_only_struct_name #user_ty_generics #user_where_clauses {
317
+ type ReadOnly = Self ;
318
+ type State = #state_struct_name #user_ty_generics;
319
+
320
+ fn shrink<' __wlong: ' __wshort, ' __wshort>( item: #path:: query:: #item_type_alias<' __wlong, Self >)
321
+ -> #path:: query:: #item_type_alias<' __wshort, Self > {
322
+ #read_only_item_struct_name {
323
+ #(
324
+ #field_idents : <
325
+ < #field_types as #path:: query:: WorldQuery >:: ReadOnly as #path:: query:: WorldQuery
326
+ > :: shrink( item. #field_idents ) ,
327
+ ) *
328
+ #(
329
+ #ignored_field_idents: item. #ignored_field_idents,
330
+ ) *
331
+ }
332
+ }
333
+ }
334
+
335
+ impl #user_impl_generics_with_world #path:: query:: WorldQueryGats <' __w> for #read_only_struct_name #user_ty_generics #user_where_clauses {
336
+ type Fetch = #read_only_fetch_struct_name #user_ty_generics_with_world;
337
+ type _State = #state_struct_name #user_ty_generics;
338
+ }
339
+ }
340
+ } else {
341
+ quote ! { }
342
+ } ;
343
+
299
344
let read_only_asserts = if fetch_struct_attributes. is_mutable {
300
345
quote ! {
301
- // Double-check that the data fetched by `ROQueryFetch ` is read-only.
302
- // This is technically unnecessary as `<_ as WorldQueryGats<'world>>::ReadOnlyFetch: ReadOnlyFetch `
303
- // but to protect against future mistakes we assert the assoc type implements `ReadOnlyFetch ` anyway
304
- #( assert_readonly:: <# path:: query:: ROQueryFetch < ' __w , #field_types> >( ) ; ) *
346
+ // Double-check that the data fetched by `<_ as WorldQuery>::ReadOnly ` is read-only.
347
+ // This is technically unnecessary as `<_ as WorldQuery>::ReadOnly: ReadOnlyWorldQuery `
348
+ // but to protect against future mistakes we assert the assoc type implements `ReadOnlyWorldQuery ` anyway
349
+ #( assert_readonly:: < < #field_types as # path:: query:: WorldQuery > :: ReadOnly >( ) ; ) *
305
350
}
306
351
} else {
307
352
quote ! {
308
- // Statically checks that the safety guarantee of `ReadOnlyFetch ` for `$fetch_struct_name` actually holds true.
309
- // We need this to make sure that we don't compile `ReadOnlyFetch ` if our struct contains nested `WorldQuery`
353
+ // Statically checks that the safety guarantee of `ReadOnlyWorldQuery ` for `$fetch_struct_name` actually holds true.
354
+ // We need this to make sure that we don't compile `ReadOnlyWorldQuery ` if our struct contains nested `WorldQuery`
310
355
// members that don't implement it. I.e.:
311
356
// ```
312
357
// #[derive(WorldQuery)]
313
358
// pub struct Foo { a: &'static mut MyComponent }
314
359
// ```
315
- #( assert_readonly:: <#path :: query :: QueryFetch < ' __w , # field_types> >( ) ; ) *
360
+ #( assert_readonly:: <#field_types>( ) ; ) *
316
361
}
317
362
} ;
318
363
@@ -323,7 +368,12 @@ pub fn derive_world_query_impl(ast: DeriveInput) -> TokenStream {
323
368
324
369
#read_only_fetch_impl
325
370
326
- impl #user_impl_generics #path:: query:: WorldQuery for #struct_name #user_ty_generics #user_where_clauses {
371
+ #read_only_world_query_impl
372
+
373
+ // SAFETY: if the worldquery is mutable this defers to soundness of the `#field_types: WorldQuery` impl, otherwise
374
+ // if the world query is immutable then `#read_only_struct_name #user_ty_generics` is the same type as `#struct_name #user_ty_generics`
375
+ unsafe impl #user_impl_generics #path:: query:: WorldQuery for #struct_name #user_ty_generics #user_where_clauses {
376
+ type ReadOnly = #read_only_struct_name #user_ty_generics;
327
377
type State = #state_struct_name #user_ty_generics;
328
378
fn shrink<' __wlong: ' __wshort, ' __wshort>( item: #path:: query:: #item_type_alias<' __wlong, Self >)
329
379
-> #path:: query:: #item_type_alias<' __wshort, Self > {
@@ -340,19 +390,18 @@ pub fn derive_world_query_impl(ast: DeriveInput) -> TokenStream {
340
390
341
391
impl #user_impl_generics_with_world #path:: query:: WorldQueryGats <' __w> for #struct_name #user_ty_generics #user_where_clauses {
342
392
type Fetch = #fetch_struct_name #user_ty_generics_with_world;
343
- type ReadOnlyFetch = #read_only_fetch_struct_name #user_ty_generics_with_world;
344
393
type _State = #state_struct_name #user_ty_generics;
345
394
}
346
395
347
396
/// SAFETY: each item in the struct is read only
348
- unsafe impl #user_impl_generics_with_world #path:: query:: ReadOnlyFetch
349
- for #read_only_fetch_struct_name #user_ty_generics_with_world #user_where_clauses_with_world { }
397
+ unsafe impl #user_impl_generics #path:: query:: ReadOnlyWorldQuery
398
+ for #read_only_struct_name #user_ty_generics #user_where_clauses { }
350
399
351
400
#[ allow( dead_code) ]
352
401
const _: ( ) = {
353
402
fn assert_readonly<T >( )
354
403
where
355
- T : #path:: query:: ReadOnlyFetch ,
404
+ T : #path:: query:: ReadOnlyWorldQuery ,
356
405
{
357
406
}
358
407
0 commit comments