Skip to content

Commit 0103072

Browse files
committed
Add support for remote reflection of value types
1 parent d17ea00 commit 0103072

File tree

10 files changed

+151
-85
lines changed

10 files changed

+151
-85
lines changed

crates/bevy_reflect/derive/src/derive_data.rs

Lines changed: 23 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,8 @@ pub(crate) struct ReflectMeta<'a> {
4747
attrs: ContainerAttributes,
4848
/// The path to this type.
4949
type_path: ReflectTypePath<'a>,
50+
/// The optional remote type to use instead of the actual type.
51+
remote_ty: Option<RemoteType<'a>>,
5052
/// A cached instance of the path to the `bevy_reflect` crate.
5153
bevy_reflect_path: Path,
5254
/// The documentation for this type, if any
@@ -71,7 +73,6 @@ pub(crate) struct ReflectStruct<'a> {
7173
meta: ReflectMeta<'a>,
7274
serialization_data: Option<SerializationDataDef>,
7375
fields: Vec<StructField<'a>>,
74-
remote_ty: Option<RemoteType<'a>>,
7576
}
7677

7778
/// Enum data used by derive macros for `Reflect` and `FromReflect`.
@@ -90,7 +91,6 @@ pub(crate) struct ReflectStruct<'a> {
9091
pub(crate) struct ReflectEnum<'a> {
9192
meta: ReflectMeta<'a>,
9293
variants: Vec<EnumVariant<'a>>,
93-
remote_ty: Option<RemoteType<'a>>,
9494
}
9595

9696
/// Represents a field on a struct or tuple struct.
@@ -331,7 +331,6 @@ impl<'a> ReflectDerive<'a> {
331331
meta,
332332
serialization_data: SerializationDataDef::new(&fields)?,
333333
fields,
334-
remote_ty: None,
335334
};
336335

