Skip to content

Commit cddb930

Browse files
bevy_reflect: ReflectFromPtr to create &dyn Reflect
1 parent 8630b19 commit cddb930

File tree

3 files changed

+99
-3
lines changed

3 files changed

+99
-3
lines changed

crates/bevy_reflect/bevy_reflect_derive/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -719,6 +719,7 @@ fn impl_get_type_registration(
719719
impl #impl_generics #bevy_reflect_path::GetTypeRegistration for #type_name #ty_generics #where_clause {
720720
fn get_type_registration() -> #bevy_reflect_path::TypeRegistration {
721721
let mut registration = #bevy_reflect_path::TypeRegistration::of::<#type_name #ty_generics>();
722+
registration.insert::<#bevy_reflect_path::ReflectFromPtr>(#bevy_reflect_path::FromType::<#type_name #ty_generics>::from_type());
722723
#(registration.insert::<#registration_data>(#bevy_reflect_path::FromType::<#type_name #ty_generics>::from_type());)*
723724
registration
724725
}

crates/bevy_reflect/src/impls/std.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use crate as bevy_reflect;
1+
use crate::{self as bevy_reflect, ReflectFromPtr};
22
use crate::{
33
map_partial_eq, serde::Serializable, DynamicMap, FromReflect, FromType, GetTypeRegistration,
44
List, ListIter, Map, MapIter, Reflect, ReflectDeserialize, ReflectMut, ReflectRef,
@@ -148,6 +148,7 @@ impl<T: FromReflect + for<'de> Deserialize<'de>> GetTypeRegistration for Vec<T>
148148
fn get_type_registration() -> TypeRegistration {
149149
let mut registration = TypeRegistration::of::<Vec<T>>();
150150
registration.insert::<ReflectDeserialize>(FromType::<Vec<T>>::from_type());
151+
registration.insert::<ReflectFromPtr>(FromType::<Vec<T>>::from_type());
151152
registration
152153
}
153154
}
@@ -270,6 +271,7 @@ where
270271
fn get_type_registration() -> TypeRegistration {
271272
let mut registration = TypeRegistration::of::<Self>();
272273
registration.insert::<ReflectDeserialize>(FromType::<Self>::from_type());
274+
registration.insert::<ReflectFromPtr>(FromType::<Self>::from_type());
273275
registration
274276
}
275277
}
@@ -355,6 +357,7 @@ impl GetTypeRegistration for Cow<'static, str> {
355357
fn get_type_registration() -> TypeRegistration {
356358
let mut registration = TypeRegistration::of::<Cow<'static, str>>();
357359
registration.insert::<ReflectDeserialize>(FromType::<Cow<'static, str>>::from_type());
360+
registration.insert::<ReflectFromPtr>(FromType::<Cow<'static, str>>::from_type());
358361
registration
359362
}
360363
}

crates/bevy_reflect/src/type_registry.rs

Lines changed: 94 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use bevy_utils::{HashMap, HashSet};
33
use downcast_rs::{impl_downcast, Downcast};
44
use parking_lot::{RwLock, RwLockReadGuard, RwLockWriteGuard};
55
use serde::Deserialize;
6-
use std::{any::TypeId, fmt::Debug, sync::Arc};
6+
use std::{any::TypeId, fmt::Debug, marker::PhantomData, sync::Arc};
77

88
/// A registry of reflected types.
99
#[derive(Default)]
@@ -350,11 +350,103 @@ impl<T: for<'a> Deserialize<'a> + Reflect> FromType<T> for ReflectDeserialize {
350350
}
351351
}
352352

