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