bevy_reflect_derive/
derive_data.rs

1use core::fmt;
2use indexmap::IndexSet;
3use proc_macro2::Span;
4
5use 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};
15use bevy_macro_utils::ResultSifter;
16use quote::{format_ident, quote, ToTokens};
17use syn::token::Comma;
18
19use crate::enum_utility::{EnumVariantOutputData, ReflectCloneVariantBuilder, VariantBuilder};
20use crate::field_attributes::CloneBehavior;
21use crate::generics::generate_generics;
22use bevy_macro_utils::fq_std::{FQClone, FQOption, FQResult};
23use 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
29pub(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/// ```
50pub(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/// ```
77pub(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/// ```
96pub(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)]
103pub(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.
123pub(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
135pub(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)]
143pub(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)]
154pub(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)]
162pub(crate) struct ReflectProvenance {
163    pub source: ReflectImplSource,
164    pub trait_: ReflectTraitToImpl,
165}
166
167impl 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
183impl<'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
422impl<'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
498impl<'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
582impl<'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
812impl<'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
962impl<'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/// ```
1070pub(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
1106impl<'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
1405impl<'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}