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 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 #[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 #[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}