Skip to content

Commit 57fa93c

Browse files
committed
Remove ReadOnlyFetch
1 parent 4050c8a commit 57fa93c

File tree

9 files changed

+432
-470
lines changed

9 files changed

+432
-470
lines changed

crates/bevy_ecs/macros/src/fetch.rs

Lines changed: 73 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,11 @@ pub fn derive_world_query_impl(ast: DeriveInput) -> TokenStream {
9090
user_generics_with_world.split_for_impl();
9191

9292
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+
};
9398

9499
let item_struct_name = Ident::new(&format!("{}Item", struct_name), Span::call_site());
95100
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 {
178183
#(#ignored_field_idents: #ignored_field_types,)*
179184
}
180185

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>
182188
for #fetch_struct_name #user_ty_generics_with_world #user_where_clauses_with_world {
183189

184190
type Item = #item_struct_name #user_ty_generics_with_world;
@@ -248,6 +254,17 @@ pub fn derive_world_query_impl(ast: DeriveInput) -> TokenStream {
248254
unsafe fn archetype_filter_fetch(&mut self, _archetype_index: usize) -> bool {
249255
true #(&& self.#field_idents.archetype_filter_fetch(_archetype_index))*
250256
}
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+
}
251268
}
252269
}
253270
};
@@ -262,23 +279,14 @@ pub fn derive_world_query_impl(ast: DeriveInput) -> TokenStream {
262279
#(#ignored_field_idents: #ignored_field_types,)*
263280
}
264281

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 {
267283
fn init(world: &mut #path::world::World) -> Self {
268284
#state_struct_name {
269285
#(#field_idents: <<#field_types as #path::query::WorldQuery>::State as #path::query::FetchState>::init(world),)*
270286
#(#ignored_field_idents: Default::default(),)*
271287
}
272288
}
273289

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-
282290
fn matches_component_set(&self, _set_contains_id: &impl Fn(#path::component::ComponentId) -> bool) -> bool {
283291
true #(&& self.#field_idents.matches_component_set(_set_contains_id))*
284292

@@ -290,29 +298,66 @@ pub fn derive_world_query_impl(ast: DeriveInput) -> TokenStream {
290298
impl_fetch(
291299
true,
292300
read_only_fetch_struct_name.clone(),
293-
read_only_item_struct_name,
301+
read_only_item_struct_name.clone(),
294302
)
295303
} else {
296304
quote! {}
297305
};
298306

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+
299344
let read_only_asserts = if fetch_struct_attributes.is_mutable {
300345
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 >(); )*
305350
}
306351
} else {
307352
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`
310355
// members that don't implement it. I.e.:
311356
// ```
312357
// #[derive(WorldQuery)]
313358
// pub struct Foo { a: &'static mut MyComponent }
314359
// ```
315-
#( assert_readonly::<#path::query::QueryFetch<'__w, #field_types>>(); )*
360+
#( assert_readonly::<#field_types>(); )*
316361
}
317362
};
318363

@@ -323,7 +368,12 @@ pub fn derive_world_query_impl(ast: DeriveInput) -> TokenStream {
323368

324369
#read_only_fetch_impl
325370

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;
327377
type State = #state_struct_name #user_ty_generics;
328378
fn shrink<'__wlong: '__wshort, '__wshort>(item: #path::query::#item_type_alias<'__wlong, Self>)
329379
-> #path::query::#item_type_alias<'__wshort, Self> {
@@ -340,19 +390,18 @@ pub fn derive_world_query_impl(ast: DeriveInput) -> TokenStream {
340390

341391
impl #user_impl_generics_with_world #path::query::WorldQueryGats<'__w> for #struct_name #user_ty_generics #user_where_clauses {
342392
type Fetch = #fetch_struct_name #user_ty_generics_with_world;
343-
type ReadOnlyFetch = #read_only_fetch_struct_name #user_ty_generics_with_world;
344393
type _State = #state_struct_name #user_ty_generics;
345394
}
346395

347396
/// 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 {}
350399

351400
#[allow(dead_code)]
352401
const _: () = {
353402
fn assert_readonly<T>()
354403
where
355-
T: #path::query::ReadOnlyFetch,
404+
T: #path::query::ReadOnlyWorldQuery,
356405
{
357406
}
358407

0 commit comments

Comments
 (0)