bevy_ecs_macros/
world_query.rs

1use proc_macro2::Ident;
2use quote::quote;
3use syn::{Attribute, Fields, ImplGenerics, TypeGenerics, Visibility, WhereClause};
4
5#[allow(clippy::too_many_arguments)]
6pub(crate) fn item_struct(
7    path: &syn::Path,
8    fields: &Fields,
9    derive_macro_call: &proc_macro2::TokenStream,
10    struct_name: &Ident,
11    visibility: &Visibility,
12    item_struct_name: &Ident,
13    field_types: &Vec<proc_macro2::TokenStream>,
14    user_impl_generics_with_world: &ImplGenerics,
15    field_attrs: &Vec<Vec<Attribute>>,
16    field_visibilities: &Vec<Visibility>,
17    field_idents: &Vec<proc_macro2::TokenStream>,
18    user_ty_generics: &TypeGenerics,
19    user_ty_generics_with_world: &TypeGenerics,
20    user_where_clauses_with_world: Option<&WhereClause>,
21) -> proc_macro2::TokenStream {
22    let item_attrs = quote!(
23            #[doc = "Automatically generated [`WorldQuery`] item type for [`"]
24            #[doc = stringify!(#struct_name)]
25            #[doc = "`], returned when iterating over query results."]
26            #[automatically_derived]
27    );
28
29    match fields {
30        Fields::Named(_) => quote! {
31            #derive_macro_call
32            #item_attrs
33            #visibility struct #item_struct_name #user_impl_generics_with_world #user_where_clauses_with_world {
34                #(#(#field_attrs)* #field_visibilities #field_idents: <#field_types as #path::query::WorldQuery>::Item<'__w>,)*
35            }
36        },
37        Fields::Unnamed(_) => quote! {
38            #derive_macro_call
39            #item_attrs
40            #visibility struct #item_struct_name #user_impl_generics_with_world #user_where_clauses_with_world(
41                #( #field_visibilities <#field_types as #path::query::WorldQuery>::Item<'__w>, )*
42            );
43        },
44        Fields::Unit => quote! {
45            #item_attrs
46            #visibility type #item_struct_name #user_ty_generics_with_world = #struct_name #user_ty_generics;
47        },
48    }
49}
50
51#[allow(clippy::too_many_arguments)]
52pub(crate) fn world_query_impl(
53    path: &syn::Path,
54    struct_name: &Ident,
55    visibility: &Visibility,
56    item_struct_name: &Ident,
57    fetch_struct_name: &Ident,
58    field_types: &Vec<proc_macro2::TokenStream>,
59    user_impl_generics: &ImplGenerics,
60    user_impl_generics_with_world: &ImplGenerics,
61    field_idents: &Vec<proc_macro2::TokenStream>,
62    user_ty_generics: &TypeGenerics,
63    user_ty_generics_with_world: &TypeGenerics,
64    named_field_idents: &Vec<Ident>,
65    marker_name: &Ident,
66    state_struct_name: &Ident,
67    user_where_clauses: Option<&WhereClause>,
68    user_where_clauses_with_world: Option<&WhereClause>,
69) -> proc_macro2::TokenStream {
70    quote! {
71        #[doc(hidden)]
72        #[doc = "Automatically generated internal [`WorldQuery`] fetch type for [`"]
73        #[doc = stringify!(#struct_name)]
74        #[doc = "`], used to define the world data accessed by this query."]
75        #[automatically_derived]
76        #visibility struct #fetch_struct_name #user_impl_generics_with_world #user_where_clauses_with_world {
77            #(#named_field_idents: <#field_types as #path::query::WorldQuery>::Fetch<'__w>,)*
78            #marker_name: &'__w (),
79        }
80
81        impl #user_impl_generics_with_world Clone for #fetch_struct_name #user_ty_generics_with_world
82            #user_where_clauses_with_world {
83                fn clone(&self) -> Self {
84                    Self {
85                        #(#named_field_idents: self.#named_field_idents.clone(),)*
86                        #marker_name: &(),
87                    }
88                }
89            }
90
91        // SAFETY: `update_component_access` and `update_archetype_component_access` are called on every field
92        unsafe impl #user_impl_generics #path::query::WorldQuery
93            for #struct_name #user_ty_generics #user_where_clauses {
94
95            type Item<'__w> = #item_struct_name #user_ty_generics_with_world;
96            type Fetch<'__w> = #fetch_struct_name #user_ty_generics_with_world;
97            type State = #state_struct_name #user_ty_generics;
98
99            fn shrink<'__wlong: '__wshort, '__wshort>(
100                item: <#struct_name #user_ty_generics as #path::query::WorldQuery>::Item<'__wlong>
101            ) -> <#struct_name #user_ty_generics as #path::query::WorldQuery>::Item<'__wshort> {
102                #item_struct_name {
103                    #(
104                        #field_idents: <#field_types>::shrink(item.#field_idents),
105                    )*
106                }
107            }
108
109            unsafe fn init_fetch<'__w>(
110                _world: #path::world::unsafe_world_cell::UnsafeWorldCell<'__w>,
111                state: &Self::State,
112                _last_run: #path::component::Tick,
113                _this_run: #path::component::Tick,
114            ) -> <Self as #path::query::WorldQuery>::Fetch<'__w> {
115                #fetch_struct_name {
116                    #(#named_field_idents:
117                        <#field_types>::init_fetch(
118                            _world,
119                            &state.#named_field_idents,
120                            _last_run,
121                            _this_run,
122                        ),
123                    )*
124                    #marker_name: &(),
125                }
126            }
127
128            const IS_DENSE: bool = true #(&& <#field_types>::IS_DENSE)*;
129
130            /// SAFETY: we call `set_archetype` for each member that implements `Fetch`
131            #[inline]
132            unsafe fn set_archetype<'__w>(
133                _fetch: &mut <Self as #path::query::WorldQuery>::Fetch<'__w>,
134                _state: &Self::State,
135                _archetype: &'__w #path::archetype::Archetype,
136                _table: &'__w #path::storage::Table
137            ) {
138                #(<#field_types>::set_archetype(&mut _fetch.#named_field_idents, &_state.#named_field_idents, _archetype, _table);)*
139            }
140
141            /// SAFETY: we call `set_table` for each member that implements `Fetch`
142            #[inline]
143            unsafe fn set_table<'__w>(
144                _fetch: &mut <Self as #path::query::WorldQuery>::Fetch<'__w>,
145                _state: &Self::State,
146                _table: &'__w #path::storage::Table
147            ) {
148                #(<#field_types>::set_table(&mut _fetch.#named_field_idents, &_state.#named_field_idents, _table);)*
149            }
150
151            /// SAFETY: we call `fetch` for each member that implements `Fetch`.
152            #[inline(always)]
153            unsafe fn fetch<'__w>(
154                _fetch: &mut <Self as #path::query::WorldQuery>::Fetch<'__w>,
155                _entity: #path::entity::Entity,
156                _table_row: #path::storage::TableRow,
157            ) -> <Self as #path::query::WorldQuery>::Item<'__w> {
158                Self::Item {
159                    #(#field_idents: <#field_types>::fetch(&mut _fetch.#named_field_idents, _entity, _table_row),)*
160                }
161            }
162
163            fn update_component_access(state: &Self::State, _access: &mut #path::query::FilteredAccess<#path::component::ComponentId>) {
164                #( <#field_types>::update_component_access(&state.#named_field_idents, _access); )*
165            }
166
167            fn init_state(world: &mut #path::world::World) -> #state_struct_name #user_ty_generics {
168                #state_struct_name {
169                    #(#named_field_idents: <#field_types>::init_state(world),)*
170                }
171            }
172
173            fn get_state(components: &#path::component::Components) -> Option<#state_struct_name #user_ty_generics> {
174                Some(#state_struct_name {
175                    #(#named_field_idents: <#field_types>::get_state(components)?,)*
176                })
177            }
178
179            fn matches_component_set(state: &Self::State, _set_contains_id: &impl Fn(#path::component::ComponentId) -> bool) -> bool {
180                true #(&& <#field_types>::matches_component_set(&state.#named_field_idents, _set_contains_id))*
181            }
182        }
183    }
184}