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