Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bevyengine
GitHub Repository: bevyengine/bevy
Path: blob/main/crates/bevy_ecs/macros/src/query_data.rs
9367 views
1
use bevy_macro_utils::{ensure_no_collision, get_struct_fields};
2
use proc_macro::TokenStream;
3
use proc_macro2::{Ident, Span};
4
use quote::{format_ident, quote};
5
use syn::{
6
parse_macro_input, parse_quote, punctuated::Punctuated, token::Comma, Attribute, DeriveInput,
7
Fields, ImplGenerics, Member, Meta, Type, TypeGenerics, Visibility, WhereClause,
8
};
9
10
use crate::{
11
bevy_ecs_path,
12
world_query::{item_struct, world_query_impl},
13
};
14
15
#[derive(Default)]
16
struct QueryDataAttributes {
17
pub is_mutable: bool,
18
19
pub is_contiguous_mutable: bool,
20
pub is_contiguous_immutable: bool,
21
22
pub derive_args: Punctuated<Meta, Comma>,
23
}
24
25
static MUTABLE_ATTRIBUTE_NAME: &str = "mutable";
26
static DERIVE_ATTRIBUTE_NAME: &str = "derive";
27
static CONTIGUOUS_ATTRIBUTE_NAME: &str = "contiguous";
28
29
mod field_attr_keywords {
30
syn::custom_keyword!(ignore);
31
}
32
33
pub static QUERY_DATA_ATTRIBUTE_NAME: &str = "query_data";
34
35
fn contiguous_item_struct(
36
path: &syn::Path,
37
fields: &Fields,
38
derive_macro_call: &proc_macro2::TokenStream,
39
struct_name: &Ident,
40
visibility: &Visibility,
41
item_struct_name: &Ident,
42
field_types: &Vec<Type>,
43
user_impl_generics_with_world_and_state: &ImplGenerics,
44
field_attrs: &Vec<Vec<Attribute>>,
45
field_visibilities: &Vec<Visibility>,
46
field_members: &Vec<Member>,
47
user_ty_generics: &TypeGenerics,
48
user_ty_generics_with_world_and_state: &TypeGenerics,
49
user_where_clauses_with_world_and_state: Option<&WhereClause>,
50
) -> proc_macro2::TokenStream {
51
let item_attrs = quote! {
52
#[doc = concat!(
53
"Automatically generated [`ContiguousQueryData`](",
54
stringify!(#path),
55
"::fetch::ContiguousQueryData) item type for [`",
56
stringify!(#struct_name),
57
"`], returned when iterating over contiguous query results",
58
)]
59
#[automatically_derived]
60
};
61
62
match fields {
63
Fields::Named(_) => quote! {
64
#derive_macro_call
65
#item_attrs
66
#visibility struct #item_struct_name #user_impl_generics_with_world_and_state #user_where_clauses_with_world_and_state {
67
#(#(#field_attrs)* #field_visibilities #field_members: <#field_types as #path::query::ContiguousQueryData>::Contiguous<'__w, '__s>,)*
68
}
69
},
70
Fields::Unnamed(_) => quote! {
71
#derive_macro_call
72
#item_attrs
73
#visibility struct #item_struct_name #user_impl_generics_with_world_and_state #user_where_clauses_with_world_and_state (
74
#( #field_visibilities <#field_types as #path::query::ContiguousQueryData>::Contiguous<'__w, '__s>, )*
75
)
76
},
77
Fields::Unit => quote! {
78
#item_attrs
79
#visibility type #item_struct_name #user_ty_generics_with_world_and_state = #struct_name #user_ty_generics;
80
},
81
}
82
}
83
84
fn contiguous_query_data_impl(
85
path: &syn::Path,
86
struct_name: &Ident,
87
contiguous_item_struct_name: &Ident,
88
field_types: &Vec<Type>,
89
user_impl_generics: &ImplGenerics,
90
user_ty_generics: &TypeGenerics,
91
user_ty_generics_with_world_and_state: &TypeGenerics,
92
field_members: &Vec<Member>,
93
field_aliases: &Vec<Ident>,
94
user_where_clauses: Option<&WhereClause>,
95
) -> proc_macro2::TokenStream {
96
quote! {
97
impl #user_impl_generics #path::query::ContiguousQueryData for #struct_name #user_ty_generics #user_where_clauses {
98
type Contiguous<'__w, '__s> = #contiguous_item_struct_name #user_ty_generics_with_world_and_state;
99
100
unsafe fn fetch_contiguous<'__w, '__s>(
101
_state: &'__s <Self as #path::query::WorldQuery>::State,
102
_fetch: &mut <Self as #path::query::WorldQuery>::Fetch<'__w>,
103
_entities: &'__w [#path::entity::Entity],
104
) -> Self::Contiguous<'__w, '__s> {
105
#contiguous_item_struct_name {
106
#(
107
#field_members:
108
<#field_types>::fetch_contiguous(
109
&_state.#field_aliases,
110
&mut _fetch.#field_aliases,
111
_entities,
112
),
113
)*
114
}
115
}
116
}
117
}
118
}
119
120
pub fn derive_query_data_impl(input: TokenStream) -> TokenStream {
121
let tokens = input.clone();
122
123
let ast = parse_macro_input!(input as DeriveInput);
124
let visibility = ast.vis;
125
126
let mut attributes = QueryDataAttributes::default();
127
for attr in &ast.attrs {
128
if !attr.path().is_ident(QUERY_DATA_ATTRIBUTE_NAME) {
129
continue;
130
}
131
132
let result = attr.parse_nested_meta(|meta| {
133
if meta.path.is_ident(MUTABLE_ATTRIBUTE_NAME) {
134
attributes.is_mutable = true;
135
Ok(())
136
} else if meta.path.is_ident(DERIVE_ATTRIBUTE_NAME) {
137
meta.parse_nested_meta(|meta| {
138
attributes.derive_args.push(Meta::Path(meta.path));
139
Ok(())
140
})
141
} else if meta.path.is_ident(CONTIGUOUS_ATTRIBUTE_NAME) {
142
meta.parse_nested_meta(|meta| {
143
if meta.path.is_ident("all") {
144
attributes.is_contiguous_mutable = true;
145
attributes.is_contiguous_immutable = true;
146
Ok(())
147
} else if meta.path.is_ident("mutable") {
148
attributes.is_contiguous_mutable = true;
149
Ok(())
150
} else if meta.path.is_ident("immutable") {
151
attributes.is_contiguous_immutable = true;
152
Ok(())
153
} else {
154
Err(meta.error("invalid target, expected `all`, `mutable` or `immutable`"))
155
}
156
})
157
} else {
158
Err(meta.error(format_args!("invalid attribute, expected `{MUTABLE_ATTRIBUTE_NAME}`, `{DERIVE_ATTRIBUTE_NAME}` or `{CONTIGUOUS_ATTRIBUTE_NAME}`")))
159
}
160
});
161
162
if let Err(err) = result {
163
return err.to_compile_error().into();
164
}
165
}
166
167
let path = bevy_ecs_path();
168
169
let user_generics = ast.generics.clone();
170
let (user_impl_generics, user_ty_generics, user_where_clauses) = user_generics.split_for_impl();
171
let user_generics_with_world = {
172
let mut generics = ast.generics.clone();
173
generics.params.insert(0, parse_quote!('__w));
174
generics
175
};
176
let (user_impl_generics_with_world, user_ty_generics_with_world, user_where_clauses_with_world) =
177
user_generics_with_world.split_for_impl();
178
let user_generics_with_world_and_state = {
179
let mut generics = ast.generics;
180
generics.params.insert(0, parse_quote!('__w));
181
generics.params.insert(1, parse_quote!('__s));
182
generics
183
};
184
let (
185
user_impl_generics_with_world_and_state,
186
user_ty_generics_with_world_and_state,
187
user_where_clauses_with_world_and_state,
188
) = user_generics_with_world_and_state.split_for_impl();
189
190
let struct_name = ast.ident;
191
let read_only_struct_name = if attributes.is_mutable {
192
Ident::new(&format!("{struct_name}ReadOnly"), Span::call_site())
193
} else {
194
struct_name.clone()
195
};
196
197
let item_struct_name = Ident::new(&format!("{struct_name}Item"), Span::call_site());
198
let read_only_item_struct_name = if attributes.is_mutable {
199
Ident::new(&format!("{struct_name}ReadOnlyItem"), Span::call_site())
200
} else {
201
item_struct_name.clone()
202
};
203
let contiguous_item_struct_name = if attributes.is_contiguous_mutable {
204
Ident::new(&format!("{struct_name}ContiguousItem"), Span::call_site())
205
} else {
206
item_struct_name.clone()
207
};
208
let read_only_contiguous_item_struct_name = if attributes.is_contiguous_immutable {
209
Ident::new(
210
&format!("{struct_name}ReadOnlyContiguousItem"),
211
Span::call_site(),
212
)
213
} else {
214
item_struct_name.clone()
215
};
216
217
let fetch_struct_name = Ident::new(&format!("{struct_name}Fetch"), Span::call_site());
218
let fetch_struct_name = ensure_no_collision(fetch_struct_name, tokens.clone());
219
let read_only_fetch_struct_name = if attributes.is_mutable {
220
let new_ident = Ident::new(&format!("{struct_name}ReadOnlyFetch"), Span::call_site());
221
ensure_no_collision(new_ident, tokens.clone())
222
} else {
223
fetch_struct_name.clone()
224
};
225
226
let marker_name =
227
ensure_no_collision(format_ident!("_world_query_derive_marker"), tokens.clone());
228
229
// Generate a name for the state struct that doesn't conflict
230
// with the struct definition.
231
let state_struct_name = Ident::new(&format!("{struct_name}State"), Span::call_site());
232
let state_struct_name = ensure_no_collision(state_struct_name, tokens);
233
234
let fields = match get_struct_fields(&ast.data, "derive(QueryData)") {
235
Ok(fields) => fields,
236
Err(e) => return e.into_compile_error().into(),
237
};
238
239
let field_attrs = fields.iter().map(|f| f.attrs.clone()).collect();
240
let field_visibilities = fields.iter().map(|f| f.vis.clone()).collect();
241
let field_members = fields.members().collect();
242
let field_aliases = fields
243
.members()
244
.map(|m| format_ident!("field{}", m))
245
.collect();
246
let field_types: Vec<Type> = fields.iter().map(|f| f.ty.clone()).collect();
247
let read_only_field_types = field_types
248
.iter()
249
.map(|ty| parse_quote!(<#ty as #path::query::QueryData>::ReadOnly))
250
.collect();
251
252
let derive_args = &attributes.derive_args;
253
// `#[derive()]` is valid syntax
254
let derive_macro_call = quote! { #[derive(#derive_args)] };
255
256
let mutable_item_struct = item_struct(
257
&path,
258
fields,
259
&derive_macro_call,
260
&struct_name,
261
&visibility,
262
&item_struct_name,
263
&field_types,
264
&user_impl_generics_with_world_and_state,
265
&field_attrs,
266
&field_visibilities,
267
&field_members,
268
&user_ty_generics,
269
&user_ty_generics_with_world_and_state,
270
user_where_clauses_with_world_and_state,
271
);
272
let mutable_world_query_impl = world_query_impl(
273
&path,
274
&struct_name,
275
&visibility,
276
&fetch_struct_name,
277
&field_types,
278
&user_impl_generics,
279
&user_impl_generics_with_world,
280
&user_ty_generics,
281
&user_ty_generics_with_world,
282
&field_aliases,
283
&marker_name,
284
&state_struct_name,
285
user_where_clauses,
286
user_where_clauses_with_world,
287
);
288
289
let (mutable_contiguous_item_struct, mutable_contiguous_impl) =
290
if attributes.is_contiguous_mutable {
291
let contiguous_item_struct = contiguous_item_struct(
292
&path,
293
fields,
294
&derive_macro_call,
295
&struct_name,
296
&visibility,
297
&contiguous_item_struct_name,
298
&field_types,
299
&user_impl_generics_with_world_and_state,
300
&field_attrs,
301
&field_visibilities,
302
&field_members,
303
&user_ty_generics,
304
&user_ty_generics_with_world_and_state,
305
user_where_clauses_with_world_and_state,
306
);
307
308
let contiguous_impl = contiguous_query_data_impl(
309
&path,
310
&struct_name,
311
&contiguous_item_struct_name,
312
&field_types,
313
&user_impl_generics,
314
&user_ty_generics,
315
&user_ty_generics_with_world_and_state,
316
&field_members,
317
&field_aliases,
318
user_where_clauses,
319
);
320
321
(contiguous_item_struct, contiguous_impl)
322
} else {
323
(quote! {}, quote! {})
324
};
325
326
let (read_only_struct, read_only_impl) = if attributes.is_mutable {
327
// If the query is mutable, we need to generate a separate readonly version of some things
328
let readonly_item_struct = item_struct(
329
&path,
330
fields,
331
&derive_macro_call,
332
&read_only_struct_name,
333
&visibility,
334
&read_only_item_struct_name,
335
&read_only_field_types,
336
&user_impl_generics_with_world_and_state,
337
&field_attrs,
338
&field_visibilities,
339
&field_members,
340
&user_ty_generics,
341
&user_ty_generics_with_world_and_state,
342
user_where_clauses_with_world_and_state,
343
);
344
let readonly_world_query_impl = world_query_impl(
345
&path,
346
&read_only_struct_name,
347
&visibility,
348
&read_only_fetch_struct_name,
349
&read_only_field_types,
350
&user_impl_generics,
351
&user_impl_generics_with_world,
352
&user_ty_generics,
353
&user_ty_generics_with_world,
354
&field_aliases,
355
&marker_name,
356
&state_struct_name,
357
user_where_clauses,
358
user_where_clauses_with_world,
359
);
360
let read_only_structs = quote! {
361
#[doc = concat!(
362
"Automatically generated [`WorldQuery`](",
363
stringify!(#path),
364
"::query::WorldQuery) type for a read-only variant of [`",
365
stringify!(#struct_name),
366
"`]."
367
)]
368
#[automatically_derived]
369
#visibility struct #read_only_struct_name #user_impl_generics #user_where_clauses {
370
#(
371
#[doc = "Automatically generated read-only field for accessing `"]
372
#[doc = stringify!(#field_types)]
373
#[doc = "`."]
374
#field_visibilities #field_members: #read_only_field_types,
375
)*
376
}
377
378
#readonly_item_struct
379
};
380
(read_only_structs, readonly_world_query_impl)
381
} else {
382
(quote! {}, quote! {})
383
};
384
385
let (read_only_contiguous_item_struct, read_only_contiguous_impl) =
386
if attributes.is_mutable && attributes.is_contiguous_immutable {
387
let contiguous_item_struct = contiguous_item_struct(
388
&path,
389
fields,
390
&derive_macro_call,
391
&read_only_struct_name,
392
&visibility,
393
&read_only_contiguous_item_struct_name,
394
&read_only_field_types,
395
&user_impl_generics_with_world_and_state,
396
&field_attrs,
397
&field_visibilities,
398
&field_members,
399
&user_ty_generics,
400
&user_ty_generics_with_world_and_state,
401
user_where_clauses_with_world_and_state,
402
);
403
404
let contiguous_impl = contiguous_query_data_impl(
405
&path,
406
&read_only_struct_name,
407
&read_only_contiguous_item_struct_name,
408
&read_only_field_types,
409
&user_impl_generics,
410
&user_ty_generics,
411
&user_ty_generics_with_world_and_state,
412
&field_members,
413
&field_aliases,
414
user_where_clauses,
415
);
416
417
(contiguous_item_struct, contiguous_impl)
418
} else {
419
(quote! {}, quote! {})
420
};
421
422
let data_impl = {
423
let read_only_data_impl = if attributes.is_mutable {
424
quote! {
425
// SAFETY: we assert fields are readonly below
426
unsafe impl #user_impl_generics #path::query::QueryData
427
for #read_only_struct_name #user_ty_generics #user_where_clauses {
428
const IS_READ_ONLY: bool = true;
429
const IS_ARCHETYPAL: bool = true #(&& <#read_only_field_types as #path::query::QueryData>::IS_ARCHETYPAL)*;
430
type ReadOnly = #read_only_struct_name #user_ty_generics;
431
type Item<'__w, '__s> = #read_only_item_struct_name #user_ty_generics_with_world_and_state;
432
433
fn shrink<'__wlong: '__wshort, '__wshort, '__s>(
434
item: Self::Item<'__wlong, '__s>
435
) -> Self::Item<'__wshort, '__s> {
436
#read_only_item_struct_name {
437
#(
438
#field_members: <#read_only_field_types>::shrink(item.#field_members),
439
)*
440
}
441
}
442
443
fn provide_extra_access(
444
state: &mut Self::State,
445
access: &mut #path::query::Access,
446
available_access: &#path::query::Access,
447
) {
448
#(<#field_types>::provide_extra_access(&mut state.#field_aliases, access, available_access);)*
449
}
450
451
/// SAFETY: we call `fetch` for each member that implements `Fetch`.
452
#[inline(always)]
453
unsafe fn fetch<'__w, '__s>(
454
_state: &'__s Self::State,
455
_fetch: &mut <Self as #path::query::WorldQuery>::Fetch<'__w>,
456
_entity: #path::entity::Entity,
457
_table_row: #path::storage::TableRow,
458
) -> Option<Self::Item<'__w, '__s>> {
459
Some(Self::Item {
460
#(#field_members: <#read_only_field_types>::fetch(&_state.#field_aliases, &mut _fetch.#field_aliases, _entity, _table_row)?,)*
461
})
462
}
463
464
fn iter_access(
465
_state: &Self::State,
466
) -> impl ::core::iter::Iterator<Item = #path::query::EcsAccessType<'_>> {
467
::core::iter::empty() #(.chain(<#field_types>::iter_access(&_state.#field_aliases)))*
468
}
469
}
470
471
impl #user_impl_generics #path::query::ReleaseStateQueryData
472
for #read_only_struct_name #user_ty_generics #user_where_clauses
473
// Make these HRTBs with an unused lifetime parameter to allow trivial constraints
474
// See https://github.com/rust-lang/rust/issues/48214
475
where #(for<'__a> #field_types: #path::query::QueryData<ReadOnly: #path::query::ReleaseStateQueryData>,)* {
476
fn release_state<'__w>(_item: Self::Item<'__w, '_>) -> Self::Item<'__w, 'static> {
477
Self::Item {
478
#(#field_members: <#read_only_field_types>::release_state(_item.#field_members),)*
479
}
480
}
481
}
482
483
impl #user_impl_generics #path::query::ArchetypeQueryData
484
for #read_only_struct_name #user_ty_generics #user_where_clauses
485
// Make these HRTBs with an unused lifetime parameter to allow trivial constraints
486
// See https://github.com/rust-lang/rust/issues/48214
487
where #(for<'__a> #field_types: #path::query::ArchetypeQueryData,)* {}
488
}
489
} else {
490
quote! {}
491
};
492
493
let is_read_only = !attributes.is_mutable;
494
495
quote! {
496
// SAFETY: we assert fields are readonly below
497
unsafe impl #user_impl_generics #path::query::QueryData
498
for #struct_name #user_ty_generics #user_where_clauses {
499
const IS_READ_ONLY: bool = #is_read_only;
500
const IS_ARCHETYPAL: bool = true #(&& <#field_types as #path::query::QueryData>::IS_ARCHETYPAL)*;
501
type ReadOnly = #read_only_struct_name #user_ty_generics;
502
type Item<'__w, '__s> = #item_struct_name #user_ty_generics_with_world_and_state;
503
504
fn shrink<'__wlong: '__wshort, '__wshort, '__s>(
505
item: Self::Item<'__wlong, '__s>
506
) -> Self::Item<'__wshort, '__s> {
507
#item_struct_name {
508
#(
509
#field_members: <#field_types>::shrink(item.#field_members),
510
)*
511
}
512
}
513
514
fn provide_extra_access(
515
state: &mut Self::State,
516
access: &mut #path::query::Access,
517
available_access: &#path::query::Access,
518
) {
519
#(<#field_types>::provide_extra_access(&mut state.#field_aliases, access, available_access);)*
520
}
521
522
/// SAFETY: we call `fetch` for each member that implements `Fetch`.
523
#[inline(always)]
524
unsafe fn fetch<'__w, '__s>(
525
_state: &'__s Self::State,
526
_fetch: &mut <Self as #path::query::WorldQuery>::Fetch<'__w>,
527
_entity: #path::entity::Entity,
528
_table_row: #path::storage::TableRow,
529
) -> Option<Self::Item<'__w, '__s>> {
530
Some(Self::Item {
531
#(#field_members: <#field_types>::fetch(&_state.#field_aliases, &mut _fetch.#field_aliases, _entity, _table_row)?,)*
532
})
533
}
534
535
fn iter_access(
536
_state: &Self::State,
537
) -> impl ::core::iter::Iterator<Item = #path::query::EcsAccessType<'_>> {
538
::core::iter::empty() #(.chain(<#field_types>::iter_access(&_state.#field_aliases)))*
539
}
540
}
541
542
impl #user_impl_generics #path::query::ReleaseStateQueryData
543
for #struct_name #user_ty_generics #user_where_clauses
544
// Make these HRTBs with an unused lifetime parameter to allow trivial constraints
545
// See https://github.com/rust-lang/rust/issues/48214
546
where #(for<'__a> #field_types: #path::query::ReleaseStateQueryData,)* {
547
fn release_state<'__w>(_item: Self::Item<'__w, '_>) -> Self::Item<'__w, 'static> {
548
Self::Item {
549
#(#field_members: <#field_types>::release_state(_item.#field_members),)*
550
}
551
}
552
}
553
554
impl #user_impl_generics #path::query::ArchetypeQueryData
555
for #struct_name #user_ty_generics #user_where_clauses
556
// Make these HRTBs with an unused lifetime parameter to allow trivial constraints
557
// See https://github.com/rust-lang/rust/issues/48214
558
where #(for<'__a> #field_types: #path::query::ArchetypeQueryData,)* {}
559
560
#read_only_data_impl
561
}
562
};
563
564
let read_only_data_impl = quote! {
565
// SAFETY: we assert fields are readonly below
566
unsafe impl #user_impl_generics #path::query::ReadOnlyQueryData
567
for #read_only_struct_name #user_ty_generics #user_where_clauses {}
568
};
569
570
let read_only_asserts = if attributes.is_mutable {
571
quote! {
572
// Double-check that the data fetched by `<_ as WorldQuery>::ReadOnly` is read-only.
573
// This is technically unnecessary as `<_ as WorldQuery>::ReadOnly: ReadOnlyQueryData`
574
// but to protect against future mistakes we assert the assoc type implements `ReadOnlyQueryData` anyway
575
#( assert_readonly::<#read_only_field_types>(); )*
576
}
577
} else {
578
quote! {
579
// Statically checks that the safety guarantee of `ReadOnlyQueryData` for `$fetch_struct_name` actually holds true.
580
// We need this to make sure that we don't compile `ReadOnlyQueryData` if our struct contains nested `QueryData`
581
// members that don't implement it. I.e.:
582
// ```
583
// #[derive(QueryData)]
584
// pub struct Foo { a: &'static mut MyComponent }
585
// ```
586
#( assert_readonly::<#field_types>(); )*
587
}
588
};
589
590
let data_asserts = quote! {
591
#( assert_data::<#field_types>(); )*
592
};
593
594
TokenStream::from(quote! {
595
#mutable_item_struct
596
597
#read_only_struct
598
599
#mutable_contiguous_item_struct
600
601
#read_only_contiguous_item_struct
602
603
const _: () = {
604
#[doc(hidden)]
605
#[doc = concat!(
606
"Automatically generated internal [`WorldQuery`](",
607
stringify!(#path),
608
"::query::WorldQuery) state type for [`",
609
stringify!(#struct_name),
610
"`], used for caching."
611
)]
612
#[automatically_derived]
613
#visibility struct #state_struct_name #user_impl_generics #user_where_clauses {
614
#(#field_aliases: <#field_types as #path::query::WorldQuery>::State,)*
615
}
616
617
#mutable_world_query_impl
618
619
#read_only_impl
620
621
#data_impl
622
623
#read_only_data_impl
624
625
#mutable_contiguous_impl
626
627
#read_only_contiguous_impl
628
};
629
630
#[allow(dead_code)]
631
const _: () = {
632
fn assert_readonly<T>()
633
where
634
T: #path::query::ReadOnlyQueryData,
635
{
636
}
637
638
fn assert_data<T>()
639
where
640
T: #path::query::QueryData,
641
{
642
}
643
644
// We generate a readonly assertion for every struct member.
645
fn assert_all #user_impl_generics_with_world () #user_where_clauses_with_world {
646
#read_only_asserts
647
#data_asserts
648
}
649
};
650
651
// The original struct will most likely be left unused. As we don't want our users having
652
// to specify `#[allow(dead_code)]` for their custom queries, we are using this cursed
653
// workaround.
654
#[allow(dead_code)]
655
const _: () = {
656
fn dead_code_workaround #user_impl_generics (
657
q: #struct_name #user_ty_generics,
658
q2: #read_only_struct_name #user_ty_generics
659
) #user_where_clauses {
660
#(q.#field_members;)*
661
#(q2.#field_members;)*
662
}
663
};
664
})
665
}
666
667