bevy_reflect_derive/impls/
typed.rs1use crate::{
2 derive_data::{ReflectMeta, ReflectTypePath},
3 string_expr::StringExpr,
4 where_clause_options::WhereClauseOptions,
5};
6use bevy_macro_utils::fq_std::FQOption;
7use proc_macro2::TokenStream;
8use quote::{quote, ToTokens};
9
10fn static_type_cell(
12 meta: &ReflectMeta,
13 property: TypedProperty,
14 generator: TokenStream,
15) -> TokenStream {
16 let bevy_reflect_path = meta.bevy_reflect_path();
17 if meta.type_path().impl_is_generic() {
18 let cell_type = match property {
19 TypedProperty::TypePath => quote!(GenericTypePathCell),
20 TypedProperty::TypeInfo => quote!(GenericTypeInfoCell),
21 };
22
23 quote! {
24 static CELL: #bevy_reflect_path::utility::#cell_type = #bevy_reflect_path::utility::#cell_type::new();
25 CELL.get_or_insert::<Self, _>(|| {
26 #generator
27 })
28 }
29 } else {
30 let cell_type = match property {
31 TypedProperty::TypePath => unreachable!(
32 "Cannot have a non-generic type path cell. Use string literals and core::concat instead."
33 ),
34 TypedProperty::TypeInfo => quote!(NonGenericTypeInfoCell),
35 };
36
37 quote! {
38 static CELL: #bevy_reflect_path::utility::#cell_type = #bevy_reflect_path::utility::#cell_type::new();
39 CELL.get_or_set(|| {
40 #generator
41 })
42 }
43 }
44}
45
46#[derive(Clone, Copy)]
47pub(crate) enum TypedProperty {
48 TypeInfo,
49 TypePath,
50}
51
52pub(crate) fn impl_type_path(meta: &ReflectMeta) -> TokenStream {
53 let where_clause_options = WhereClauseOptions::new(meta);
54
55 if !meta.attrs().type_path_attrs().should_auto_derive() {
56 return TokenStream::new();
57 }
58
59 let type_path = meta.type_path();
60 let bevy_reflect_path = meta.bevy_reflect_path();
61
62 let (long_type_path, short_type_path) = if type_path.impl_is_generic() {
63 let long_path_cell = static_type_cell(
64 meta,
65 TypedProperty::TypePath,
66 type_path.long_type_path(bevy_reflect_path).into_owned(),
67 );
68 let short_path_cell = static_type_cell(
69 meta,
70 TypedProperty::TypePath,
71 type_path.short_type_path(bevy_reflect_path).into_owned(),
72 );
73 (
74 long_path_cell.to_token_stream(),
75 short_path_cell.to_token_stream(),
76 )
77 } else {
78 (
79 type_path.long_type_path(bevy_reflect_path).into_borrowed(),
80 type_path.short_type_path(bevy_reflect_path).into_borrowed(),
81 )
82 };
83
84 let type_ident = wrap_in_option(type_path.type_ident().map(StringExpr::into_borrowed));
85 let module_path = wrap_in_option(type_path.module_path().map(StringExpr::into_borrowed));
86 let crate_name = wrap_in_option(type_path.crate_name().map(StringExpr::into_borrowed));
87
88 let primitive_assert = if let ReflectTypePath::Primitive(_) = type_path {
89 Some(quote! {
90 const _: () = {
91 mod private_scope {
92 type AssertIsPrimitive = #type_path;
94 }
95 };
96 })
97 } else {
98 None
99 };
100
101 let (impl_generics, ty_generics, where_clause) = type_path.generics().split_for_impl();
102
103 let where_reflect_clause = where_clause_options.extend_where_clause(where_clause);
105
106 quote! {
107 #primitive_assert
108
109 impl #impl_generics #bevy_reflect_path::TypePath for #type_path #ty_generics #where_reflect_clause {
110 fn type_path() -> &'static str {
111 #long_type_path
112 }
113
114 fn short_type_path() -> &'static str {
115 #short_type_path
116 }
117
118 fn type_ident() -> Option<&'static str> {
119 #type_ident
120 }
121
122 fn crate_name() -> Option<&'static str> {
123 #crate_name
124 }
125
126 fn module_path() -> Option<&'static str> {
127 #module_path
128 }
129 }
130 }
131}
132
133pub(crate) fn impl_typed(
134 where_clause_options: &WhereClauseOptions,
135 type_info_generator: TokenStream,
136) -> TokenStream {
137 let meta = where_clause_options.meta();
138 let type_path = meta.type_path();
139 let bevy_reflect_path = meta.bevy_reflect_path();
140
141 let type_info_cell = static_type_cell(meta, TypedProperty::TypeInfo, type_info_generator);
142
143 let (impl_generics, ty_generics, where_clause) = type_path.generics().split_for_impl();
144
145 let where_reflect_clause = where_clause_options.extend_where_clause(where_clause);
146
147 quote! {
148 impl #impl_generics #bevy_reflect_path::Typed for #type_path #ty_generics #where_reflect_clause {
149 #[inline]
150 fn type_info() -> &'static #bevy_reflect_path::TypeInfo {
151 #type_info_cell
152 }
153 }
154 }
155}
156
157fn wrap_in_option(tokens: Option<TokenStream>) -> TokenStream {
159 match tokens {
160 Some(tokens) => quote! {
161 #FQOption::Some(#tokens)
162 },
163 None => quote! {
164 #FQOption::None
165 },
166 }
167}