bevy_reflect_derive/
derive_data.rs

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