Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bevyengine
GitHub Repository: bevyengine/bevy
Path: blob/main/crates/bevy_reflect/derive/src/derive_data.rs
9421 views
1
use core::fmt;
2
use indexmap::IndexSet;
3
use proc_macro2::Span;
4
5
use crate::{
6
container_attributes::{ContainerAttributes, FromReflectAttrs, TypePathAttrs},
7
field_attributes::FieldAttributes,
8
remote::RemoteType,
9
serialization::SerializationDataDef,
10
string_expr::StringExpr,
11
type_path::parse_path_no_leading_colon,
12
where_clause_options::WhereClauseOptions,
13
REFLECT_ATTRIBUTE_NAME, TYPE_NAME_ATTRIBUTE_NAME, TYPE_PATH_ATTRIBUTE_NAME,
14
};
15
use bevy_macro_utils::ResultSifter;
16
use quote::{format_ident, quote, ToTokens};
17
use syn::{token::Comma, MacroDelimiter};
18
19
use crate::enum_utility::{EnumVariantOutputData, ReflectCloneVariantBuilder, VariantBuilder};
20
use crate::field_attributes::CloneBehavior;
21
use crate::generics::generate_generics;
22
use bevy_macro_utils::fq_std::{FQClone, FQOption, FQResult};
23
use syn::{
24
parse_str, punctuated::Punctuated, spanned::Spanned, Data, DeriveInput, Field, Fields,
25
GenericParam, Generics, Ident, LitStr, Member, Meta, Path, PathSegment, Type, TypeParam,
26
Variant,
27
};
28
29
pub(crate) enum ReflectDerive<'a> {
30
Struct(ReflectStruct<'a>),
31
TupleStruct(ReflectStruct<'a>),
32
UnitStruct(ReflectStruct<'a>),
33
Enum(ReflectEnum<'a>),
34
Opaque(ReflectMeta<'a>),
35
}
36
37
/// Metadata present on all reflected types, including name, generics, and attributes.
38
///
39
/// # Example
40
///
41
/// ```ignore (bevy_reflect is not accessible from this crate)
42
/// #[derive(Reflect)]
43
/// // traits
44
/// // |----------------------------------------|
45
/// #[reflect(PartialEq, Serialize, Deserialize, Default)]
46
/// // type_path generics
47
/// // |-------------------||----------|
48
/// struct ThingThatImReflecting<T1, T2, T3> {/* ... */}
49
/// ```
50
pub(crate) struct ReflectMeta<'a> {
51
/// The registered traits for this type.
52
attrs: ContainerAttributes,
53
/// The path to this type.
54
type_path: ReflectTypePath<'a>,
55
/// The optional remote type to use instead of the actual type.
56
remote_ty: Option<RemoteType<'a>>,
57
/// A cached instance of the path to the `bevy_reflect` crate.
58
bevy_reflect_path: Path,
59
/// The documentation for this type, if any
60
#[cfg(feature = "reflect_documentation")]
61
docs: crate::documentation::Documentation,
62
}
63
64
/// Struct data used by derive macros for `Reflect` and `FromReflect`.
65
///
66
/// # Example
67
///
68
/// ```ignore (bevy_reflect is not accessible from this crate)
69
/// #[derive(Reflect)]
70
/// #[reflect(PartialEq, Serialize, Deserialize, Default)]
71
/// struct ThingThatImReflecting<T1, T2, T3> {
72
/// x: T1, // |
73
/// y: T2, // |- fields
74
/// z: T3 // |
75
/// }
76
/// ```
77
pub(crate) struct ReflectStruct<'a> {
78
meta: ReflectMeta<'a>,
79
serialization_data: Option<SerializationDataDef>,
80
fields: Vec<StructField<'a>>,
81
}
82
83
/// Enum data used by derive macros for `Reflect` and `FromReflect`.
84
///
85
/// # Example
86
///
87
/// ```ignore (bevy_reflect is not accessible from this crate)
88
/// #[derive(Reflect)]
89
/// #[reflect(PartialEq, Serialize, Deserialize, Default)]
90
/// enum ThingThatImReflecting<T1, T2, T3> {
91
/// A(T1), // |
92
/// B, // |- variants
93
/// C { foo: T2, bar: T3 } // |
94
/// }
95
/// ```
96
pub(crate) struct ReflectEnum<'a> {
97
meta: ReflectMeta<'a>,
98
variants: Vec<EnumVariant<'a>>,
99
}
100
101
/// Represents a field on a struct or tuple struct.
102
#[derive(Clone)]
103
pub(crate) struct StructField<'a> {
104
/// The raw field.
105
pub data: &'a Field,
106
/// The reflection-based attributes on the field.
107
pub attrs: FieldAttributes,
108
/// The index of this field within the struct.
109
pub declaration_index: usize,
110
/// The index of this field as seen by the reflection API.
111
///
112
/// This index accounts for the removal of [ignored] fields.
113
/// It will only be `Some(index)` when the field is not ignored.
114
///
115
/// [ignored]: crate::field_attributes::ReflectIgnoreBehavior::IgnoreAlways
116
pub reflection_index: Option<usize>,
117
/// The documentation for this field, if any
118
#[cfg(feature = "reflect_documentation")]
119
pub doc: crate::documentation::Documentation,
120
}
121
122
/// Represents a variant on an enum.
123
pub(crate) struct EnumVariant<'a> {
124
/// The raw variant.
125
pub data: &'a Variant,
126
/// The fields within this variant.
127
pub fields: EnumVariantFields<'a>,
128
/// The reflection-based attributes on the variant.
129
pub attrs: FieldAttributes,
130
/// The documentation for this variant, if any
131
#[cfg(feature = "reflect_documentation")]
132
pub doc: crate::documentation::Documentation,
133
}
134
135
pub(crate) enum EnumVariantFields<'a> {
136
Named(Vec<StructField<'a>>),
137
Unnamed(Vec<StructField<'a>>),
138
Unit,
139
}
140
141
/// How the macro was invoked.
142
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
143
pub(crate) enum ReflectImplSource {
144
/// Using `impl_reflect!`.
145
ImplRemoteType,
146
/// Using `#[derive(...)]`.
147
DeriveLocalType,
148
/// Using `#[reflect_remote]`.
149
RemoteReflect,
150
}
151
152
/// Which trait the macro explicitly implements.
153
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
154
pub(crate) enum ReflectTraitToImpl {
155
Reflect,
156
FromReflect,
157
TypePath,
158
}
159
160
/// The provenance of a macro invocation.
161
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
162
pub(crate) struct ReflectProvenance {
163
pub source: ReflectImplSource,
164
pub trait_: ReflectTraitToImpl,
165
}
166
167
impl fmt::Display for ReflectProvenance {
168
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
169
use self::{ReflectImplSource as S, ReflectTraitToImpl as T};
170
let str = match (self.source, self.trait_) {
171
(S::ImplRemoteType, T::Reflect) => "`impl_reflect`",
172
(S::DeriveLocalType, T::Reflect) => "`#[derive(Reflect)]`",
173
(S::DeriveLocalType, T::FromReflect) => "`#[derive(FromReflect)]`",
174
(S::DeriveLocalType, T::TypePath) => "`#[derive(TypePath)]`",
175
(S::RemoteReflect, T::Reflect) => "`#[reflect_remote]`",
176
(S::RemoteReflect, T::FromReflect | T::TypePath)
177
| (S::ImplRemoteType, T::FromReflect | T::TypePath) => unreachable!(),
178
};
179
f.write_str(str)
180
}
181
}
182
183
impl<'a> ReflectDerive<'a> {
184
pub fn from_input(
185
input: &'a DeriveInput,
186
provenance: ReflectProvenance,
187
) -> Result<Self, syn::Error> {
188
let mut container_attributes = ContainerAttributes::default();
189
// Should indicate whether `#[type_path = "..."]` was used.
190
let mut custom_path: Option<Path> = None;
191
// Should indicate whether `#[type_name = "..."]` was used.
192
let mut custom_type_name: Option<Ident> = None;
193
194
#[cfg(feature = "reflect_documentation")]
195
let mut doc = crate::documentation::Documentation::default();
196
197
for attribute in &input.attrs {
198
match &attribute.meta {
199
Meta::List(meta_list) if meta_list.path.is_ident(REFLECT_ATTRIBUTE_NAME) => {
200
if let MacroDelimiter::Paren(_) = meta_list.delimiter {
201
container_attributes.parse_meta_list(meta_list, provenance.trait_)?;
202
} else {
203
return Err(syn::Error::new(
204
meta_list.delimiter.span().join(),
205
format_args!(
206
"`#[{REFLECT_ATTRIBUTE_NAME}(\"...\")]` must use parentheses `(` and `)`"
207
),
208
));
209
}
210
}
211
Meta::NameValue(pair) if pair.path.is_ident(TYPE_PATH_ATTRIBUTE_NAME) => {
212
let syn::Expr::Lit(syn::ExprLit {
213
lit: syn::Lit::Str(lit),
214
..
215
}) = &pair.value
216
else {
217
return Err(syn::Error::new(
218
pair.span(),
219
format_args!("`#[{TYPE_PATH_ATTRIBUTE_NAME} = \"...\"]` must be a string literal"),
220
));
221
};
222
223
custom_path = Some(syn::parse::Parser::parse_str(
224
parse_path_no_leading_colon,
225
&lit.value(),
226
)?);
227
}
228
Meta::NameValue(pair) if pair.path.is_ident(TYPE_NAME_ATTRIBUTE_NAME) => {
229
let syn::Expr::Lit(syn::ExprLit {
230
lit: syn::Lit::Str(lit),
231
..
232
}) = &pair.value
233
else {
234
return Err(syn::Error::new(
235
pair.span(),
236
format_args!("`#[{TYPE_NAME_ATTRIBUTE_NAME} = \"...\"]` must be a string literal"),
237
));
238
};
239
240
custom_type_name = Some(parse_str(&lit.value())?);
241
}
242
#[cfg(feature = "reflect_documentation")]
243
Meta::NameValue(pair) if pair.path.is_ident("doc") => {
244
if let syn::Expr::Lit(syn::ExprLit {
245
lit: syn::Lit::Str(lit),
246
..
247
}) = &pair.value
248
{
249
doc.push(lit.value());
250
}
251
}
252
_ => continue,
253
}
254
}
255
match (&mut custom_path, custom_type_name) {
256
(Some(path), custom_type_name) => {
257
let ident = custom_type_name.unwrap_or_else(|| input.ident.clone());
258
path.segments.push(PathSegment::from(ident));
259
}
260
(None, Some(name)) => {
261
return Err(syn::Error::new(
262
name.span(),
263
format!("cannot use `#[{TYPE_NAME_ATTRIBUTE_NAME} = \"...\"]` without a `#[{TYPE_PATH_ATTRIBUTE_NAME} = \"...\"]` attribute."),
264
));
265
}
266
_ => (),
267
}
268
269
let type_path = ReflectTypePath::Internal {
270
ident: &input.ident,
271
custom_path,
272
generics: &input.generics,
273
};
274
275
let meta = ReflectMeta::new(type_path, container_attributes);
276
277
if provenance.source == ReflectImplSource::ImplRemoteType
278
&& meta.type_path_attrs().should_auto_derive()
279
&& !meta.type_path().has_custom_path()
280
{
281
return Err(syn::Error::new(
282
meta.type_path().span(),
283
format!("a #[{TYPE_PATH_ATTRIBUTE_NAME} = \"...\"] attribute must be specified when using {provenance}"),
284
));
285
}
286
287
#[cfg(feature = "reflect_documentation")]
288
let meta = meta.with_docs(doc);
289
290
if meta.attrs().is_opaque() {
291
return Ok(Self::Opaque(meta));
292
}
293
294
match &input.data {
295
Data::Struct(data) => {
296
let fields = Self::collect_struct_fields(&data.fields)?;
297
let serialization_data =
298
SerializationDataDef::new(&fields, &meta.bevy_reflect_path)?;
299
let reflect_struct = ReflectStruct {
300
meta,
301
serialization_data,
302
fields,
303
};
304
305
match data.fields {
306
Fields::Named(..) => Ok(Self::Struct(reflect_struct)),
307
Fields::Unnamed(..) => Ok(Self::TupleStruct(reflect_struct)),
308
Fields::Unit => Ok(Self::UnitStruct(reflect_struct)),
309
}
310
}
311
Data::Enum(data) => {
312
let variants = Self::collect_enum_variants(&data.variants)?;
313
314
let reflect_enum = ReflectEnum { meta, variants };
315
Ok(Self::Enum(reflect_enum))
316
}
317
Data::Union(..) => Err(syn::Error::new(
318
input.span(),
319
"reflection not supported for unions",
320
)),
321
}
322
}
323
324
/// Set the remote type for this derived type.
325
///
326
/// # Panics
327
///
328
/// Panics when called on [`ReflectDerive::Opaque`].
329
pub fn set_remote(&mut self, remote_ty: Option<RemoteType<'a>>) {
330
match self {
331
Self::Struct(data) | Self::TupleStruct(data) | Self::UnitStruct(data) => {
332
data.meta.remote_ty = remote_ty;
333
}
334
Self::Enum(data) => {
335
data.meta.remote_ty = remote_ty;
336
}
337
Self::Opaque(meta) => {
338
meta.remote_ty = remote_ty;
339
}
340
}
341
}
342
343
/// Get the remote type path, if any.
344
pub fn remote_ty(&self) -> Option<RemoteType<'_>> {
345
match self {
346
Self::Struct(data) | Self::TupleStruct(data) | Self::UnitStruct(data) => {
347
data.meta.remote_ty()
348
}
349
Self::Enum(data) => data.meta.remote_ty(),
350
Self::Opaque(meta) => meta.remote_ty(),
351
}
352
}
353
354
/// Get the [`ReflectMeta`] for this derived type.
355
pub fn meta(&self) -> &ReflectMeta<'_> {
356
match self {
357
Self::Struct(data) | Self::TupleStruct(data) | Self::UnitStruct(data) => data.meta(),
358
Self::Enum(data) => data.meta(),
359
Self::Opaque(meta) => meta,
360
}
361
}
362
363
pub fn where_clause_options(&self) -> WhereClauseOptions<'_, '_> {
364
match self {
365
Self::Struct(data) | Self::TupleStruct(data) | Self::UnitStruct(data) => {
366
data.where_clause_options()
367
}
368
Self::Enum(data) => data.where_clause_options(),
369
Self::Opaque(meta) => WhereClauseOptions::new(meta),
370
}
371
}
372
373
fn collect_struct_fields(fields: &'a Fields) -> Result<Vec<StructField<'a>>, syn::Error> {
374
let mut active_index = 0;
375
let sifter: ResultSifter<StructField<'a>> = fields
376
.iter()
377
.enumerate()
378
.map(
379
|(declaration_index, field)| -> Result<StructField, syn::Error> {
380
let attrs = FieldAttributes::parse_attributes(&field.attrs)?;
381
382
let reflection_index = if attrs.ignore.is_ignored() {
383
None
384
} else {
385
active_index += 1;
386
Some(active_index - 1)
387
};
388
389
Ok(StructField {
390
declaration_index,
391
reflection_index,
392
attrs,
393
data: field,
394
#[cfg(feature = "reflect_documentation")]
395
doc: crate::documentation::Documentation::from_attributes(&field.attrs),
396
})
397
},
398
)
399
.fold(ResultSifter::default(), ResultSifter::fold);
400
401
sifter.finish()
402
}
403
404
fn collect_enum_variants(
405
variants: &'a Punctuated<Variant, Comma>,
406
) -> Result<Vec<EnumVariant<'a>>, syn::Error> {
407
let sifter: ResultSifter<EnumVariant<'a>> = variants
408
.iter()
409
.map(|variant| -> Result<EnumVariant, syn::Error> {
410
let fields = Self::collect_struct_fields(&variant.fields)?;
411
412
let fields = match variant.fields {
413
Fields::Named(..) => EnumVariantFields::Named(fields),
414
Fields::Unnamed(..) => EnumVariantFields::Unnamed(fields),
415
Fields::Unit => EnumVariantFields::Unit,
416
};
417
Ok(EnumVariant {
418
fields,
419
attrs: FieldAttributes::parse_attributes(&variant.attrs)?,
420
data: variant,
421
#[cfg(feature = "reflect_documentation")]
422
doc: crate::documentation::Documentation::from_attributes(&variant.attrs),
423
})
424
})
425
.fold(ResultSifter::default(), ResultSifter::fold);
426
427
sifter.finish()
428
}
429
}
430
431
impl<'a> ReflectMeta<'a> {
432
pub fn new(type_path: ReflectTypePath<'a>, attrs: ContainerAttributes) -> Self {
433
Self {
434
attrs,
435
type_path,
436
remote_ty: None,
437
bevy_reflect_path: crate::meta::get_bevy_reflect_path(),
438
#[cfg(feature = "reflect_documentation")]
439
docs: Default::default(),
440
}
441
}
442
443
/// Sets the documentation for this type.
444
#[cfg(feature = "reflect_documentation")]
445
pub fn with_docs(self, docs: crate::documentation::Documentation) -> Self {
446
Self { docs, ..self }
447
}
448
449
/// The registered reflect attributes on this struct.
450
pub fn attrs(&self) -> &ContainerAttributes {
451
&self.attrs
452
}
453
454
/// The `FromReflect` attributes on this type.
455
#[expect(
456
clippy::wrong_self_convention,
457
reason = "Method returns `FromReflectAttrs`, does not actually convert data."
458
)]
459
pub fn from_reflect(&self) -> &FromReflectAttrs {
460
self.attrs.from_reflect_attrs()
461
}
462
463
/// The `TypePath` attributes on this type.
464
pub fn type_path_attrs(&self) -> &TypePathAttrs {
465
self.attrs.type_path_attrs()
466
}
467
468
/// The path to this type.
469
pub fn type_path(&self) -> &ReflectTypePath<'a> {
470
&self.type_path
471
}
472
473
/// Get the remote type path, if any.
474
pub fn remote_ty(&self) -> Option<RemoteType<'_>> {
475
self.remote_ty
476
}
477
478
/// Whether this reflected type represents a remote type or not.
479
pub fn is_remote_wrapper(&self) -> bool {
480
self.remote_ty.is_some()
481
}
482
483
/// The cached `bevy_reflect` path.
484
pub fn bevy_reflect_path(&self) -> &Path {
485
&self.bevy_reflect_path
486
}
487
488
/// Returns the `GetTypeRegistration` impl as a `TokenStream`.
489
pub fn get_type_registration(
490
&self,
491
where_clause_options: &WhereClauseOptions,
492
) -> proc_macro2::TokenStream {
493
crate::registration::impl_get_type_registration(
494
where_clause_options,
495
None,
496
Option::<core::iter::Empty<&Type>>::None,
497
)
498
}
499
500
/// The collection of docstrings for this type, if any.
501
#[cfg(feature = "reflect_documentation")]
502
pub fn doc(&self) -> &crate::documentation::Documentation {
503
&self.docs
504
}
505
}
506
507
impl<'a> StructField<'a> {
508
/// Generates a `TokenStream` for `NamedField` or `UnnamedField` construction.
509
pub fn to_info_tokens(&self, bevy_reflect_path: &Path) -> proc_macro2::TokenStream {
510
let name = match &self.data.ident {
511
Some(ident) => ident.to_string().to_token_stream(),
512
None => self.reflection_index.to_token_stream(),
513
};
514
515
let field_info = if self.data.ident.is_some() {
516
quote! {
517
#bevy_reflect_path::NamedField
518
}
519
} else {
520
quote! {
521
#bevy_reflect_path::UnnamedField
522
}
523
};
524
525
let ty = self.reflected_type();
526
527
let mut info = quote! {
528
#field_info::new::<#ty>(#name)
529
};
530
531
let custom_attributes = &self.attrs.custom_attributes;
532
if !custom_attributes.is_empty() {
533
let custom_attributes = custom_attributes.to_tokens(bevy_reflect_path);
534
info.extend(quote! {
535
.with_custom_attributes(#custom_attributes)
536
});
537
}
538
539
#[cfg(feature = "reflect_documentation")]
540
{
541
let docs = &self.doc;
542
if !docs.is_empty() {
543
info.extend(quote! {
544
.with_docs(#docs)
545
});
546
}
547
}
548
549
info
550
}
551
552
/// Returns the reflected type of this field.
553
///
554
/// Normally this is just the field's defined type.
555
/// However, this can be adjusted to use a different type, like for representing remote types.
556
/// In those cases, the returned value is the remote wrapper type.
557
pub fn reflected_type(&self) -> &Type {
558
self.attrs.remote.as_ref().unwrap_or(&self.data.ty)
559
}
560
561
pub fn attrs(&self) -> &FieldAttributes {
562
&self.attrs
563
}
564
565
/// Generates a [`Member`] based on this field.
566
///
567
/// If the field is unnamed, the declaration index is used.
568
/// This allows this member to be used for both active and ignored fields.
569
pub fn to_member(&self) -> Member {
570
match &self.data.ident {
571
Some(ident) => Member::Named(ident.clone()),
572
None => Member::Unnamed(self.declaration_index.into()),
573
}
574
}
575
576
/// Returns a token stream for generating a `FieldId` for this field.
577
pub fn field_id(&self, bevy_reflect_path: &Path) -> proc_macro2::TokenStream {
578
match &self.data.ident {
579
Some(ident) => {
580
let name = ident.to_string();
581
quote!(#bevy_reflect_path::FieldId::Named(#bevy_reflect_path::__macro_exports::alloc_utils::Cow::Borrowed(#name)))
582
}
583
None => {
584
let index = self.declaration_index;
585
quote!(#bevy_reflect_path::FieldId::Unnamed(#index))
586
}
587
}
588
}
589
}
590
591
impl<'a> ReflectStruct<'a> {
592
/// Access the metadata associated with this struct definition.
593
pub fn meta(&self) -> &ReflectMeta<'a> {
594
&self.meta
595
}
596
597
/// Returns the [`SerializationDataDef`] for this struct.
598
pub fn serialization_data(&self) -> Option<&SerializationDataDef> {
599
self.serialization_data.as_ref()
600
}
601
602
/// Returns the `GetTypeRegistration` impl as a `TokenStream`.
603
///
604
/// Returns a specific implementation for structs and this method should be preferred over the generic [`get_type_registration`](ReflectMeta) method
605
pub fn get_type_registration(
606
&self,
607
where_clause_options: &WhereClauseOptions,
608
) -> proc_macro2::TokenStream {
609
crate::registration::impl_get_type_registration(
610
where_clause_options,
611
self.serialization_data(),
612
Some(self.active_types().iter()),
613
)
614
}
615
616
/// Get a collection of types which are exposed to the reflection API
617
pub fn active_types(&self) -> IndexSet<Type> {
618
// Collect into an `IndexSet` to eliminate duplicate types.
619
self.active_fields()
620
.map(|field| field.reflected_type().clone())
621
.collect::<IndexSet<_>>()
622
}
623
624
/// Get an iterator of fields which are exposed to the reflection API.
625
pub fn active_fields(&self) -> impl Iterator<Item = &StructField<'a>> {
626
self.fields()
627
.iter()
628
.filter(|field| field.attrs.ignore.is_active())
629
}
630
631
/// Get an iterator of fields which are ignored by the reflection API
632
pub fn ignored_fields(&self) -> impl Iterator<Item = &StructField<'a>> {
633
self.fields()
634
.iter()
635
.filter(|field| field.attrs.ignore.is_ignored())
636
}
637
638
/// The complete set of fields in this struct.
639
pub fn fields(&self) -> &[StructField<'a>] {
640
&self.fields
641
}
642
643
pub fn where_clause_options(&self) -> WhereClauseOptions<'_, '_> {
644
WhereClauseOptions::new_with_types(self.meta(), self.active_types())
645
}
646
647
/// Generates a `TokenStream` for `TypeInfo::Struct` or `TypeInfo::TupleStruct` construction.
648
pub fn to_info_tokens(&self, is_tuple: bool) -> proc_macro2::TokenStream {
649
let bevy_reflect_path = self.meta().bevy_reflect_path();
650
651
let (info_variant, info_struct): (_, Path) = if is_tuple {
652
(
653
Ident::new("TupleStruct", Span::call_site()),
654
parse_str("tuple_struct::TupleStructInfo").expect("should be a valid path"),
655
)
656
} else {
657
(
658
Ident::new("Struct", Span::call_site()),
659
parse_str("structs::StructInfo").expect("should be a valid path"),
660
)
661
};
662
663
let field_infos = self
664
.active_fields()
665
.map(|field| field.to_info_tokens(bevy_reflect_path));
666
667
let mut info = quote! {
668
#bevy_reflect_path::#info_struct::new::<Self>(&[
669
#(#field_infos),*
670
])
671
};
672
673
let custom_attributes = self.meta.attrs.custom_attributes();
674
if !custom_attributes.is_empty() {
675
let custom_attributes = custom_attributes.to_tokens(bevy_reflect_path);
676
info.extend(quote! {
677
.with_custom_attributes(#custom_attributes)
678
});
679
}
680
681
if let Some(generics) = generate_generics(self.meta()) {
682
info.extend(quote! {
683
.with_generics(#generics)
684
});
685
}
686
687
#[cfg(feature = "reflect_documentation")]
688
{
689
let docs = self.meta().doc();
690
if !docs.is_empty() {
691
info.extend(quote! {
692
.with_docs(#docs)
693
});
694
}
695
}
696
697
quote! {
698
#bevy_reflect_path::TypeInfo::#info_variant(#info)
699
}
700
}
701
/// Returns the `Reflect::reflect_clone` impl, if any, as a `TokenStream`.
702
pub fn get_clone_impl(&self) -> Option<proc_macro2::TokenStream> {
703
let bevy_reflect_path = self.meta().bevy_reflect_path();
704
705
if let container_clone @ Some(_) = self.meta().attrs().get_clone_impl(bevy_reflect_path) {
706
return container_clone;
707
}
708
709
let mut tokens = proc_macro2::TokenStream::new();
710
711
for field in self.fields().iter() {
712
let field_ty = field.reflected_type();
713
let member = field.to_member();
714
let accessor = self.access_for_field(field, false);
715
716
match &field.attrs.clone {
717
CloneBehavior::Default => {
718
let value = if field.attrs.ignore.is_ignored() {
719
let field_id = field.field_id(bevy_reflect_path);
720
721
quote! {
722
return #FQResult::Err(#bevy_reflect_path::ReflectCloneError::FieldNotCloneable {
723
field: #field_id,
724
variant: #FQOption::None,
725
container_type_path: #bevy_reflect_path::__macro_exports::alloc_utils::Cow::Borrowed(
726
<Self as #bevy_reflect_path::TypePath>::type_path()
727
)
728
})
729
}
730
} else {
731
quote! {
732
<#field_ty as #bevy_reflect_path::PartialReflect>::reflect_clone_and_take(#accessor)?
733
}
734
};
735
736
tokens.extend(quote! {
737
#member: #value,
738
});
739
}
740
CloneBehavior::Trait => {
741
tokens.extend(quote! {
742
#member: #FQClone::clone(#accessor),
743
});
744
}
745
CloneBehavior::Func(clone_fn) => {
746
tokens.extend(quote! {
747
#member: #clone_fn(#accessor),
748
});
749
}
750
}
751
}
752
753
let ctor = match self.meta.remote_ty() {
754
Some(ty) => {
755
let ty = ty.as_expr_path().ok()?.to_token_stream();
756
quote! {
757
Self(#ty {
758
#tokens
759
})
760
}
761
}
762
None => {
763
quote! {
764
Self {
765
#tokens
766
}
767
}
768
}
769
};
770
771
Some(quote! {
772
#[inline]
773
#[allow(unreachable_code, reason = "Ignored fields without a `clone` attribute will early-return with an error")]
774
fn reflect_clone(&self) -> #FQResult<#bevy_reflect_path::__macro_exports::alloc_utils::Box<dyn #bevy_reflect_path::Reflect>, #bevy_reflect_path::ReflectCloneError> {
775
#FQResult::Ok(#bevy_reflect_path::__macro_exports::alloc_utils::Box::new(#ctor))
776
}
777
})
778
}
779
780
/// Generates an accessor for the given field.
781
///
782
/// The mutability of the access can be controlled by the `is_mut` parameter.
783
///
784
/// Generally, this just returns something like `&self.field`.
785
/// However, if the struct is a remote wrapper, this then becomes `&self.0.field` in order to access the field on the inner type.
786
///
787
/// If the field itself is a remote type, the above accessor is further wrapped in a call to `ReflectRemote::as_wrapper[_mut]`.
788
pub fn access_for_field(
789
&self,
790
field: &StructField<'a>,
791
is_mutable: bool,
792
) -> proc_macro2::TokenStream {
793
let bevy_reflect_path = self.meta().bevy_reflect_path();
794
let member = field.to_member();
795
796
let prefix_tokens = if is_mutable { quote!(&mut) } else { quote!(&) };
797
798
let accessor = if self.meta.is_remote_wrapper() {
799
quote!(self.0.#member)
800
} else {
801
quote!(self.#member)
802
};
803
804
match &field.attrs.remote {
805
Some(wrapper_ty) => {
806
let method = if is_mutable {
807
format_ident!("as_wrapper_mut")
808
} else {
809
format_ident!("as_wrapper")
810
};
811
812
quote! {
813
<#wrapper_ty as #bevy_reflect_path::ReflectRemote>::#method(#prefix_tokens #accessor)
814
}
815
}
816
None => quote!(#prefix_tokens #accessor),
817
}
818
}
819
}
820
821
impl<'a> ReflectEnum<'a> {
822
/// Access the metadata associated with this enum definition.
823
pub fn meta(&self) -> &ReflectMeta<'a> {
824
&self.meta
825
}
826
827
/// Returns the given ident as a qualified unit variant of this enum.
828
///
829
/// This takes into account the remote type, if any.
830
pub fn get_unit(&self, variant: &Ident) -> proc_macro2::TokenStream {
831
let name = self
832
.meta
833
.remote_ty
834
.map(|path| match path.as_expr_path() {
835
Ok(path) => path.to_token_stream(),
836
Err(err) => err.into_compile_error(),
837
})
838
.unwrap_or_else(|| self.meta.type_path().to_token_stream());
839
840
quote! {
841
#name::#variant
842
}
843
}
844
845
/// The complete set of variants in this enum.
846
pub fn variants(&self) -> &[EnumVariant<'a>] {
847
&self.variants
848
}
849
850
/// Get a collection of types which are exposed to the reflection API
851
pub fn active_types(&self) -> IndexSet<Type> {
852
// Collect into an `IndexSet` to eliminate duplicate types.
853
self.active_fields()
854
.map(|field| field.reflected_type().clone())
855
.collect::<IndexSet<_>>()
856
}
857
858
/// Get an iterator of fields which are exposed to the reflection API
859
pub fn active_fields(&self) -> impl Iterator<Item = &StructField<'a>> {
860
self.variants.iter().flat_map(EnumVariant::active_fields)
861
}
862
863
pub fn where_clause_options(&self) -> WhereClauseOptions<'_, '_> {
864
WhereClauseOptions::new_with_types(self.meta(), self.active_types())
865
}
866
867
/// Returns the `GetTypeRegistration` impl as a `TokenStream`.
868
///
869
/// Returns a specific implementation for enums and this method should be preferred over the generic [`get_type_registration`](crate::ReflectMeta) method
870
pub fn get_type_registration(
871
&self,
872
where_clause_options: &WhereClauseOptions,
873
) -> proc_macro2::TokenStream {
874
crate::registration::impl_get_type_registration(
875
where_clause_options,
876
None,
877
Some(self.active_types().iter()),
878
)
879
}
880
881
/// Generates a `TokenStream` for `TypeInfo::Enum` construction.
882
pub fn to_info_tokens(&self) -> proc_macro2::TokenStream {
883
let bevy_reflect_path = self.meta().bevy_reflect_path();
884
885
let variants = self
886
.variants
887
.iter()
888
.map(|variant| variant.to_info_tokens(bevy_reflect_path));
889
890
let mut info = quote! {
891
#bevy_reflect_path::enums::EnumInfo::new::<Self>(&[
892
#(#variants),*
893
])
894
};
895
896
let custom_attributes = self.meta.attrs.custom_attributes();
897
if !custom_attributes.is_empty() {
898
let custom_attributes = custom_attributes.to_tokens(bevy_reflect_path);
899
info.extend(quote! {
900
.with_custom_attributes(#custom_attributes)
901
});
902
}
903
904
if let Some(generics) = generate_generics(self.meta()) {
905
info.extend(quote! {
906
.with_generics(#generics)
907
});
908
}
909
910
#[cfg(feature = "reflect_documentation")]
911
{
912
let docs = self.meta().doc();
913
if !docs.is_empty() {
914
info.extend(quote! {
915
.with_docs(#docs)
916
});
917
}
918
}
919
920
quote! {
921
#bevy_reflect_path::TypeInfo::Enum(#info)
922
}
923
}
924
925
/// Returns the `Reflect::reflect_clone` impl, if any, as a `TokenStream`.
926
pub fn get_clone_impl(&self) -> Option<proc_macro2::TokenStream> {
927
let bevy_reflect_path = self.meta().bevy_reflect_path();
928
929
if let container_clone @ Some(_) = self.meta().attrs().get_clone_impl(bevy_reflect_path) {
930
return container_clone;
931
}
932
933
let this = Ident::new("this", Span::call_site());
934
let EnumVariantOutputData {
935
variant_patterns,
936
variant_constructors,
937
..
938
} = ReflectCloneVariantBuilder::new(self).build(&this);
939
940
let inner = quote! {
941
match #this {
942
#(#variant_patterns => #variant_constructors),*
943
}
944
};
945
946
let body = if variant_patterns.is_empty() {
947
// enum variant is empty, so &self will never exist
948
quote!(unreachable!())
949
} else if self.meta.is_remote_wrapper() {
950
quote! {
951
let #this = <Self as #bevy_reflect_path::ReflectRemote>::as_remote(self);
952
#FQResult::Ok(#bevy_reflect_path::__macro_exports::alloc_utils::Box::new(<Self as #bevy_reflect_path::ReflectRemote>::into_wrapper(#inner)))
953
}
954
} else {
955
quote! {
956
let #this = self;
957
#FQResult::Ok(#bevy_reflect_path::__macro_exports::alloc_utils::Box::new(#inner))
958
}
959
};
960
961
Some(quote! {
962
#[inline]
963
#[allow(unreachable_code, reason = "Ignored fields without a `clone` attribute will early-return with an error")]
964
fn reflect_clone(&self) -> #FQResult<#bevy_reflect_path::__macro_exports::alloc_utils::Box<dyn #bevy_reflect_path::Reflect>, #bevy_reflect_path::ReflectCloneError> {
965
#body
966
}
967
})
968
}
969
}
970
971
impl<'a> EnumVariant<'a> {
972
/// Get an iterator of fields which are exposed to the reflection API
973
pub fn active_fields(&self) -> impl Iterator<Item = &StructField<'a>> {
974
self.fields()
975
.iter()
976
.filter(|field| field.attrs.ignore.is_active())
977
}
978
979
/// The complete set of fields in this variant.
980
pub fn fields(&self) -> &[StructField<'a>] {
981
match &self.fields {
982
EnumVariantFields::Named(fields) | EnumVariantFields::Unnamed(fields) => fields,
983
EnumVariantFields::Unit => &[],
984
}
985
}
986
987
/// Generates a `TokenStream` for `VariantInfo` construction.
988
pub fn to_info_tokens(&self, bevy_reflect_path: &Path) -> proc_macro2::TokenStream {
989
let variant_name = &self.data.ident.to_string();
990
991
let (info_variant, info_struct) = match &self.fields {
992
EnumVariantFields::Unit => (
993
Ident::new("Unit", Span::call_site()),
994
Ident::new("UnitVariantInfo", Span::call_site()),
995
),
996
EnumVariantFields::Unnamed(..) => (
997
Ident::new("Tuple", Span::call_site()),
998
Ident::new("TupleVariantInfo", Span::call_site()),
999
),
1000
EnumVariantFields::Named(..) => (
1001
Ident::new("Struct", Span::call_site()),
1002
Ident::new("StructVariantInfo", Span::call_site()),
1003
),
1004
};
1005
1006
let fields = self
1007
.active_fields()
1008
.map(|field| field.to_info_tokens(bevy_reflect_path));
1009
1010
let args = match &self.fields {
1011
EnumVariantFields::Unit => quote!(#variant_name),
1012
_ => {
1013
quote!( #variant_name , &[#(#fields),*] )
1014
}
1015
};
1016
1017
let mut info = quote! {
1018
#bevy_reflect_path::enums::#info_struct::new(#args)
1019
};
1020
1021
let custom_attributes = &self.attrs.custom_attributes;
1022
if !custom_attributes.is_empty() {
1023
let custom_attributes = custom_attributes.to_tokens(bevy_reflect_path);
1024
info.extend(quote! {
1025
.with_custom_attributes(#custom_attributes)
1026
});
1027
}
1028
1029
#[cfg(feature = "reflect_documentation")]
1030
{
1031
let docs = &self.doc;
1032
if !docs.is_empty() {
1033
info.extend(quote! {
1034
.with_docs(#docs)
1035
});
1036
}
1037
}
1038
1039
quote! {
1040
#bevy_reflect_path::enums::VariantInfo::#info_variant(#info)
1041
}
1042
}
1043
}
1044
1045
/// Represents a path to a type.
1046
///
1047
/// This is used over [`struct@Ident`] or [`Path`]
1048
/// to have the correct semantics for [deriving `TypePath`].
1049
///
1050
/// The type can always be reached with its [`ToTokens`] implementation.
1051
///
1052
/// The [`short_type_path`], [`type_ident`], [`crate_name`], and [`module_path`] methods
1053
/// have corresponding methods on the `TypePath` trait.
1054
/// [`long_type_path`] corresponds to the `type_path` method on `TypePath`.
1055
///
1056
/// [deriving `TypePath`]: crate::derive_type_path
1057
/// [`long_type_path`]: ReflectTypePath::long_type_path
1058
/// [`short_type_path`]: ReflectTypePath::short_type_path
1059
/// [`type_ident`]: ReflectTypePath::type_ident
1060
/// [`crate_name`]: ReflectTypePath::crate_name
1061
/// [`module_path`]: ReflectTypePath::module_path
1062
///
1063
/// # Example
1064
///
1065
/// ```ignore (bevy_reflect is not accessible from this crate)
1066
/// # use syn::parse_quote;
1067
/// # use bevy_reflect_derive::ReflectTypePath;
1068
/// let path: syn::Path = parse_quote!(::std::marker::PhantomData)?;
1069
///
1070
/// let type_path = ReflectTypePath::External {
1071
/// path,
1072
/// custom_path: None,
1073
/// };
1074
///
1075
/// // Equivalent to "std::marker".
1076
/// let module_path = type_path.module_path();
1077
/// # Ok::<(), syn::Error>(())
1078
/// ```
1079
pub(crate) enum ReflectTypePath<'a> {
1080
/// Types without a crate/module that can be named from any scope (e.g. `bool`).
1081
Primitive(&'a Ident),
1082
/// Using `::my_crate::foo::Bar` syntax.
1083
///
1084
/// May have a separate custom path used for the `TypePath` implementation.
1085
External {
1086
path: &'a Path,
1087
custom_path: Option<Path>,
1088
generics: &'a Generics,
1089
},
1090
/// The name of a type relative to its scope.
1091
///
1092
/// The type must be able to be reached with just its name.
1093
///
1094
/// May have a separate alias path used for the `TypePath` implementation.
1095
///
1096
/// Module and crate are found with [`module_path!()`](module_path),
1097
/// if there is no custom path specified.
1098
Internal {
1099
ident: &'a Ident,
1100
custom_path: Option<Path>,
1101
generics: &'a Generics,
1102
},
1103
/// Any [`Type`] with only a defined `type_path` and `short_type_path`.
1104
#[expect(
1105
dead_code,
1106
reason = "Not currently used but may be useful in the future due to its generality."
1107
)]
1108
Anonymous {
1109
qualified_type: Box<Type>,
1110
long_type_path: StringExpr,
1111
short_type_path: StringExpr,
1112
},
1113
}
1114
1115
impl<'a> ReflectTypePath<'a> {
1116
/// Returns the path interpreted as an [`struct@Ident`].
1117
///
1118
/// Returns [`None`] if [anonymous].
1119
///
1120
/// [anonymous]: ReflectTypePath::Anonymous
1121
pub fn get_ident(&self) -> Option<&Ident> {
1122
match self {
1123
Self::Internal {
1124
ident, custom_path, ..
1125
} => Some(
1126
custom_path
1127
.as_ref()
1128
.map(|path| &path.segments.last().unwrap().ident)
1129
.unwrap_or(ident),
1130
),
1131
Self::External {
1132
path, custom_path, ..
1133
} => Some(
1134
&custom_path
1135
.as_ref()
1136
.unwrap_or(path)
1137
.segments
1138
.last()
1139
.unwrap()
1140
.ident,
1141
),
1142
Self::Primitive(ident) => Some(ident),
1143
_ => None,
1144
}
1145
}
1146
1147
/// The generics associated with the type.
1148
///
1149
/// Empty if [anonymous] or [primitive].
1150
///
1151
/// [primitive]: ReflectTypePath::Primitive
1152
/// [anonymous]: ReflectTypePath::Anonymous
1153
pub fn generics(&self) -> &'a Generics {
1154
// Use a constant because we need to return a reference of at least 'a.
1155
const EMPTY_GENERICS: &Generics = &Generics {
1156
gt_token: None,
1157
lt_token: None,
1158
where_clause: None,
1159
params: Punctuated::new(),
1160
};
1161
1162
match self {
1163
Self::Internal { generics, .. } | Self::External { generics, .. } => generics,
1164
_ => EMPTY_GENERICS,
1165
}
1166
}
1167
1168
/// Whether an implementation of `Typed` or `TypePath` should be generic.
1169
///
1170
/// Returning true that it should use a `GenericTypeCell` in its implementation.
1171
pub fn impl_is_generic(&self) -> bool {
1172
// Whether to use `GenericTypeCell` is not dependent on lifetimes
1173
// (which all have to be 'static anyway).
1174
!self
1175
.generics()
1176
.params
1177
.iter()
1178
.all(|param| matches!(param, GenericParam::Lifetime(_)))
1179
}
1180
1181
/// Returns the path interpreted as a [`Path`].
1182
///
1183
/// Returns [`None`] if [anonymous], [primitive],
1184
/// or a [`ReflectTypePath::Internal`] without a custom path.
1185
///
1186
/// [primitive]: ReflectTypePath::Primitive
1187
/// [anonymous]: ReflectTypePath::Anonymous
1188
pub fn get_path(&self) -> Option<&Path> {
1189
match self {
1190
Self::Internal { custom_path, .. } => custom_path.as_ref(),
1191
Self::External {
1192
path, custom_path, ..
1193
} => Some(custom_path.as_ref().unwrap_or(path)),
1194
_ => None,
1195
}
1196
}
1197
1198
/// Returns whether this [internal] or [external] path has a custom path.
1199
///
1200
/// [internal]: ReflectTypePath::Internal
1201
/// [external]: ReflectTypePath::External
1202
pub fn has_custom_path(&self) -> bool {
1203
match self {
1204
Self::Internal { custom_path, .. } | Self::External { custom_path, .. } => {
1205
custom_path.is_some()
1206
}
1207
_ => false,
1208
}
1209
}
1210
1211
/// Returns a [`StringExpr`] representing the name of the type's crate.
1212
///
1213
/// Returns [`None`] if the type is [primitive] or [anonymous].
1214
///
1215
/// For non-customized [internal] paths this is created from [`module_path`].
1216
///
1217
/// For `Option<PhantomData>`, this is `"core"`.
1218
///
1219
/// [primitive]: ReflectTypePath::Primitive
1220
/// [anonymous]: ReflectTypePath::Anonymous
1221
/// [internal]: ReflectTypePath::Internal
1222
pub fn crate_name(&self) -> Option<StringExpr> {
1223
if let Some(path) = self.get_path() {
1224
let crate_name = &path.segments.first().unwrap().ident;
1225
return Some(StringExpr::from(crate_name));
1226
}
1227
1228
match self {
1229
Self::Internal { .. } => Some(StringExpr::Borrowed(quote! {
1230
::core::module_path!()
1231
.split(':')
1232
.next()
1233
.unwrap()
1234
})),
1235
Self::External { .. } => unreachable!(),
1236
_ => None,
1237
}
1238
}
1239
1240
/// Combines type generics and const generics into one [`StringExpr`].
1241
///
1242
/// This string can be used with a `GenericTypePathCell` in a `TypePath` implementation.
1243
///
1244
/// The `ty_generic_fn` param maps [`TypeParam`]s to [`StringExpr`]s.
1245
fn reduce_generics(
1246
generics: &Generics,
1247
mut ty_generic_fn: impl FnMut(&TypeParam) -> StringExpr,
1248
bevy_reflect_path: &Path,
1249
) -> StringExpr {
1250
let mut params = generics.params.iter().filter_map(|param| match param {
1251
GenericParam::Type(type_param) => Some(ty_generic_fn(type_param)),
1252
GenericParam::Const(const_param) => {
1253
let ident = &const_param.ident;
1254
let ty = &const_param.ty;
1255
1256
Some(StringExpr::Owned(quote! {
1257
<#ty as #bevy_reflect_path::__macro_exports::alloc_utils::ToString>::to_string(&#ident)
1258
}))
1259
}
1260
GenericParam::Lifetime(_) => None,
1261
});
1262
1263
params
1264
.next()
1265
.into_iter()
1266
.chain(params.flat_map(|x| [StringExpr::from_str(", "), x]))
1267
.collect()
1268
}
1269
1270
/// Returns a [`StringExpr`] representing the "type path" of the type.
1271
///
1272
/// For `Option<PhantomData>`, this is `"std::option::Option<std::marker::PhantomData>"`.
1273
pub fn long_type_path(&self, bevy_reflect_path: &Path) -> StringExpr {
1274
match self {
1275
Self::Primitive(ident) => StringExpr::from(ident),
1276
Self::Anonymous { long_type_path, .. } => long_type_path.clone(),
1277
Self::Internal { generics, .. } | Self::External { generics, .. } => {
1278
let ident = self.type_ident().unwrap();
1279
let module_path = self.module_path().unwrap();
1280
1281
if self.impl_is_generic() {
1282
let generics = ReflectTypePath::reduce_generics(
1283
generics,
1284
|TypeParam { ident, .. }| {
1285
StringExpr::Borrowed(quote! {
1286
<#ident as #bevy_reflect_path::TypePath>::type_path()
1287
})
1288
},
1289
bevy_reflect_path,
1290
);
1291
1292
StringExpr::from_iter([
1293
module_path,
1294
StringExpr::from_str("::"),
1295
ident,
1296
StringExpr::from_str("<"),
1297
generics,
1298
StringExpr::from_str(">"),
1299
])
1300
} else {
1301
StringExpr::from_iter([module_path, StringExpr::from_str("::"), ident])
1302
}
1303
}
1304
}
1305
}
1306
1307
/// Returns a [`StringExpr`] representing the "short path" of the type.
1308
///
1309
/// For `Option<PhantomData>`, this is `"Option<PhantomData>"`.
1310
pub fn short_type_path(&self, bevy_reflect_path: &Path) -> StringExpr {
1311
match self {
1312
Self::Anonymous {
1313
short_type_path, ..
1314
} => short_type_path.clone(),
1315
Self::Primitive(ident) => StringExpr::from(ident),
1316
Self::External { generics, .. } | Self::Internal { generics, .. } => {
1317
let ident = self.type_ident().unwrap();
1318
1319
if self.impl_is_generic() {
1320
let generics = ReflectTypePath::reduce_generics(
1321
generics,
1322
|TypeParam { ident, .. }| {
1323
StringExpr::Borrowed(quote! {
1324
<#ident as #bevy_reflect_path::TypePath>::short_type_path()
1325
})
1326
},
1327
bevy_reflect_path,
1328
);
1329
1330
StringExpr::from_iter([
1331
ident,
1332
StringExpr::from_str("<"),
1333
generics,
1334
StringExpr::from_str(">"),
1335
])
1336
} else {
1337
ident
1338
}
1339
}
1340
}
1341
}
1342
1343
/// Returns a [`StringExpr`] representing the path to the module
1344
/// that the type is in.
1345
///
1346
/// Returns [`None`] if the type is [primitive] or [anonymous].
1347
///
1348
/// For non-customized [internal] paths this is created from [`module_path`].
1349
///
1350
/// For `Option<PhantomData>`, this is `"std::option"`.
1351
///
1352
/// [primitive]: ReflectTypePath::Primitive
1353
/// [anonymous]: ReflectTypePath::Anonymous
1354
/// [internal]: ReflectTypePath::Internal
1355
pub fn module_path(&self) -> Option<StringExpr> {
1356
if let Some(path) = self.get_path() {
1357
let path_string = path
1358
.segments
1359
.pairs()
1360
.take(path.segments.len() - 1)
1361
.map(|pair| pair.value().ident.to_string())
1362
.reduce(|path, ident| path + "::" + &ident)
1363
.unwrap();
1364
1365
let path_lit = LitStr::new(&path_string, path.span());
1366
return Some(StringExpr::from_lit(&path_lit));
1367
}
1368
1369
match self {
1370
Self::Internal { .. } => Some(StringExpr::Const(quote! {
1371
::core::module_path!()
1372
})),
1373
Self::External { .. } => unreachable!(),
1374
_ => None,
1375
}
1376
}
1377
1378
/// Returns a [`StringExpr`] representing the type's final ident.
1379
///
1380
/// Returns [`None`] if the type is [anonymous].
1381
///
1382
/// This is not necessarily a valid qualified path to the type.
1383
///
1384
/// For `Option<PhantomData>`, this is `"Option"`.
1385
///
1386
/// [anonymous]: ReflectTypePath::Anonymous
1387
pub fn type_ident(&self) -> Option<StringExpr> {
1388
self.get_ident().map(StringExpr::from)
1389
}
1390
1391
/// Returns the true type regardless of whether a custom path is specified.
1392
///
1393
/// To get the custom path if there is one, use [`Self::get_path`].
1394
///
1395
/// For example, the type `Foo<T: Debug>` would return `Foo<T>`.
1396
pub fn true_type(&self) -> proc_macro2::TokenStream {
1397
match self {
1398
Self::Primitive(ident) => quote!(#ident),
1399
Self::Internal {
1400
ident, generics, ..
1401
} => {
1402
let (_, ty_generics, _) = generics.split_for_impl();
1403
quote!(#ident #ty_generics)
1404
}
1405
Self::External { path, generics, .. } => {
1406
let (_, ty_generics, _) = generics.split_for_impl();
1407
quote!(#path #ty_generics)
1408
}
1409
Self::Anonymous { qualified_type, .. } => qualified_type.to_token_stream(),
1410
}
1411
}
1412
}
1413
1414
impl<'a> ToTokens for ReflectTypePath<'a> {
1415
fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
1416
match self {
1417
Self::Internal { ident, .. } | Self::Primitive(ident) => ident.to_tokens(tokens),
1418
Self::External { path, .. } => path.to_tokens(tokens),
1419
Self::Anonymous { qualified_type, .. } => qualified_type.to_tokens(tokens),
1420
}
1421
}
1422
}
1423
1424