# Objective https://github.com/bevyengine/bevy/pull/4447 adds functions that can fetch resources/components as `*const ()` ptr by providing the `ComponentId`. This alone is not enough for them to be usable safely with reflection, because there is no general way to go from the raw pointer to a `&dyn Reflect` which is the pointer + a pointer to the VTable of the `Reflect` impl. By adding a `ReflectFromPtr` type that is included in the type type registration when deriving `Reflect`, safe functions can be implemented in scripting languages that don't assume a type layout and can access the component data via reflection: ```rust #[derive(Reflect)] struct StringResource { value: String } ``` ```lua local res_id = world:resource_id_by_name("example::StringResource") local res = world:resource(res_id) print(res.value) ``` ## Solution 1. add a `ReflectFromPtr` type with a `FromType<T: Reflect>` implementation and the following methods: - ` pub unsafe fn as_reflect_ptr<'a>(&self, val: Ptr<'a>) -> &'a dyn Reflect` - ` pub unsafe fn as_reflect_ptr_mut<'a>(&self, val: PtrMut<'a>) -> &'a mud dyn Reflect` Safety requirements of the methods are that you need to check that the `ReflectFromPtr` was constructed for the correct type. 2. add that type to the `TypeRegistration` in the `GetTypeRegistration` impl generated by `#[derive(Reflect)]`. This is different to other reflected traits because it doesn't need `#[reflect(ReflectReflectFromPtr)]` which IMO should be there by default. Co-authored-by: Jakob Hellermann <hellermann@sipgate.de> Co-authored-by: Carter Anderson <mcanders1@gmail.com>
27 lines
1.1 KiB
Rust
27 lines
1.1 KiB
Rust
//! Contains code related specifically to Bevy's type registration.
|
|
|
|
use proc_macro2::Ident;
|
|
use quote::quote;
|
|
use syn::{Generics, Path};
|
|
|
|
/// Creates the `GetTypeRegistration` impl for the given type data.
|
|
pub(crate) fn impl_get_type_registration(
|
|
type_name: &Ident,
|
|
bevy_reflect_path: &Path,
|
|
registration_data: &[Ident],
|
|
generics: &Generics,
|
|
) -> proc_macro2::TokenStream {
|
|
let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
|
|
quote! {
|
|
#[allow(unused_mut)]
|
|
impl #impl_generics #bevy_reflect_path::GetTypeRegistration for #type_name #ty_generics #where_clause {
|
|
fn get_type_registration() -> #bevy_reflect_path::TypeRegistration {
|
|
let mut registration = #bevy_reflect_path::TypeRegistration::of::<#type_name #ty_generics>();
|
|
registration.insert::<#bevy_reflect_path::ReflectFromPtr>(#bevy_reflect_path::FromType::<#type_name #ty_generics>::from_type());
|
|
#(registration.insert::<#registration_data>(#bevy_reflect_path::FromType::<#type_name #ty_generics>::from_type());)*
|
|
registration
|
|
}
|
|
}
|
|
}
|
|
}
|