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