bevy_reflect_derive/
generics.rs

1use crate::derive_data::ReflectMeta;
2use proc_macro2::TokenStream;
3use quote::quote;
4use syn::punctuated::Punctuated;
5use syn::{GenericParam, Token};
6
7/// Creates a `TokenStream` for generating an expression that creates a `Generics` instance.
8///
9/// Returns `None` if `Generics` cannot or should not be generated.
10pub(crate) fn generate_generics(meta: &ReflectMeta) -> Option<TokenStream> {
11    if !meta.attrs().type_path_attrs().should_auto_derive() {
12        // Cannot verify that all generic parameters implement `TypePath`
13        return None;
14    }
15
16    let bevy_reflect_path = meta.bevy_reflect_path();
17
18    let generics = meta
19        .type_path()
20        .generics()
21        .params
22        .iter()
23        .filter_map(|param| match param {
24            GenericParam::Type(ty_param) => {
25                let ident = &ty_param.ident;
26                let name = ident.to_string();
27                let with_default = ty_param
28                    .default
29                    .as_ref()
30                    .map(|default_ty| quote!(.with_default::<#default_ty>()));
31
32                Some(quote! {
33                    #bevy_reflect_path::GenericInfo::Type(
34                        #bevy_reflect_path::TypeParamInfo::new::<#ident>(
35                            #bevy_reflect_path::__macro_exports::alloc_utils::Cow::Borrowed(#name),
36                        )
37                        #with_default
38                    )
39                })
40            }
41            GenericParam::Const(const_param) => {
42                let ty = &const_param.ty;
43                let name = const_param.ident.to_string();
44                let with_default = const_param.default.as_ref().map(|default| {
45                    // We add the `as #ty` to ensure that the correct type is inferred.
46                    quote!(.with_default(#default as #ty))
47                });
48
49                Some(quote! {
50                    #[allow(
51                        clippy::unnecessary_cast,
52                        reason = "reflection requires an explicit type hint for const generics"
53                    )]
54                    #bevy_reflect_path::GenericInfo::Const(
55                        #bevy_reflect_path::ConstParamInfo::new::<#ty>(
56                            #bevy_reflect_path::__macro_exports::alloc_utils::Cow::Borrowed(#name),
57                        )
58                        #with_default
59                    )
60                })
61            }
62            GenericParam::Lifetime(_) => None,
63        })
64        .collect::<Punctuated<_, Token![,]>>();
65
66    if generics.is_empty() {
67        // No generics to generate
68        return None;
69    }
70
71    Some(quote!(#bevy_reflect_path::Generics::from_iter([ #generics ])))
72}