1use crate::{
2 derive_data::{ReflectImplSource, ReflectProvenance, ReflectTraitToImpl},
3 from_reflect,
4 ident::ident_or_index,
5 impls,
6 impls::impl_assertions,
7 ReflectDerive, REFLECT_ATTRIBUTE_NAME,
8};
9use bevy_macro_utils::fq_std::FQOption;
10use proc_macro::TokenStream;
11use proc_macro2::{Ident, Span};
12use quote::{format_ident, quote, quote_spanned};
13use syn::{
14 parse::{Parse, ParseStream},
15 parse_macro_input,
16 spanned::Spanned,
17 token::PathSep,
18 DeriveInput, ExprPath, Generics, Member, PathArguments, Type, TypePath,
19};
20
21pub(crate) fn reflect_remote(args: TokenStream, input: TokenStream) -> TokenStream {
23 let remote_args = match syn::parse::<RemoteArgs>(args) {
24 Ok(path) => path,
25 Err(err) => return err.to_compile_error().into(),
26 };
27
28 let remote_ty = remote_args.remote_ty;
29
30 let ast = parse_macro_input!(input as DeriveInput);
31 let wrapper_definition = generate_remote_wrapper(&ast, &remote_ty);
32
33 let mut derive_data = match ReflectDerive::from_input(
34 &ast,
35 ReflectProvenance {
36 source: ReflectImplSource::RemoteReflect,
37 trait_: ReflectTraitToImpl::Reflect,
38 },
39 ) {
40 Ok(data) => data,
41 Err(err) => return err.into_compile_error().into(),
42 };
43
44 derive_data.set_remote(Some(RemoteType::new(&remote_ty)));
45
46 let assertions = impl_assertions(&derive_data);
47 let definition_assertions = generate_remote_definition_assertions(&derive_data);
48
49 let reflect_remote_impl = impl_reflect_remote(&derive_data, &remote_ty);
50
51 let (reflect_impls, from_reflect_impl) = match derive_data {
52 ReflectDerive::Struct(struct_data) | ReflectDerive::UnitStruct(struct_data) => (
53 impls::impl_struct(&struct_data),
54 if struct_data.meta().from_reflect().should_auto_derive() {
55 Some(from_reflect::impl_struct(&struct_data))
56 } else {
57 None
58 },
59 ),
60 ReflectDerive::TupleStruct(struct_data) => (
61 impls::impl_tuple_struct(&struct_data),
62 if struct_data.meta().from_reflect().should_auto_derive() {
63 Some(from_reflect::impl_tuple_struct(&struct_data))
64 } else {
65 None
66 },
67 ),
68 ReflectDerive::Enum(enum_data) => (
69 impls::impl_enum(&enum_data),
70 if enum_data.meta().from_reflect().should_auto_derive() {
71 Some(from_reflect::impl_enum(&enum_data))
72 } else {
73 None
74 },
75 ),
76 ReflectDerive::Opaque(meta) => (
77 impls::impl_opaque(&meta),
78 if meta.from_reflect().should_auto_derive() {
79 Some(from_reflect::impl_opaque(&meta))
80 } else {
81 None
82 },
83 ),
84 };
85
86 TokenStream::from(quote! {
87 #wrapper_definition
88
89 const _: () = {
90 #reflect_remote_impl
91
92 #reflect_impls
93
94 #from_reflect_impl
95
96 #definition_assertions
97
98 #assertions
99 };
100 })
101}
102
103fn generate_remote_wrapper(input: &DeriveInput, remote_ty: &TypePath) -> proc_macro2::TokenStream {
116 let ident = &input.ident;
117 let vis = &input.vis;
118 let ty_generics = &input.generics;
119 let where_clause = &input.generics.where_clause;
120 let attrs = input
121 .attrs
122 .iter()
123 .filter(|attr| !attr.path().is_ident(REFLECT_ATTRIBUTE_NAME));
124
125 quote! {
126 #(#attrs)*
127 #[repr(transparent)]
128 #[doc(hidden)]
129 #vis struct #ident #ty_generics (pub #remote_ty) #where_clause;
130 }
131}
132
133fn impl_reflect_remote(input: &ReflectDerive, remote_ty: &TypePath) -> proc_macro2::TokenStream {
141 let bevy_reflect_path = input.meta().bevy_reflect_path();
142
143 let type_path = input.meta().type_path();
144 let (impl_generics, ty_generics, where_clause) =
145 input.meta().type_path().generics().split_for_impl();
146
147 let where_reflect_clause = input
148 .where_clause_options()
149 .extend_where_clause(where_clause);
150
151 quote! {
152 impl #impl_generics #bevy_reflect_path::ReflectRemote for #type_path #ty_generics #where_reflect_clause {
154 type Remote = #remote_ty;
155
156 fn as_remote(&self) -> &Self::Remote {
157 &self.0
158 }
159 fn as_remote_mut(&mut self) -> &mut Self::Remote {
160 &mut self.0
161 }
162 fn into_remote(self) -> Self::Remote
163 {
164 unsafe {
166 ::core::mem::transmute_copy::<Self, Self::Remote>(
177 &::core::mem::ManuallyDrop::new(self)
179 )
180 }
181 }
182
183 fn as_wrapper(remote: &Self::Remote) -> &Self {
184 unsafe { ::core::mem::transmute::<&Self::Remote, &Self>(remote) }
186 }
187 fn as_wrapper_mut(remote: &mut Self::Remote) -> &mut Self {
188 unsafe { ::core::mem::transmute::<&mut Self::Remote, &mut Self>(remote) }
190 }
191 fn into_wrapper(remote: Self::Remote) -> Self
192 {
193 unsafe {
195 ::core::mem::transmute_copy::<Self::Remote, Self>(
206 &::core::mem::ManuallyDrop::new(remote)
208 )
209 }
210 }
211 }
212 }
213}
214
215pub(crate) fn generate_remote_assertions(
244 derive_data: &ReflectDerive,
245) -> Option<proc_macro2::TokenStream> {
246 struct RemoteAssertionData<'a> {
247 ident: Member,
248 variant: Option<&'a Ident>,
249 ty: &'a Type,
250 generics: &'a Generics,
251 remote_ty: &'a Type,
252 }
253
254 let bevy_reflect_path = derive_data.meta().bevy_reflect_path();
255
256 let fields: Box<dyn Iterator<Item = RemoteAssertionData>> = match derive_data {
257 ReflectDerive::Struct(data)
258 | ReflectDerive::TupleStruct(data)
259 | ReflectDerive::UnitStruct(data) => Box::new(data.active_fields().filter_map(|field| {
260 field
261 .attrs
262 .remote
263 .as_ref()
264 .map(|remote_ty| RemoteAssertionData {
265 ident: ident_or_index(field.data.ident.as_ref(), field.declaration_index),
266 variant: None,
267 ty: &field.data.ty,
268 generics: data.meta().type_path().generics(),
269 remote_ty,
270 })
271 })),
272 ReflectDerive::Enum(data) => Box::new(data.variants().iter().flat_map(|variant| {
273 variant.active_fields().filter_map(|field| {
274 field
275 .attrs
276 .remote
277 .as_ref()
278 .map(|remote_ty| RemoteAssertionData {
279 ident: ident_or_index(field.data.ident.as_ref(), field.declaration_index),
280 variant: Some(&variant.data.ident),
281 ty: &field.data.ty,
282 generics: data.meta().type_path().generics(),
283 remote_ty,
284 })
285 })
286 })),
287
288 _ => return None,
289 };
290
291 let assertions = fields
292 .map(move |field| {
293 let ident = if let Some(variant) = field.variant {
294 format_ident!("{}__{}", variant, field.ident)
295 } else {
296 match field.ident {
297 Member::Named(ident) => ident,
298 Member::Unnamed(index) => format_ident!("field_{}", index),
299 }
300 };
301 let (impl_generics, _, where_clause) = field.generics.split_for_impl();
302
303 let where_reflect_clause = derive_data
304 .where_clause_options()
305 .extend_where_clause(where_clause);
306
307 let ty = &field.ty;
308 let remote_ty = field.remote_ty;
309 let assertion_ident = format_ident!("assert__{}__is_valid_remote", ident);
310
311 let span = create_assertion_span(remote_ty.span());
312
313 quote_spanned! {span=>
314 #[allow(non_snake_case)]
315 #[allow(clippy::multiple_bound_locations)]
316 fn #assertion_ident #impl_generics () #where_reflect_clause {
317 let _: <#remote_ty as #bevy_reflect_path::ReflectRemote>::Remote = (|| -> #FQOption<#ty> {
318 None
319 })().unwrap();
320 }
321 }
322 })
323 .collect::<proc_macro2::TokenStream>();
324
325 if assertions.is_empty() {
326 None
327 } else {
328 Some(quote! {
329 struct RemoteFieldAssertions;
330
331 impl RemoteFieldAssertions {
332 #assertions
333 }
334 })
335 }
336}
337
338fn generate_remote_definition_assertions(derive_data: &ReflectDerive) -> proc_macro2::TokenStream {
351 let meta = derive_data.meta();
352 let self_ident = format_ident!("__remote__");
353 let self_ty = derive_data.remote_ty().unwrap().type_path();
354 let self_expr_path = derive_data.remote_ty().unwrap().as_expr_path().unwrap();
355 let (impl_generics, _, where_clause) = meta.type_path().generics().split_for_impl();
356
357 let where_reflect_clause = derive_data
358 .where_clause_options()
359 .extend_where_clause(where_clause);
360
361 let assertions = match derive_data {
362 ReflectDerive::Struct(data)
363 | ReflectDerive::TupleStruct(data)
364 | ReflectDerive::UnitStruct(data) => {
365 let mut output = proc_macro2::TokenStream::new();
366
367 for field in data.fields() {
368 let field_member =
369 ident_or_index(field.data.ident.as_ref(), field.declaration_index);
370 let field_ty = &field.data.ty;
371 let span = create_assertion_span(field_ty.span());
372
373 output.extend(quote_spanned! {span=>
374 #self_ident.#field_member = (|| -> #FQOption<#field_ty> {None})().unwrap();
375 });
376 }
377
378 output
379 }
380 ReflectDerive::Enum(data) => {
381 let variants = data.variants().iter().map(|variant| {
382 let ident = &variant.data.ident;
383
384 let mut output = proc_macro2::TokenStream::new();
385
386 if variant.fields().is_empty() {
387 return quote!(#self_expr_path::#ident => {});
388 }
389
390 for field in variant.fields() {
391 let field_member =
392 ident_or_index(field.data.ident.as_ref(), field.declaration_index);
393 let field_ident = format_ident!("field_{}", field_member);
394 let field_ty = &field.data.ty;
395 let span = create_assertion_span(field_ty.span());
396
397 output.extend(quote_spanned! {span=>
398 #self_expr_path::#ident {#field_member: mut #field_ident, ..} => {
399 #field_ident = (|| -> #FQOption<#field_ty> {None})().unwrap();
400 }
401 });
402 }
403
404 output
405 });
406
407 quote! {
408 match #self_ident {
409 #(#variants)*
410 }
411 }
412 }
413 ReflectDerive::Opaque(_) => {
414 proc_macro2::TokenStream::new()
416 }
417 };
418
419 quote! {
420 const _: () = {
421 #[allow(non_snake_case)]
422 #[allow(unused_variables)]
423 #[allow(unused_assignments)]
424 #[allow(unreachable_patterns)]
425 #[allow(clippy::multiple_bound_locations)]
426 fn assert_wrapper_definition_matches_remote_type #impl_generics (mut #self_ident: #self_ty) #where_reflect_clause {
427 #assertions
428 }
429 };
430 }
431}
432
433fn create_assertion_span(span: Span) -> Span {
438 Span::call_site().located_at(span)
439}
440
441#[derive(Copy, Clone)]
445pub(crate) struct RemoteType<'a> {
446 path: &'a TypePath,
447}
448
449impl<'a> RemoteType<'a> {
450 pub fn new(path: &'a TypePath) -> Self {
451 Self { path }
452 }
453
454 pub fn type_path(&self) -> &'a TypePath {
456 self.path
457 }
458
459 pub fn as_expr_path(&self) -> Result<ExprPath, syn::Error> {
465 let mut expr_path = self.path.clone();
466 if let Some(segment) = expr_path.path.segments.last_mut() {
467 match &mut segment.arguments {
468 PathArguments::None => {}
469 PathArguments::AngleBracketed(arg) => {
470 arg.colon2_token = Some(PathSep::default());
471 }
472 PathArguments::Parenthesized(arg) => {
473 return Err(syn::Error::new(
474 arg.span(),
475 "cannot use parenthesized type as remote type",
476 ))
477 }
478 }
479 }
480
481 Ok(ExprPath {
482 path: expr_path.path,
483 qself: expr_path.qself,
484 attrs: Vec::new(),
485 })
486 }
487}
488
489struct RemoteArgs {
493 remote_ty: TypePath,
494}
495
496impl Parse for RemoteArgs {
497 fn parse(input: ParseStream) -> syn::Result<Self> {
498 Ok(Self {
499 remote_ty: input.parse()?,
500 })
501 }
502}