Skip to content

Commit e5925fd

Browse files
committed
Better safety documentation
1 parent b00c4d7 commit e5925fd

File tree

4 files changed

+27
-1
lines changed

4 files changed

+27
-1
lines changed

crates/bevy_reflect/bevy_reflect_derive/src/enum_utility.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ pub(crate) fn get_variant_constructors(
6969
if let Some(field_ty) = &field.attrs.remote {
7070
quote! {
7171
unsafe {
72+
// SAFE: The wrapper type should be repr(transparent) over the remote type
7273
::std::mem::transmute(
7374
<#field_ty as #bevy_reflect_path::FromReflect>::from_reflect(#ref_value #accessor)
7475
#unwrapper

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -380,6 +380,7 @@ fn generate_impls(reflect_enum: &ReflectEnum, ref_index: &Ident, ref_name: &Iden
380380
.as_ref()
381381
.map(|ty| {
382382
quote! {
383+
// SAFE: The wrapper type should be repr(transparent) over the remote type
383384
unsafe { ::core::mem::transmute::<#ref_token _, #ref_token #ty>(#ident) }
384385
}
385386
})

crates/bevy_reflect/bevy_reflect_derive/src/lib.rs

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ pub fn reflect_trait(args: TokenStream, input: TokenStream) -> TokenStream {
100100
/// Generates a wrapper type that can be used to "derive `Reflect`" for remote types.
101101
///
102102
/// This works by wrapping the remote type in a generated wrapper that has the `#[repr(transparent)]` attribute.
103-
/// This allows the two types to be safely transmuted back-and-forth.
103+
/// This allows the two types to be safely [transmuted] back-and-forth.
104104
///
105105
/// # Defining the Wrapper
106106
///
@@ -156,6 +156,26 @@ pub fn reflect_trait(args: TokenStream, input: TokenStream) -> TokenStream {
156156
/// pub struct Wrapper<T: Default + Clone>(RemoteType<T>);
157157
/// ```
158158
///
159+
/// # Usage as a Field
160+
///
161+
/// You can tell `Reflect` to use a remote type's wrapper internally on fields of a struct or enum.
162+
/// This allows the real type to be used as usual while `Reflect` handles everything internally.
163+
/// To do this, add the `#[reflect(remote = "...")]` attribute to your field:
164+
///
165+
/// ```ignore
166+
/// #[derive(Reflect)]
167+
/// struct SomeStruct {
168+
/// #[reflect(remote = "RemoteTypeWrapper")]
169+
/// data: RemoteType
170+
/// }
171+
/// ```
172+
///
173+
/// ## Safety
174+
///
175+
/// When using the `#[reflect(remote = "...")]` field attribute, be sure you are defining the correct wrapper type.
176+
/// Internally, this field will be unsafely [transmuted], and is only sound if using a wrapper generated for the remote type.
177+
/// This also means keeping your wrapper definitions up-to-date with the remote types.
178+
///
159179
/// # `FromReflect`
160180
///
161181
/// Because of the way this code modifies the item it's defined on, it is not possible to implement `FromReflect`
@@ -172,6 +192,7 @@ pub fn reflect_trait(args: TokenStream, input: TokenStream) -> TokenStream {
172192
/// This is the _only_ trait this works with. You cannot derive any other traits using this method.
173193
/// For those, use regular derive macros below this one.
174194
///
195+
/// [transmuted]: std::mem::transmute
175196
#[proc_macro_attribute]
176197
pub fn reflect_remote(args: TokenStream, input: TokenStream) -> TokenStream {
177198
remote::reflect_remote(args, input)

crates/bevy_reflect/bevy_reflect_derive/src/struct_utility.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ impl FieldAccessors {
2727
match &field.attrs.remote {
2828
Some(wrapper_ty) => {
2929
quote! {
30+
// SAFE: The wrapper type should be repr(transparent) over the remote type
3031
unsafe { ::core::mem::transmute_copy::<_, #wrapper_ty>(&#accessor) }
3132
}
3233
}
@@ -37,6 +38,7 @@ impl FieldAccessors {
3738
match &field.attrs.remote {
3839
Some(wrapper_ty) => {
3940
quote! {
41+
// SAFE: The wrapper type should be repr(transparent) over the remote type
4042
unsafe { ::core::mem::transmute::<&_, &#wrapper_ty>(&#accessor) }
4143
}
4244
}
@@ -47,6 +49,7 @@ impl FieldAccessors {
4749
match &field.attrs.remote {
4850
Some(wrapper_ty) => {
4951
quote! {
52+
// SAFE: The wrapper type should be repr(transparent) over the remote type
5053
unsafe { ::core::mem::transmute::<&mut _, &mut #wrapper_ty>(&mut #accessor) }
5154
}
5255
}

0 commit comments

Comments
 (0)