Skip to main content

bevy_ecs_macros/
world_query.rs

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