353+
#[derive(Clone)]
354+
pub struct ReflectFromPtr {
355+
type_id: TypeId,
356+
to_reflect: for<'a> unsafe fn(*const (), lt: PhantomData<&'a ()>) -> &'a dyn Reflect,
357+
to_reflect_mut: for<'a> unsafe fn(*mut (), lt: PhantomData<&'a ()>) -> &'a mut dyn Reflect,
358+
}
359+
360+
impl ReflectFromPtr {
361+
/// # Safety:
362+
/// - `val` must be a pointer to a value of the type that the [`ReflectFromPtr`] was constructed for
363+
/// - the lifetime `'a` of the return type can be arbitrarily chosen by the caller, who must ensure that during
364+
/// that lifetime, `val` is valid
365+
pub unsafe fn to_reflect_ptr<'a>(&self, val: *const ()) -> &'a dyn Reflect {
366+
(self.to_reflect)(val, PhantomData)
367+
}
368+
369+
/// # Safety:
370+
/// - `val` must be a pointer to a value of the type that the [`ReflectFromPtr`] was constructed for
371+
/// - the lifetime `'a` of the return type can be arbitrarily chosen by the caller, who must ensure that during
372+
/// that lifetime, `val` is valid and not aliased
373+
pub unsafe fn to_reflect_ptr_mut<'a>(&self, val: *mut ()) -> &'a mut dyn Reflect {
374+
(self.to_reflect_mut)(val, PhantomData)
375+
}
376+
377+
pub fn to_reflect<'a, T: 'static>(&self, val: &'a T) -> &'a dyn Reflect {
378+
assert_eq!(self.type_id, std::any::TypeId::of::<T>());
379+
// SAFE: the lifetime of `val` is the same as the lifetime of the return value
380+
// and the type of `val` has been checked to be the same correct one
381+
unsafe { self.to_reflect_ptr(val as *const _ as *const ()) }
382+
}
383+
384+
pub fn to_reflect_mut<'a, T: 'static>(&self, val: &'a mut T) -> &'a mut dyn Reflect {
385+
assert_eq!(self.type_id, std::any::TypeId::of::<T>());
386+
// SAFE: the lifetime of `val` is the same as the lifetime of the return value
387+
// and the type of `val` has been checked to be the same correct one
388+
unsafe { self.to_reflect_ptr_mut(val as *mut _ as *mut ()) }
389+
}
390+
}
391+
392+
impl<T: Reflect + 'static> FromType<T> for ReflectFromPtr {
393+
fn from_type() -> Self {
394+
ReflectFromPtr {
395+
type_id: std::any::TypeId::of::<T>(),
396+
to_reflect: |ptr, _lt| {
397+
// SAFE: can only be called by `to_reflect_ptr` where the caller promises the safety requirements
398+
// or `to_reflect` which is typed and checks that the correct type is used.
399+
let val: &T = unsafe { &*ptr.cast::<T>() };
400+
val as &dyn Reflect
401+
},
402+
to_reflect_mut: |ptr, _lt| {
403+
// SAFE: can only be called by `to_reflect_ptr_mut` where the caller promises the safety requirements
404+
// or `to_reflect_mut` which is typed and checks that the correct type is used.
405+
let val: &mut T = unsafe { &mut *ptr.cast::<T>() };
406+
val as &mut dyn Reflect
407+
},
408+
}
409+
}
410+
}
411+
353412
#[cfg(test)]
354413
mod test {
355-
use crate::TypeRegistration;
414+
use crate::{GetTypeRegistration, ReflectFromPtr, TypeRegistration};
356415
use bevy_utils::HashMap;
357416

417+
use crate as bevy_reflect;
418+
use crate::Reflect;
419+
420+
#[test]
421+
fn test_reflect_from_ptr() {
422+
#[derive(Reflect)]
423+
struct Foo {
424+
a: f32,
425+
}
426+
427+
let foo_registration = <Foo as GetTypeRegistration>::get_type_registration();
428+
let reflect_from_ptr = foo_registration.data::<ReflectFromPtr>().unwrap();
429+
430+
let mut value = Foo { a: 1.0 };
431+
432+
let dyn_reflect = reflect_from_ptr.to_reflect_mut(&mut value);
433+
match dyn_reflect.reflect_mut() {
434+
bevy_reflect::ReflectMut::Struct(strukt) => {
435+
strukt.field_mut("a").unwrap().apply(&2.0f32)
436+
}
437+
_ => panic!("invalid reflection"),
438+
}
439+
440+
let dyn_reflect = reflect_from_ptr.to_reflect(&value);
441+
match dyn_reflect.reflect_ref() {
442+
bevy_reflect::ReflectRef::Struct(strukt) => {
443+
let a = strukt.field("a").unwrap().downcast_ref::<f32>().unwrap();
444+
assert_eq!(*a, 2.0);
445+
}
446+
_ => panic!("invalid reflection"),
447+
}
448+
}
449+
358450
#[test]
359451
fn test_get_short_name() {
360452
assert_eq!(

0 commit comments

Comments
 (0)