bevy_reflect_derive/
generics.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
use crate::derive_data::ReflectMeta;
use proc_macro2::TokenStream;
use quote::quote;
use syn::punctuated::Punctuated;
use syn::{GenericParam, Token};

/// Creates a `TokenStream` for generating an expression that creates a `Generics` instance.
///
/// Returns `None` if `Generics` cannot or should not be generated.
pub(crate) fn generate_generics(meta: &ReflectMeta) -> Option<TokenStream> {
    if !meta.attrs().type_path_attrs().should_auto_derive() {
        // Cannot verify that all generic parameters implement `TypePath`
        return None;
    }

    let bevy_reflect_path = meta.bevy_reflect_path();

    let generics = meta
        .type_path()
        .generics()
        .params
        .iter()
        .filter_map(|param| match param {
            GenericParam::Type(ty_param) => {
                let ident = &ty_param.ident;
                let name = ident.to_string();
                let with_default = ty_param
                    .default
                    .as_ref()
                    .map(|default_ty| quote!(.with_default::<#default_ty>()));

                Some(quote! {
                    #bevy_reflect_path::GenericInfo::Type(
                        #bevy_reflect_path::TypeParamInfo::new::<#ident>(
                            ::std::borrow::Cow::Borrowed(#name),
                        )
                        #with_default
                    )
                })
            }
            GenericParam::Const(const_param) => {
                let ty = &const_param.ty;
                let name = const_param.ident.to_string();
                let with_default = const_param.default.as_ref().map(|default| {
                    // We add the `as #ty` to ensure that the correct type is inferred.
                    quote!(.with_default(#default as #ty))
                });

                Some(quote! {
                    #[allow(
                        clippy::unnecessary_cast,
                        reason = "reflection requires an explicit type hint for const generics"
                    )]
                    #bevy_reflect_path::GenericInfo::Const(
                        #bevy_reflect_path::ConstParamInfo::new::<#ty>(
                            ::std::borrow::Cow::Borrowed(#name),
                        )
                        #with_default
                    )
                })
            }
            GenericParam::Lifetime(_) => None,
        })
        .collect::<Punctuated<_, Token![,]>>();

    if generics.is_empty() {
        // No generics to generate
        return None;
    }

    Some(quote!(#bevy_reflect_path::Generics::from_iter([ #generics ])))
}