bevy_ecs_macros/
world_query.rs

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