Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bevyengine
GitHub Repository: bevyengine/bevy
Path: blob/main/crates/bevy_reflect/derive/src/container_attributes.rs
9427 views
1
//! Contains code related to container attributes for reflected types.
2
//!
3
//! A container attribute is an attribute which applies to an entire struct or enum
4
//! as opposed to a particular field or variant. An example of such an attribute is
5
//! the derive helper attribute for `Reflect`, which looks like:
6
//! `#[reflect(PartialEq, Default, ...)]`.
7
8
use crate::{custom_attributes::CustomAttributes, derive_data::ReflectTraitToImpl};
9
use bevy_macro_utils::{
10
fq_std::{FQAny, FQClone, FQOption, FQResult},
11
terminated_parser,
12
};
13
use proc_macro2::{Ident, Span};
14
use quote::quote_spanned;
15
use syn::{
16
ext::IdentExt, parenthesized, parse::ParseStream, spanned::Spanned, token, Expr, LitBool,
17
MetaList, MetaNameValue, Path, Token, WhereClause,
18
};
19
20
mod kw {
21
syn::custom_keyword!(from_reflect);
22
syn::custom_keyword!(type_path);
23
syn::custom_keyword!(Debug);
24
syn::custom_keyword!(PartialEq);
25
syn::custom_keyword!(PartialOrd);
26
syn::custom_keyword!(Hash);
27
syn::custom_keyword!(Clone);
28
syn::custom_keyword!(no_field_bounds);
29
syn::custom_keyword!(no_auto_register);
30
syn::custom_keyword!(opaque);
31
}
32
33
// The "special" trait idents that are used internally for reflection.
34
// Received via attributes like `#[reflect(PartialEq, Hash, ...)]`
35
const DEBUG_ATTR: &str = "Debug";
36
const PARTIAL_EQ_ATTR: &str = "PartialEq";
37
const PARTIAL_ORD_ATTR: &str = "PartialOrd";
38
const HASH_ATTR: &str = "Hash";
39
40
// The traits listed below are not considered "special" (i.e. they use the `ReflectMyTrait` syntax)
41
// but useful to know exist nonetheless
42
pub(crate) const REFLECT_DEFAULT: &str = "ReflectDefault";
43
44
// Attributes for `FromReflect` implementation
45
const FROM_REFLECT_ATTR: &str = "from_reflect";
46
47
// Attributes for `TypePath` implementation
48
const TYPE_PATH_ATTR: &str = "type_path";
49
50
// The error message to show when a trait/type is specified multiple times
51
const CONFLICTING_TYPE_DATA_MESSAGE: &str = "conflicting type data registration";
52
53
/// A marker for trait implementations registered via the `Reflect` derive macro.
54
#[derive(Clone, Default)]
55
pub(crate) enum TraitImpl {
56
/// The trait is not registered as implemented.
57
#[default]
58
NotImplemented,
59
60
/// The trait is registered as implemented.
61
Implemented(Span),
62
63
/// The trait is registered with a custom function rather than an actual implementation.
64
Custom(Path, Span),
65
}
66
67
impl TraitImpl {
68
/// Merges this [`TraitImpl`] with another.
69
///
70
/// Update `self` with whichever value is not [`TraitImpl::NotImplemented`].
71
/// If `other` is [`TraitImpl::NotImplemented`], then `self` is not modified.
72
/// An error is returned if neither value is [`TraitImpl::NotImplemented`].
73
pub fn merge(&mut self, other: TraitImpl) -> Result<(), syn::Error> {
74
match (&self, other) {
75
(TraitImpl::NotImplemented, value) => {
76
*self = value;
77
Ok(())
78
}
79
(_, TraitImpl::NotImplemented) => Ok(()),
80
(_, TraitImpl::Implemented(span) | TraitImpl::Custom(_, span)) => {
81
Err(syn::Error::new(span, CONFLICTING_TYPE_DATA_MESSAGE))
82
}
83
}
84
}
85
}
86
87
/// A collection of attributes used for deriving `FromReflect`.
88
#[derive(Clone, Default)]
89
pub(crate) struct FromReflectAttrs {
90
auto_derive: Option<LitBool>,
91
}
92
93
impl FromReflectAttrs {
94
/// Returns true if `FromReflect` should be automatically derived as part of the `Reflect` derive.
95
pub fn should_auto_derive(&self) -> bool {
96
self.auto_derive.as_ref().is_none_or(LitBool::value)
97
}
98
}
99
100
/// A collection of attributes used for deriving `TypePath` via the `Reflect` derive.
101
///
102
/// Note that this differs from the attributes used by the `TypePath` derive itself,
103
/// which look like `[type_path = "my_crate::foo"]`.
104
/// The attributes used by reflection take the form `#[reflect(type_path = false)]`.
105
///
106
/// These attributes should only be used for `TypePath` configuration specific to
107
/// deriving `Reflect`.
108
#[derive(Clone, Default)]
109
pub(crate) struct TypePathAttrs {
110
auto_derive: Option<LitBool>,
111
}
112
113
impl TypePathAttrs {
114
/// Returns true if `TypePath` should be automatically derived as part of the `Reflect` derive.
115
pub fn should_auto_derive(&self) -> bool {
116
self.auto_derive.as_ref().is_none_or(LitBool::value)
117
}
118
}
119
120
/// A collection of traits that have been registered for a reflected type.
121
///
122
/// This keeps track of a few traits that are utilized internally for reflection
123
/// (we'll call these traits _special traits_ within this context), but it
124
/// will also keep track of all registered traits. Traits are registered as part of the
125
/// `Reflect` derive macro using the helper attribute: `#[reflect(...)]`.
126
///
127
/// The list of special traits are as follows:
128
/// * `Debug`
129
/// * `Hash`
130
/// * `PartialEq`
131
///
132
/// When registering a trait, there are a few things to keep in mind:
133
/// * Traits must have a valid `Reflect{}` struct in scope. For example, `Default`
134
/// needs `bevy_reflect::prelude::ReflectDefault` in scope.
135
/// * Traits must be single path identifiers. This means you _must_ use `Default`
136
/// instead of `std::default::Default` (otherwise it will try to register `Reflectstd`!)
137
/// * A custom function may be supplied in place of an actual implementation
138
/// for the special traits (but still follows the same single-path identifier
139
/// rules as normal).
140
///
141
/// # Example
142
///
143
/// Registering the `Default` implementation:
144
///
145
/// ```ignore (bevy_reflect is not accessible from this crate)
146
/// // Import ReflectDefault so it's accessible by the derive macro
147
/// use bevy_reflect::prelude::ReflectDefault;
148
///
149
/// #[derive(Reflect, Default)]
150
/// #[reflect(Default)]
151
/// struct Foo;
152
/// ```
153
///
154
/// Registering the `Hash` implementation:
155
///
156
/// ```ignore (bevy_reflect is not accessible from this crate)
157
/// // `Hash` is a "special trait" and does not need (nor have) a ReflectHash struct
158
///
159
/// #[derive(Reflect, Hash)]
160
/// #[reflect(Hash)]
161
/// struct Foo;
162
/// ```
163
///
164
/// Registering the `Hash` implementation using a custom function:
165
///
166
/// ```ignore (bevy_reflect is not accessible from this crate)
167
/// // This function acts as our `Hash` implementation and
168
/// // corresponds to the `Reflect::reflect_hash` method.
169
/// fn get_hash(foo: &Foo) -> Option<u64> {
170
/// Some(123)
171
/// }
172
///
173
/// #[derive(Reflect)]
174
/// // Register the custom `Hash` function
175
/// #[reflect(Hash(get_hash))]
176
/// struct Foo;
177
/// ```
178
///
179
/// > __Note:__ Registering a custom function only works for special traits.
180
#[derive(Default, Clone)]
181
pub(crate) struct ContainerAttributes {
182
clone: TraitImpl,
183
debug: TraitImpl,
184
hash: TraitImpl,
185
partial_ord: TraitImpl,
186
partial_eq: TraitImpl,
187
from_reflect_attrs: FromReflectAttrs,
188
type_path_attrs: TypePathAttrs,
189
custom_where: Option<WhereClause>,
190
no_field_bounds: bool,
191
no_auto_register: bool,
192
custom_attributes: CustomAttributes,
193
is_opaque: bool,
194
idents: Vec<Ident>,
195
}
196
197
impl ContainerAttributes {
198
/// Parse a comma-separated list of container attributes.
199
///
200
/// # Example
201
/// - `Hash, Debug(custom_debug), MyTrait`
202
pub fn parse_terminated(
203
&mut self,
204
input: ParseStream,
205
trait_: ReflectTraitToImpl,
206
) -> syn::Result<()> {
207
terminated_parser(Token![,], |stream| {
208
self.parse_container_attribute(stream, trait_)
209
})(input)?;
210
211
Ok(())
212
}
213
214
/// Parse the contents of a `#[reflect(...)]` attribute into a [`ContainerAttributes`] instance.
215
///
216
/// # Example
217
/// - `#[reflect(Hash, Debug(custom_debug), MyTrait)]`
218
/// - `#[reflect(no_field_bounds)]`
219
pub fn parse_meta_list(
220
&mut self,
221
meta: &MetaList,
222
trait_: ReflectTraitToImpl,
223
) -> syn::Result<()> {
224
meta.parse_args_with(|stream: ParseStream| self.parse_terminated(stream, trait_))
225
}
226
227
/// Parse a single container attribute.
228
fn parse_container_attribute(
229
&mut self,
230
input: ParseStream,
231
trait_: ReflectTraitToImpl,
232
) -> syn::Result<()> {
233
let lookahead = input.lookahead1();
234
if lookahead.peek(Token![@]) {
235
self.custom_attributes.parse_custom_attribute(input)
236
} else if lookahead.peek(Token![where]) {
237
self.parse_custom_where(input)
238
} else if lookahead.peek(kw::from_reflect) {
239
self.parse_from_reflect(input, trait_)
240
} else if lookahead.peek(kw::type_path) {
241
self.parse_type_path(input, trait_)
242
} else if lookahead.peek(kw::opaque) {
243
self.parse_opaque(input)
244
} else if lookahead.peek(kw::no_field_bounds) {
245
self.parse_no_field_bounds(input)
246
} else if lookahead.peek(kw::Clone) {
247
self.parse_clone(input)
248
} else if lookahead.peek(kw::no_auto_register) {
249
self.parse_no_auto_register(input)
250
} else if lookahead.peek(kw::Debug) {
251
self.parse_debug(input)
252
} else if lookahead.peek(kw::Hash) {
253
self.parse_hash(input)
254
} else if lookahead.peek(kw::PartialOrd) {
255
self.parse_partial_ord(input)
256
} else if lookahead.peek(kw::PartialEq) {
257
self.parse_partial_eq(input)
258
} else if lookahead.peek(Ident::peek_any) {
259
self.parse_ident(input)
260
} else {
261
Err(lookahead.error())
262
}
263
}
264
265
/// Parse an ident (for registration).
266
///
267
/// Examples:
268
/// - `#[reflect(MyTrait)]` (registers `ReflectMyTrait`)
269
fn parse_ident(&mut self, input: ParseStream) -> syn::Result<()> {
270
let ident = input.parse::<Ident>()?;
271
272
if input.peek(token::Paren) {
273
return Err(syn::Error::new(ident.span(), format!(
274
"only [{DEBUG_ATTR:?}, {PARTIAL_EQ_ATTR:?}, {PARTIAL_ORD_ATTR:?}, {HASH_ATTR:?}] may specify custom functions",
275
)));
276
}
277
278
let ident_name = ident.to_string();
279
280
// Create the reflect ident
281
let mut reflect_ident = crate::ident::get_reflect_ident(&ident_name);
282
// We set the span to the old ident so any compile errors point to that ident instead
283
reflect_ident.set_span(ident.span());
284
285
add_unique_ident(&mut self.idents, reflect_ident)?;
286
287
Ok(())
288
}
289
290
/// Parse `clone` attribute.
291
///
292
/// Examples:
293
/// - `#[reflect(Clone)]`
294
/// - `#[reflect(Clone(custom_clone_fn))]`
295
fn parse_clone(&mut self, input: ParseStream) -> syn::Result<()> {
296
let ident = input.parse::<kw::Clone>()?;
297
298
if input.peek(token::Paren) {
299
let content;
300
parenthesized!(content in input);
301
let path = content.parse::<Path>()?;
302
self.clone.merge(TraitImpl::Custom(path, ident.span))?;
303
} else {
304
self.clone = TraitImpl::Implemented(ident.span);
305
}
306
307
Ok(())
308
}
309
310
/// Parse special `Debug` registration.
311
///
312
/// Examples:
313
/// - `#[reflect(Debug)]`
314
/// - `#[reflect(Debug(custom_debug_fn))]`
315
fn parse_debug(&mut self, input: ParseStream) -> syn::Result<()> {
316
let ident = input.parse::<kw::Debug>()?;
317
318
if input.peek(token::Paren) {
319
let content;
320
parenthesized!(content in input);
321
let path = content.parse::<Path>()?;
322
self.debug.merge(TraitImpl::Custom(path, ident.span))?;
323
} else {
324
self.debug = TraitImpl::Implemented(ident.span);
325
}
326
327
Ok(())
328
}
329
330
/// Parse special `PartialEq` registration.
331
///
332
/// Examples:
333
/// - `#[reflect(PartialEq)]`
334
/// - `#[reflect(PartialEq(custom_partial_eq_fn))]`
335
fn parse_partial_eq(&mut self, input: ParseStream) -> syn::Result<()> {
336
let ident = input.parse::<kw::PartialEq>()?;
337
338
if input.peek(token::Paren) {
339
let content;
340
parenthesized!(content in input);
341
let path = content.parse::<Path>()?;
342
self.partial_eq.merge(TraitImpl::Custom(path, ident.span))?;
343
} else {
344
self.partial_eq = TraitImpl::Implemented(ident.span);
345
}
346
347
Ok(())
348
}
349
350
/// Parse special `PartialOrd` registration.
351
///
352
/// Examples:
353
/// - `#[reflect(PartialOrd)]`
354
/// - `#[reflect(PartialOrd(custom_partial_cmp_fn))]`
355
fn parse_partial_ord(&mut self, input: ParseStream) -> syn::Result<()> {
356
let ident = input.parse::<kw::PartialOrd>()?;
357
358
if input.peek(token::Paren) {
359
let content;
360
parenthesized!(content in input);
361
let path = content.parse::<Path>()?;
362
self.partial_ord
363
.merge(TraitImpl::Custom(path, ident.span))?;
364
} else {
365
self.partial_ord = TraitImpl::Implemented(ident.span);
366
}
367
368
Ok(())
369
}
370
371
/// Parse special `Hash` registration.
372
///
373
/// Examples:
374
/// - `#[reflect(Hash)]`
375
/// - `#[reflect(Hash(custom_hash_fn))]`
376
fn parse_hash(&mut self, input: ParseStream) -> syn::Result<()> {
377
let ident = input.parse::<kw::Hash>()?;
378
379
if input.peek(token::Paren) {
380
let content;
381
parenthesized!(content in input);
382
let path = content.parse::<Path>()?;
383
self.hash.merge(TraitImpl::Custom(path, ident.span))?;
384
} else {
385
self.hash = TraitImpl::Implemented(ident.span);
386
}
387
388
Ok(())
389
}
390
391
/// Parse `opaque` attribute.
392
///
393
/// Examples:
394
/// - `#[reflect(opaque)]`
395
fn parse_opaque(&mut self, input: ParseStream) -> syn::Result<()> {
396
input.parse::<kw::opaque>()?;
397
self.is_opaque = true;
398
Ok(())
399
}
400
401
/// Parse `no_field_bounds` attribute.
402
///
403
/// Examples:
404
/// - `#[reflect(no_field_bounds)]`
405
fn parse_no_field_bounds(&mut self, input: ParseStream) -> syn::Result<()> {
406
input.parse::<kw::no_field_bounds>()?;
407
self.no_field_bounds = true;
408
Ok(())
409
}
410
411
/// Parse `no_auto_register` attribute.
412
///
413
/// Examples:
414
/// - `#[reflect(no_auto_register)]`
415
fn parse_no_auto_register(&mut self, input: ParseStream) -> syn::Result<()> {
416
input.parse::<kw::no_auto_register>()?;
417
self.no_auto_register = true;
418
Ok(())
419
}
420
421
/// Parse `where` attribute.
422
///
423
/// Examples:
424
/// - `#[reflect(where T: Debug)]`
425
fn parse_custom_where(&mut self, input: ParseStream) -> syn::Result<()> {
426
self.custom_where = Some(input.parse()?);
427
Ok(())
428
}
429
430
/// Parse `from_reflect` attribute.
431
///
432
/// Examples:
433
/// - `#[reflect(from_reflect = false)]`
434
fn parse_from_reflect(
435
&mut self,
436
input: ParseStream,
437
trait_: ReflectTraitToImpl,
438
) -> syn::Result<()> {
439
let pair = input.parse::<MetaNameValue>()?;
440
let extracted_bool = extract_bool(&pair.value, |lit| {
441
// Override `lit` if this is a `FromReflect` derive.
442
// This typically means a user is opting out of the default implementation
443
// from the `Reflect` derive and using the `FromReflect` derive directly instead.
444
if trait_ == ReflectTraitToImpl::FromReflect {
445
LitBool::new(true, Span::call_site())
446
} else {
447
lit.clone()
448
}
449
})?;
450
451
if let Some(existing) = &self.from_reflect_attrs.auto_derive {
452
if existing.value() != extracted_bool.value() {
453
return Err(syn::Error::new(
454
extracted_bool.span(),
455
format!("`{FROM_REFLECT_ATTR}` already set to {}", existing.value()),
456
));
457
}
458
} else {
459
self.from_reflect_attrs.auto_derive = Some(extracted_bool);
460
}
461
462
Ok(())
463
}
464
465
/// Parse `type_path` attribute.
466
///
467
/// Examples:
468
/// - `#[reflect(type_path = false)]`
469
fn parse_type_path(
470
&mut self,
471
input: ParseStream,
472
trait_: ReflectTraitToImpl,
473
) -> syn::Result<()> {
474
let pair = input.parse::<MetaNameValue>()?;
475
let extracted_bool = extract_bool(&pair.value, |lit| {
476
// Override `lit` if this is a `FromReflect` derive.
477
// This typically means a user is opting out of the default implementation
478
// from the `Reflect` derive and using the `FromReflect` derive directly instead.
479
if trait_ == ReflectTraitToImpl::TypePath {
480
LitBool::new(true, Span::call_site())
481
} else {
482
lit.clone()
483
}
484
})?;
485
486
if let Some(existing) = &self.type_path_attrs.auto_derive {
487
if existing.value() != extracted_bool.value() {
488
return Err(syn::Error::new(
489
extracted_bool.span(),
490
format!("`{TYPE_PATH_ATTR}` already set to {}", existing.value()),
491
));
492
}
493
} else {
494
self.type_path_attrs.auto_derive = Some(extracted_bool);
495
}
496
497
Ok(())
498
}
499
500
/// Returns true if the given reflected trait name (i.e. `ReflectDefault` for `Default`)
501
/// is registered for this type.
502
pub fn contains(&self, name: &str) -> bool {
503
self.idents.iter().any(|ident| ident == name)
504
}
505
506
/// The list of reflected traits by their reflected ident (i.e. `ReflectDefault` for `Default`).
507
pub fn idents(&self) -> &[Ident] {
508
&self.idents
509
}
510
511
/// The `FromReflect` configuration found within `#[reflect(...)]` attributes on this type.
512
#[expect(
513
clippy::wrong_self_convention,
514
reason = "Method returns `FromReflectAttrs`, does not actually convert data."
515
)]
516
pub fn from_reflect_attrs(&self) -> &FromReflectAttrs {
517
&self.from_reflect_attrs
518
}
519
520
/// The `TypePath` configuration found within `#[reflect(...)]` attributes on this type.
521
pub fn type_path_attrs(&self) -> &TypePathAttrs {
522
&self.type_path_attrs
523
}
524
525
/// Returns the implementation of `PartialReflect::reflect_hash` as a `TokenStream`.
526
///
527
/// If `Hash` was not registered, returns `None`.
528
pub fn get_hash_impl(&self, bevy_reflect_path: &Path) -> Option<proc_macro2::TokenStream> {
529
match &self.hash {
530
&TraitImpl::Implemented(span) => Some(quote_spanned! {span=>
531
fn reflect_hash(&self) -> #FQOption<u64> {
532
use ::core::hash::{Hash, Hasher};
533
let mut hasher = #bevy_reflect_path::utility::reflect_hasher();
534
Hash::hash(&#FQAny::type_id(self), &mut hasher);
535
Hash::hash(self, &mut hasher);
536
#FQOption::Some(Hasher::finish(&hasher))
537
}
538
}),
539
&TraitImpl::Custom(ref impl_fn, span) => Some(quote_spanned! {span=>
540
fn reflect_hash(&self) -> #FQOption<u64> {
541
#FQOption::Some(#impl_fn(self))
542
}
543
}),
544
TraitImpl::NotImplemented => None,
545
}
546
}
547
548
/// Returns the implementation of `PartialReflect::reflect_partial_eq` as a `TokenStream`.
549
///
550
/// If `PartialEq` was not registered, returns `None`.
551
pub fn get_partial_eq_impl(
552
&self,
553
bevy_reflect_path: &Path,
554
) -> Option<proc_macro2::TokenStream> {
555
match &self.partial_eq {
556
&TraitImpl::Implemented(span) => Some(quote_spanned! {span=>
557
fn reflect_partial_eq(&self, value: &dyn #bevy_reflect_path::PartialReflect) -> #FQOption<bool> {
558
let value = <dyn #bevy_reflect_path::PartialReflect>::try_downcast_ref::<Self>(value);
559
if let #FQOption::Some(value) = value {
560
#FQOption::Some(::core::cmp::PartialEq::eq(self, value))
561
} else {
562
#FQOption::Some(false)
563
}
564
}
565
}),
566
&TraitImpl::Custom(ref impl_fn, span) => Some(quote_spanned! {span=>
567
fn reflect_partial_eq(&self, value: &dyn #bevy_reflect_path::PartialReflect) -> #FQOption<bool> {
568
#FQOption::Some(#impl_fn(self, value))
569
}
570
}),
571
TraitImpl::NotImplemented => None,
572
}
573
}
574
575
/// Returns the implementation of `PartialReflect::reflect_partial_cmp` as a `TokenStream`.
576
///
577
/// If `PartialOrd` was not registered, returns `None`.
578
pub fn get_partial_ord_impl(
579
&self,
580
bevy_reflect_path: &Path,
581
) -> Option<proc_macro2::TokenStream> {
582
match &self.partial_ord {
583
&TraitImpl::Implemented(span) => Some(quote_spanned! {span=>
584
fn reflect_partial_cmp(&self, value: &dyn #bevy_reflect_path::PartialReflect) -> #FQOption<::core::cmp::Ordering> {
585
let value = <dyn #bevy_reflect_path::PartialReflect>::try_downcast_ref::<Self>(value);
586
if let #FQOption::Some(value) = value {
587
::core::cmp::PartialOrd::partial_cmp(self, value)
588
} else {
589
#FQOption::None
590
}
591
}
592
}),
593
&TraitImpl::Custom(ref impl_fn, span) => Some(quote_spanned! {span=>
594
fn reflect_partial_cmp(&self, value: &dyn #bevy_reflect_path::PartialReflect) -> #FQOption<::core::cmp::Ordering> {
595
#impl_fn(self, value)
596
}
597
}),
598
TraitImpl::NotImplemented => None,
599
}
600
}
601
602
/// Returns the implementation of `PartialReflect::debug` as a `TokenStream`.
603
///
604
/// If `Debug` was not registered, returns `None`.
605
pub fn get_debug_impl(&self) -> Option<proc_macro2::TokenStream> {
606
match &self.debug {
607
&TraitImpl::Implemented(span) => Some(quote_spanned! {span=>
608
fn debug(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
609
::core::fmt::Debug::fmt(self, f)
610
}
611
}),
612
&TraitImpl::Custom(ref impl_fn, span) => Some(quote_spanned! {span=>
613
fn debug(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
614
#impl_fn(self, f)
615
}
616
}),
617
TraitImpl::NotImplemented => None,
618
}
619
}
620
621
pub fn get_clone_impl(&self, bevy_reflect_path: &Path) -> Option<proc_macro2::TokenStream> {
622
match &self.clone {
623
&TraitImpl::Implemented(span) => Some(quote_spanned! {span=>
624
#[inline]
625
fn reflect_clone(&self) -> #FQResult<#bevy_reflect_path::__macro_exports::alloc_utils::Box<dyn #bevy_reflect_path::Reflect>, #bevy_reflect_path::ReflectCloneError> {
626
#FQResult::Ok(#bevy_reflect_path::__macro_exports::alloc_utils::Box::new(#FQClone::clone(self)))
627
}
628
}),
629
&TraitImpl::Custom(ref impl_fn, span) => Some(quote_spanned! {span=>
630
#[inline]
631
fn reflect_clone(&self) -> #FQResult<#bevy_reflect_path::__macro_exports::alloc_utils::Box<dyn #bevy_reflect_path::Reflect>, #bevy_reflect_path::ReflectCloneError> {
632
#FQResult::Ok(#bevy_reflect_path::__macro_exports::alloc_utils::Box::new(#impl_fn(self)))
633
}
634
}),
635
TraitImpl::NotImplemented => None,
636
}
637
}
638
639
pub fn custom_attributes(&self) -> &CustomAttributes {
640
&self.custom_attributes
641
}
642
643
/// The custom where configuration found within `#[reflect(...)]` attributes on this type.
644
pub fn custom_where(&self) -> Option<&WhereClause> {
645
self.custom_where.as_ref()
646
}
647
648
/// Returns true if the `no_field_bounds` attribute was found on this type.
649
pub fn no_field_bounds(&self) -> bool {
650
self.no_field_bounds
651
}
652
653
/// Returns true if the `no_auto_register` attribute was found on this type.
654
#[cfg(feature = "auto_register")]
655
pub fn no_auto_register(&self) -> bool {
656
self.no_auto_register
657
}
658
659
/// Returns true if the `opaque` attribute was found on this type.
660
pub fn is_opaque(&self) -> bool {
661
self.is_opaque
662
}
663
}
664
665
/// Adds an identifier to a vector of identifiers if it is not already present.
666
///
667
/// Returns an error if the identifier already exists in the list.
668
fn add_unique_ident(idents: &mut Vec<Ident>, ident: Ident) -> Result<(), syn::Error> {
669
let ident_name = ident.to_string();
670
if idents.iter().any(|i| i == ident_name.as_str()) {
671
return Err(syn::Error::new(ident.span(), CONFLICTING_TYPE_DATA_MESSAGE));
672
}
673
674
idents.push(ident);
675
Ok(())
676
}
677
678
/// Extract a boolean value from an expression.
679
///
680
/// The mapper exists so that the caller can conditionally choose to use the given
681
/// value or supply their own.
682
fn extract_bool(
683
value: &Expr,
684
mut mapper: impl FnMut(&LitBool) -> LitBool,
685
) -> Result<LitBool, syn::Error> {
686
match value {
687
Expr::Lit(syn::ExprLit {
688
lit: syn::Lit::Bool(lit),
689
..
690
}) => Ok(mapper(lit)),
691
_ => Err(syn::Error::new(value.span(), "Expected a boolean value")),
692
}
693
}
694
695