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 const _: () = {
111 extern crate alloc;
112
113 use alloc::string::ToString;
114
115 impl #impl_generics #bevy_reflect_path::TypePath for #type_path #ty_generics #where_reflect_clause {
116 fn type_path() -> &'static str {
117 #long_type_path
118 }
119
120 fn short_type_path() -> &'static str {
121 #short_type_path
122 }
123
124 fn type_ident() -> Option<&'static str> {
125 #type_ident
126 }
127
128 fn crate_name() -> Option<&'static str> {
129 #crate_name
130 }
131
132 fn module_path() -> Option<&'static str> {
133 #module_path
134 }
135 }
136 };
137 }
138}
139
140pub(crate) fn impl_typed(
141 meta: &ReflectMeta,
142 where_clause_options: &WhereClauseOptions,
143 type_info_generator: TokenStream,
144) -> TokenStream {
145 let type_path = meta.type_path();
146 let bevy_reflect_path = meta.bevy_reflect_path();
147
148 let type_info_cell = static_type_cell(meta, TypedProperty::TypeInfo, type_info_generator);
149
150 let (impl_generics, ty_generics, where_clause) = type_path.generics().split_for_impl();
151
152 let where_reflect_clause = where_clause_options.extend_where_clause(where_clause);
153
154 quote! {
155 impl #impl_generics #bevy_reflect_path::Typed for #type_path #ty_generics #where_reflect_clause {
156 #[inline]
157 fn type_info() -> &'static #bevy_reflect_path::TypeInfo {
158 #type_info_cell
159 }
160 }
161 }
162}
163
164fn wrap_in_option(tokens: Option<TokenStream>) -> TokenStream {
166 match tokens {
167 Some(tokens) => quote! {
168 #FQOption::Some(#tokens)
169 },
170 None => quote! {
171 #FQOption::None
172 },
173 }
174}