bevy_reflect_derive/
remote.rs

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
21/// Generates the remote wrapper type and implements all the necessary traits.
22pub(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
103/// Generates the remote wrapper type.
104///
105/// # Example
106///
107/// If the supplied remote type is `Bar<T>`, then the wrapper type— named `Foo<T>`— would look like:
108///
109/// ```
110/// # struct Bar<T>(T);
111///
112/// #[repr(transparent)]
113/// struct Foo<T>(Bar<T>);
114/// ```
115fn 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
133/// Generates the implementation of the `ReflectRemote` trait for the given derive data and remote type.
134///
135/// # Note to Developers
136///
137/// The `ReflectRemote` trait could likely be made with default method implementations.
138/// However, this makes it really easy for a user to accidentally implement this trait in an unsafe way.
139/// To prevent this, we instead generate the implementation through a macro using this function.
140fn 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        // SAFE: The generated wrapper type is guaranteed to be valid and repr(transparent) over the remote type.
153        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                // SAFE: The wrapper type should be repr(transparent) over the remote type
165                unsafe {
166                    // Unfortunately, we have to use `transmute_copy` to avoid a compiler error:
167                    // ```
168                    // error[E0512]: cannot transmute between types of different sizes, or dependently-sized types
169                    // |
170                    // |                 core::mem::transmute::<A, B>(a)
171                    // |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^
172                    // |
173                    // = note: source type: `A` (this type does not have a fixed size)
174                    // = note: target type: `B` (this type does not have a fixed size)
175                    // ```
176                    ::core::mem::transmute_copy::<Self, Self::Remote>(
177                        // `ManuallyDrop` is used to prevent double-dropping `self`
178                        &::core::mem::ManuallyDrop::new(self)
179                    )
180                }
181            }
182
183            fn as_wrapper(remote: &Self::Remote) -> &Self {
184                // SAFE: The wrapper type should be repr(transparent) over the remote type
185                unsafe { ::core::mem::transmute::<&Self::Remote, &Self>(remote) }
186            }
187            fn as_wrapper_mut(remote: &mut Self::Remote) -> &mut Self {
188                // SAFE: The wrapper type should be repr(transparent) over the remote type
189                unsafe { ::core::mem::transmute::<&mut Self::Remote, &mut Self>(remote) }
190            }
191            fn into_wrapper(remote: Self::Remote) -> Self
192            {
193                // SAFE: The wrapper type should be repr(transparent) over the remote type
194                unsafe {
195                    // Unfortunately, we have to use `transmute_copy` to avoid a compiler error:
196                    // ```
197                    // error[E0512]: cannot transmute between types of different sizes, or dependently-sized types
198                    // |
199                    // |                 core::mem::transmute::<A, B>(a)
200                    // |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^
201                    // |
202                    // = note: source type: `A` (this type does not have a fixed size)
203                    // = note: target type: `B` (this type does not have a fixed size)
204                    // ```
205                    ::core::mem::transmute_copy::<Self::Remote, Self>(
206                        // `ManuallyDrop` is used to prevent double-dropping `self`
207                        &::core::mem::ManuallyDrop::new(remote)
208                    )
209                }
210            }
211        }
212    }
213}
214
215/// Generates compile-time assertions for remote fields.
216///
217/// This prevents types from using an invalid remote type.
218/// this works by generating a struct, `RemoteFieldAssertions`, with methods that
219/// will result in compile-time failure if types are mismatched.
220/// The output of this function is best placed within an anonymous context to maintain hygiene.
221///
222/// # Example
223///
224/// The following would fail to compile due to an incorrect `#[reflect(remote = ...)]` value.
225///
226/// ```ignore
227/// mod external_crate {
228///     pub struct TheirFoo(pub u32);
229///     pub struct TheirBar(pub i32);
230/// }
231///
232/// #[reflect_remote(external_crate::TheirFoo)]
233/// struct MyFoo(pub u32);
234/// #[reflect_remote(external_crate::TheirBar)]
235/// struct MyBar(pub i32);
236///
237/// #[derive(Reflect)]
238/// struct MyStruct {
239///   #[reflect(remote = MyBar)] // ERROR: expected type `TheirFoo` but found struct `TheirBar`
240///   foo: external_crate::TheirFoo
241/// }
242/// ```
243pub(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
338/// Generates compile-time assertions that ensure a remote wrapper definition matches up with the
339/// remote type it's wrapping.
340///
341/// Note: This currently results in "backwards" error messages like:
342///
343/// ```ignore
344/// expected: <WRAPPER_FIELD_TYPE>
345/// found: <REMOTE_FIELD_TYPE>
346/// ```
347///
348/// Ideally it would be the other way around, but there's no easy way of doing this without
349/// generating a copy of the struct/enum definition and using that as the base instead of the remote type.
350fn 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            // No assertions needed since there are no fields to check
415            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
433/// Creates a span located around the given one, but resolves to the assertion's context.
434///
435/// This should allow the compiler to point back to the line and column in the user's code,
436/// while still attributing the error to the macro.
437fn create_assertion_span(span: Span) -> Span {
438    Span::call_site().located_at(span)
439}
440
441/// A reflected type's remote type.
442///
443/// This is a wrapper around [`TypePath`] that allows it to be paired with other remote-specific logic.
444#[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    /// Returns the [type path](TypePath) of this remote type.
455    pub fn type_path(&self) -> &'a TypePath {
456        self.path
457    }
458
459    /// Attempts to convert the [type path](TypePath) of this remote type into an [expression path](ExprPath).
460    ///
461    /// For example, this would convert `foo::Bar<T>` into `foo::Bar::<T>` to be used as part of an expression.
462    ///
463    /// This will return an error for types that are parenthesized, such as in `Fn() -> Foo`.
464    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
489/// Metadata from the arguments defined in the `reflect_remote` attribute.
490///
491/// The syntax for the arguments is: `#[reflect_remote(REMOTE_TYPE_PATH)]`.
492struct 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}