337336
match data.fields {
@@ -343,11 +342,7 @@ impl<'a> ReflectDerive<'a> {
343342
Data::Enum(data) => {
344343
let variants = Self::collect_enum_variants(&data.variants)?;
345344

346-
let reflect_enum = ReflectEnum {
347-
meta,
348-
variants,
349-
remote_ty: None,
350-
};
345+
let reflect_enum = ReflectEnum { meta, variants };
351346
Ok(Self::Enum(reflect_enum))
352347
}
353348
Data::Union(..) => Err(syn::Error::new(
@@ -365,23 +360,25 @@ impl<'a> ReflectDerive<'a> {
365360
pub fn set_remote(&mut self, remote_ty: Option<RemoteType<'a>>) {
366361
match self {
367362
Self::Struct(data) | Self::TupleStruct(data) | Self::UnitStruct(data) => {
368-
data.remote_ty = remote_ty;
363+
data.meta.remote_ty = remote_ty;
369364
}
370365
Self::Enum(data) => {
371-
data.remote_ty = remote_ty;
366+
data.meta.remote_ty = remote_ty;
367+
}
368+
Self::Value(meta) => {
369+
meta.remote_ty = remote_ty;
372370
}
373-
_ => panic!("cannot create a reflected value type for a remote type"),
374371
}
375372
}
376373

377374
/// Get the remote type path, if any.
378375
pub fn remote_ty(&self) -> Option<RemoteType> {
379376
match self {
380377
Self::Struct(data) | Self::TupleStruct(data) | Self::UnitStruct(data) => {
381-
data.remote_ty()
378+
data.meta.remote_ty()
382379
}
383-
Self::Enum(data) => data.remote_ty(),
384-
Self::Value(_) => None,
380+
Self::Enum(data) => data.meta.remote_ty(),
381+
Self::Value(meta) => meta.remote_ty(),
385382
}
386383
}
387384

@@ -475,6 +472,7 @@ impl<'a> ReflectMeta<'a> {
475472
Self {
476473
attrs,
477474
type_path,
475+
remote_ty: None,
478476
bevy_reflect_path: utility::get_bevy_reflect_path(),
479477
#[cfg(feature = "documentation")]
480478
docs: Default::default(),
@@ -508,6 +506,16 @@ impl<'a> ReflectMeta<'a> {
508506
&self.type_path
509507
}
510508

509+
/// Get the remote type path, if any.
510+
pub fn remote_ty(&self) -> Option<RemoteType> {
511+
self.remote_ty
512+
}
513+
514+
/// Whether this reflected type represents a remote type or not.
515+
pub fn is_remote_wrapper(&self) -> bool {
516+
self.remote_ty.is_some()
517+
}
518+
511519
/// The cached `bevy_reflect` path.
512520
pub fn bevy_reflect_path(&self) -> &Path {
513521
&self.bevy_reflect_path
@@ -595,17 +603,6 @@ impl<'a> ReflectStruct<'a> {
595603
self.serialization_data.as_ref()
596604
}
597605

598-
/// Whether this reflected struct represents a remote type or not.
599-
pub fn is_remote_wrapper(&self) -> bool {
600-
self.remote_ty.is_some()
601-
}
602-
603-
#[allow(dead_code)]
604-
/// Get the remote type path, if any.
605-
pub fn remote_ty(&self) -> Option<RemoteType<'a>> {
606-
self.remote_ty
607-
}
608-
609606
/// Returns the `GetTypeRegistration` impl as a `TokenStream`.
610607
///
611608
/// Returns a specific implementation for structs and this method should be preferred over the generic [`get_type_registration`](ReflectMeta) method
@@ -705,22 +702,12 @@ impl<'a> ReflectEnum<'a> {
705702
&self.meta
706703
}
707704

708-
/// Whether this reflected enum represents a remote type or not.
709-
pub fn is_remote_wrapper(&self) -> bool {
710-
self.remote_ty.is_some()
711-
}
712-
713-
#[allow(dead_code)]
714-
/// Get the remote type path, if any.
715-
pub fn remote_ty(&self) -> Option<RemoteType<'a>> {
716-
self.remote_ty
717-
}
718-
719705
/// Returns the given ident as a qualified unit variant of this enum.
720706
///
721707
/// This takes into account the remote type, if any.
722708
pub fn get_unit(&self, variant: &Ident) -> proc_macro2::TokenStream {
723709
let name = self
710+
.meta
724711
.remote_ty
725712
.map(|path| match path.as_expr_path() {
726713
Ok(path) => path.to_token_stream(),

crates/bevy_reflect/derive/src/from_reflect.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ pub(crate) fn impl_enum(reflect_enum: &ReflectEnum) -> proc_macro2::TokenStream
5252
..
5353
} = FromReflectVariantBuilder::new(reflect_enum).build(&ref_value);
5454

55-
let match_branches = if reflect_enum.is_remote_wrapper() {
55+
let match_branches = if reflect_enum.meta().is_remote_wrapper() {
5656
quote! {
5757
#(#variant_names => #fqoption::Some(Self(#variant_constructors)),)*
5858
}
@@ -104,6 +104,7 @@ fn impl_struct_internal(
104104
let fqoption = FQOption.into_token_stream();
105105

106106
let struct_path = reflect_struct.meta().type_path();
107+
let remote_ty = reflect_struct.meta().remote_ty();
107108
let bevy_reflect_path = reflect_struct.meta().bevy_reflect_path();
108109

109110
let ref_struct = Ident::new("__ref_struct", Span::call_site());
@@ -122,7 +123,7 @@ fn impl_struct_internal(
122123
let __this = Ident::new("__this", Span::call_site());
123124

124125
// The reflected type: either `Self` or a remote type
125-
let (reflect_ty, constructor, retval) = if let Some(remote_ty) = reflect_struct.remote_ty() {
126+
let (reflect_ty, constructor, retval) = if let Some(remote_ty) = remote_ty {
126127
let constructor = match remote_ty.as_expr_path() {
127128
Ok(path) => path,
128129
Err(err) => return err.into_compile_error(),

crates/bevy_reflect/derive/src/impls/common.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,14 @@ use crate::{derive_data::ReflectMeta, utility::WhereClauseOptions};
77
pub fn impl_full_reflect(
88
meta: &ReflectMeta,
99
where_clause_options: &WhereClauseOptions,
10-
is_remote_wrapper: bool,
1110
) -> proc_macro2::TokenStream {
1211
let bevy_reflect_path = meta.bevy_reflect_path();
1312
let type_path = meta.type_path();
1413

1514
let (impl_generics, ty_generics, where_clause) = type_path.generics().split_for_impl();
1615
let where_reflect_clause = where_clause_options.extend_where_clause(where_clause);
1716

18-
let any_impls = if is_remote_wrapper {
17+
let any_impls = if meta.is_remote_wrapper() {
1918
quote! {
2019
#[inline]
2120
fn into_any(self: #FQBox<Self>) -> #FQBox<dyn #FQAny> {

crates/bevy_reflect/derive/src/impls/enums.rs

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ use syn::{Fields, Path};
99
pub(crate) fn impl_enum(reflect_enum: &ReflectEnum) -> proc_macro2::TokenStream {
1010
let bevy_reflect_path = reflect_enum.meta().bevy_reflect_path();
1111
let enum_path = reflect_enum.meta().type_path();
12-
let is_remote = reflect_enum.is_remote_wrapper();
12+
let is_remote = reflect_enum.meta().is_remote_wrapper();
1313

1414
// For `match self` expressions where self is a reference
1515
let match_this = if is_remote {
@@ -62,11 +62,7 @@ pub(crate) fn impl_enum(reflect_enum: &ReflectEnum) -> proc_macro2::TokenStream
6262
);
6363

6464
let type_path_impl = impl_type_path(reflect_enum.meta());
65-
let full_reflect_impl = impl_full_reflect(
66-
reflect_enum.meta(),
67-
&where_clause_options,
68-
reflect_enum.is_remote_wrapper(),
69-
);
65+
let full_reflect_impl = impl_full_reflect(reflect_enum.meta(), &where_clause_options);
7066
let common_methods = common_partial_reflect_methods(
7167
reflect_enum.meta(),
7268
|| Some(quote!(#bevy_reflect_path::enum_partial_eq)),

crates/bevy_reflect/derive/src/impls/structs.rs

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -39,11 +39,7 @@ pub(crate) fn impl_struct(reflect_struct: &ReflectStruct) -> proc_macro2::TokenS
3939
);
4040

4141
let type_path_impl = impl_type_path(reflect_struct.meta());
42-
let full_reflect_impl = impl_full_reflect(
43-
reflect_struct.meta(),
44-
&where_clause_options,
45-
reflect_struct.is_remote_wrapper(),
46-
);
42+
let full_reflect_impl = impl_full_reflect(reflect_struct.meta(), &where_clause_options);
4743
let common_methods = common_partial_reflect_methods(
4844
reflect_struct.meta(),
4945
|| Some(quote!(#bevy_reflect_path::struct_partial_eq)),

crates/bevy_reflect/derive/src/impls/tuple_structs.rs

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -29,11 +29,7 @@ pub(crate) fn impl_tuple_struct(reflect_struct: &ReflectStruct) -> proc_macro2::
2929
);
3030

3131
let type_path_impl = impl_type_path(reflect_struct.meta());
32-
let full_reflect_impl = impl_full_reflect(
33-
reflect_struct.meta(),
34-
&where_clause_options,
35-
reflect_struct.is_remote_wrapper(),
36-
);
32+
let full_reflect_impl = impl_full_reflect(reflect_struct.meta(), &where_clause_options);
3733
let common_methods = common_partial_reflect_methods(
3834
reflect_struct.meta(),
3935
|| Some(quote!(#bevy_reflect_path::tuple_struct_partial_eq)),

crates/bevy_reflect/derive/src/impls/values.rs

Lines changed: 26 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,26 @@ pub(crate) fn impl_value(meta: &ReflectMeta) -> proc_macro2::TokenStream {
2828
);
2929

3030
let type_path_impl = impl_type_path(meta);
31-
let full_reflect_impl = impl_full_reflect(meta, &where_clause_options, false);
31+
let full_reflect_impl = impl_full_reflect(meta, &where_clause_options);
3232
let common_methods = common_partial_reflect_methods(meta, || None, || None);
3333

34+
let apply_impl = if let Some(remote_ty) = meta.remote_ty() {
35+
let ty = remote_ty.type_path();
36+
quote! {
37+
if let #FQOption::Some(value) = <dyn #bevy_reflect_path::PartialReflect>::try_downcast_ref::<#ty>(value) {
38+
*self = Self(#FQClone::clone(value));
39+
return #FQResult::Ok(());
40+
}
41+
}
42+
} else {
43+
quote! {
44+
if let #FQOption::Some(value) = <dyn #bevy_reflect_path::PartialReflect>::try_downcast_ref::<Self>(value) {
45+
*self = #FQClone::clone(value);
46+
return #FQResult::Ok(());
47+
}
48+
}
49+
};
50+
3451
#[cfg(not(feature = "functions"))]
3552
let function_impls = None::<proc_macro2::TokenStream>;
3653
#[cfg(feature = "functions")]
@@ -67,17 +84,14 @@ pub(crate) fn impl_value(meta: &ReflectMeta) -> proc_macro2::TokenStream {
6784
&mut self,
6885
value: &dyn #bevy_reflect_path::PartialReflect
6986
) -> #FQResult<(), #bevy_reflect_path::ApplyError> {
70-
if let #FQOption::Some(value) = <dyn #bevy_reflect_path::PartialReflect>::try_downcast_ref::<Self>(value) {
71-
*self = #FQClone::clone(value);
72-
} else {
73-
return #FQResult::Err(
74-
#bevy_reflect_path::ApplyError::MismatchedTypes {
75-
from_type: ::core::convert::Into::into(#bevy_reflect_path::DynamicTypePath::reflect_type_path(value)),
76-
to_type: ::core::convert::Into::into(<Self as #bevy_reflect_path::TypePath>::type_path()),
77-
}
78-
);
79-
}
80-
#FQResult::Ok(())
87+
#apply_impl
88+
89+
#FQResult::Err(
90+
#bevy_reflect_path::ApplyError::MismatchedTypes {
91+
from_type: ::core::convert::Into::into(#bevy_reflect_path::DynamicTypePath::reflect_type_path(value)),
92+
to_type: ::core::convert::Into::into(<Self as #bevy_reflect_path::TypePath>::type_path()),
93+
}
94+
)
8195
}
8296

8397
#[inline]

crates/bevy_reflect/derive/src/remote.rs

Lines changed: 18 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
use crate::derive_data::{ReflectImplSource, ReflectProvenance, ReflectTraitToImpl};
22
use crate::impls::impl_assertions;
33
use crate::utility::ident_or_index;
4-
use crate::{from_reflect, impls, ReflectDerive, REFLECT_ATTRIBUTE_NAME};
4+
use crate::{
5+
from_reflect, impls, ReflectDerive, REFLECT_ATTRIBUTE_NAME, REFLECT_VALUE_ATTRIBUTE_NAME,
6+
};
57
use bevy_macro_utils::fq_std::FQOption;
68
use proc_macro::TokenStream;
79
use proc_macro2::{Ident, Span};
@@ -68,11 +70,14 @@ pub(crate) fn reflect_remote(args: TokenStream, input: TokenStream) -> TokenStre
6870
None
6971
},
7072
),
71-
_ => {
72-
return syn::Error::new(ast.span(), "cannot reflect a remote value type")
73-
.into_compile_error()
74-
.into()
75-
}
73+
ReflectDerive::Value(meta) => (
74+
impls::impl_value(&meta),
75+
if meta.from_reflect().should_auto_derive() {
76+
Some(from_reflect::impl_value(&meta))
77+
} else {
78+
None
79+
},
80+
),
7681
};
7782

7883
TokenStream::from(quote! {
@@ -109,10 +114,10 @@ fn generate_remote_wrapper(input: &DeriveInput, remote_ty: &TypePath) -> proc_ma
109114
let vis = &input.vis;
110115
let ty_generics = &input.generics;
111116
let where_clause = &input.generics.where_clause;
112-
let attrs = input
113-
.attrs
114-
.iter()
115-
.filter(|attr| !attr.path().is_ident(REFLECT_ATTRIBUTE_NAME));
117+
let attrs = input.attrs.iter().filter(|attr| {
118+
!attr.path().is_ident(REFLECT_ATTRIBUTE_NAME)
119+
&& !attr.path().is_ident(REFLECT_VALUE_ATTRIBUTE_NAME)
120+
});
116121

117122
quote! {
118123
#(#attrs)*
@@ -402,12 +407,9 @@ fn generate_remote_definition_assertions(derive_data: &ReflectDerive) -> proc_ma
402407
}
403408
}
404409
}
405-
ReflectDerive::Value(meta) => {
406-
return syn::Error::new(
407-
meta.type_path().span(),
408-
"cannot reflect a remote value type",
409-
)
410-
.into_compile_error()
410+
ReflectDerive::Value(_) => {
411+
// No assertions needed since there are no fields to check
412+
proc_macro2::TokenStream::new()
411413
}
412414
};
413415

crates/bevy_reflect/derive/src/struct_utility.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ impl FieldAccessors {
6161
where
6262
F: FnMut(&StructField, proc_macro2::TokenStream) -> proc_macro2::TokenStream,
6363
{
64-
let is_remote = reflect_struct.is_remote_wrapper();
64+
let is_remote = reflect_struct.meta().is_remote_wrapper();
6565
reflect_struct
6666
.active_fields()
6767
.map(|field| {

0 commit comments

Comments
 (0)