use crate::{serde::Serializable, FromReflect, Reflect, TypeInfo, TypePath, Typed};
use alloc::{boxed::Box, string::String};
use bevy_platform::{
collections::{HashMap, HashSet},
sync::{Arc, PoisonError, RwLock, RwLockReadGuard, RwLockWriteGuard},
};
use bevy_ptr::{Ptr, PtrMut};
use bevy_utils::TypeIdMap;
use core::{
any::TypeId,
fmt::Debug,
ops::{Deref, DerefMut},
};
use downcast_rs::{impl_downcast, Downcast};
use serde::{Deserialize, Serialize};
pub struct TypeRegistry {
registrations: TypeIdMap<TypeRegistration>,
short_path_to_id: HashMap<&'static str, TypeId>,
type_path_to_id: HashMap<&'static str, TypeId>,
ambiguous_names: HashSet<&'static str>,
}
#[derive(Clone, Default)]
pub struct TypeRegistryArc {
pub internal: Arc<RwLock<TypeRegistry>>,
}
impl Debug for TypeRegistryArc {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
self.internal
.read()
.unwrap_or_else(PoisonError::into_inner)
.type_path_to_id
.keys()
.fmt(f)
}
}
#[diagnostic::on_unimplemented(
message = "`{Self}` does not implement `GetTypeRegistration` so cannot provide type registration information",
note = "consider annotating `{Self}` with `#[derive(Reflect)]`"
)]
pub trait GetTypeRegistration: 'static {
fn get_type_registration() -> TypeRegistration;
fn register_type_dependencies(_registry: &mut TypeRegistry) {}
}
impl Default for TypeRegistry {
fn default() -> Self {
Self::new()
}
}
impl TypeRegistry {
pub fn empty() -> Self {
Self {
registrations: Default::default(),
short_path_to_id: Default::default(),
type_path_to_id: Default::default(),
ambiguous_names: Default::default(),
}
}
pub fn new() -> Self {
let mut registry = Self::empty();
registry.register::<()>();
registry.register::<bool>();
registry.register::<char>();
registry.register::<u8>();
registry.register::<u16>();
registry.register::<u32>();
registry.register::<u64>();
registry.register::<u128>();
registry.register::<usize>();
registry.register::<i8>();
registry.register::<i16>();
registry.register::<i32>();
registry.register::<i64>();
registry.register::<i128>();
registry.register::<isize>();
registry.register::<f32>();
registry.register::<f64>();
registry.register::<String>();
registry
}
#[cfg(feature = "auto_register")]
pub fn register_derived_types(&mut self) {
crate::__macro_exports::auto_register::register_types(self);
}
pub fn register<T>(&mut self)
where
T: GetTypeRegistration,
{
if self.register_internal(TypeId::of::<T>(), T::get_type_registration) {
T::register_type_dependencies(self);
}
}
pub fn register_by_val<T>(&mut self, _: &T)
where
T: GetTypeRegistration,
{
self.register::<T>();
}
pub fn add_registration(&mut self, registration: TypeRegistration) -> bool {
let type_id = registration.type_id();
self.register_internal(type_id, || registration)
}
pub fn overwrite_registration(&mut self, registration: TypeRegistration) {
Self::update_registration_indices(
®istration,
&mut self.short_path_to_id,
&mut self.type_path_to_id,
&mut self.ambiguous_names,
);
self.registrations
.insert(registration.type_id(), registration);
}
fn register_internal(
&mut self,
type_id: TypeId,
get_registration: impl FnOnce() -> TypeRegistration,
) -> bool {
use bevy_platform::collections::hash_map::Entry;
match self.registrations.entry(type_id) {
Entry::Occupied(_) => false,
Entry::Vacant(entry) => {
let registration = get_registration();
Self::update_registration_indices(
®istration,
&mut self.short_path_to_id,
&mut self.type_path_to_id,
&mut self.ambiguous_names,
);
entry.insert(registration);
true
}
}
}
fn update_registration_indices(
registration: &TypeRegistration,
short_path_to_id: &mut HashMap<&'static str, TypeId>,
type_path_to_id: &mut HashMap<&'static str, TypeId>,
ambiguous_names: &mut HashSet<&'static str>,
) {
let short_name = registration.type_info().type_path_table().short_path();
if short_path_to_id.contains_key(short_name) || ambiguous_names.contains(short_name) {
short_path_to_id.remove(short_name);
ambiguous_names.insert(short_name);
} else {
short_path_to_id.insert(short_name, registration.type_id());
}
type_path_to_id.insert(registration.type_info().type_path(), registration.type_id());
}
pub fn register_type_data<T: Reflect + TypePath, D: TypeData + FromType<T>>(&mut self) {
let data = self.get_mut(TypeId::of::<T>()).unwrap_or_else(|| {
panic!(
"attempted to call `TypeRegistry::register_type_data` for type `{T}` with data `{D}` without registering `{T}` first",
T = T::type_path(),
D = core::any::type_name::<D>(),
)
});
data.insert(D::from_type());
}
pub fn contains(&self, type_id: TypeId) -> bool {
self.registrations.contains_key(&type_id)
}
#[inline]
pub fn get(&self, type_id: TypeId) -> Option<&TypeRegistration> {
self.registrations.get(&type_id)
}
pub fn get_mut(&mut self, type_id: TypeId) -> Option<&mut TypeRegistration> {
self.registrations.get_mut(&type_id)
}
pub fn get_with_type_path(&self, type_path: &str) -> Option<&TypeRegistration> {
self.type_path_to_id
.get(type_path)
.and_then(|id| self.get(*id))
}
pub fn get_with_type_path_mut(&mut self, type_path: &str) -> Option<&mut TypeRegistration> {
self.type_path_to_id
.get(type_path)
.cloned()
.and_then(move |id| self.get_mut(id))
}
pub fn get_with_short_type_path(&self, short_type_path: &str) -> Option<&TypeRegistration> {
self.short_path_to_id
.get(short_type_path)
.and_then(|id| self.registrations.get(id))
}
pub fn get_with_short_type_path_mut(
&mut self,
short_type_path: &str,
) -> Option<&mut TypeRegistration> {
self.short_path_to_id
.get(short_type_path)
.and_then(|id| self.registrations.get_mut(id))
}
pub fn is_ambiguous(&self, short_type_path: &str) -> bool {
self.ambiguous_names.contains(short_type_path)
}
pub fn get_type_data<T: TypeData>(&self, type_id: TypeId) -> Option<&T> {
self.get(type_id)
.and_then(|registration| registration.data::<T>())
}
pub fn get_type_data_mut<T: TypeData>(&mut self, type_id: TypeId) -> Option<&mut T> {
self.get_mut(type_id)
.and_then(|registration| registration.data_mut::<T>())
}
pub fn get_type_info(&self, type_id: TypeId) -> Option<&'static TypeInfo> {
self.get(type_id).map(TypeRegistration::type_info)
}
pub fn iter(&self) -> impl Iterator<Item = &TypeRegistration> {
self.registrations.values()
}
pub fn iter_mut(&mut self) -> impl Iterator<Item = &mut TypeRegistration> {
self.registrations.values_mut()
}
pub fn iter_with_data<T: TypeData>(&self) -> impl Iterator<Item = (&TypeRegistration, &T)> {
self.registrations.values().filter_map(|item| {
let type_data = item.data::<T>();
type_data.map(|data| (item, data))
})
}
}
impl TypeRegistryArc {
pub fn read(&self) -> RwLockReadGuard<'_, TypeRegistry> {
self.internal.read().unwrap_or_else(PoisonError::into_inner)
}
pub fn write(&self) -> RwLockWriteGuard<'_, TypeRegistry> {
self.internal
.write()
.unwrap_or_else(PoisonError::into_inner)
}
}
pub struct TypeRegistration {
data: TypeIdMap<Box<dyn TypeData>>,
type_info: &'static TypeInfo,
}
impl Debug for TypeRegistration {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_struct("TypeRegistration")
.field("type_info", &self.type_info)
.finish()
}
}
impl TypeRegistration {
pub fn of<T: Reflect + Typed + TypePath>() -> Self {
Self {
data: Default::default(),
type_info: T::type_info(),
}
}
#[inline]
pub fn type_id(&self) -> TypeId {
self.type_info.type_id()
}
pub fn type_info(&self) -> &'static TypeInfo {
self.type_info
}
pub fn insert<T: TypeData>(&mut self, data: T) {
self.data.insert(TypeId::of::<T>(), Box::new(data));
}
#[inline]
pub fn register_type_data<T: TypeData + FromType<V>, V>(&mut self) {
self.insert(T::from_type());
T::insert_dependencies(self);
}
pub fn data<T: TypeData>(&self) -> Option<&T> {
self.data
.get(&TypeId::of::<T>())
.and_then(|value| value.downcast_ref())
}
pub fn data_by_id(&self, type_id: TypeId) -> Option<&dyn TypeData> {
self.data.get(&type_id).map(Deref::deref)
}
pub fn data_mut<T: TypeData>(&mut self) -> Option<&mut T> {
self.data
.get_mut(&TypeId::of::<T>())
.and_then(|value| value.downcast_mut())
}
pub fn data_mut_by_id(&mut self, type_id: TypeId) -> Option<&mut dyn TypeData> {
self.data.get_mut(&type_id).map(DerefMut::deref_mut)
}
pub fn contains<T: TypeData>(&self) -> bool {
self.data.contains_key(&TypeId::of::<T>())
}
pub fn contains_by_id(&self, type_id: TypeId) -> bool {
self.data.contains_key(&type_id)
}
pub fn len(&self) -> usize {
self.data.len()
}
pub fn is_empty(&self) -> bool {
self.data.is_empty()
}
pub fn iter(&self) -> impl ExactSizeIterator<Item = (TypeId, &dyn TypeData)> {
self.data.iter().map(|(id, data)| (*id, data.deref()))
}
pub fn iter_mut(&mut self) -> impl ExactSizeIterator<Item = (TypeId, &mut dyn TypeData)> {
self.data
.iter_mut()
.map(|(id, data)| (*id, data.deref_mut()))
}
}
impl Clone for TypeRegistration {
fn clone(&self) -> Self {
let mut data = TypeIdMap::default();
for (id, type_data) in &self.data {
data.insert(*id, (*type_data).clone_type_data());
}
TypeRegistration {
data,
type_info: self.type_info,
}
}
}
pub trait TypeData: Downcast + Send + Sync {
fn clone_type_data(&self) -> Box<dyn TypeData>;
}
impl_downcast!(TypeData);
impl<T: 'static + Send + Sync> TypeData for T
where
T: Clone,
{
fn clone_type_data(&self) -> Box<dyn TypeData> {
Box::new(self.clone())
}
}
pub trait FromType<T> {
fn from_type() -> Self;
fn insert_dependencies(_type_registration: &mut TypeRegistration) {}
}
#[derive(Clone)]
pub struct ReflectSerialize {
get_serializable: fn(value: &dyn Reflect) -> Serializable,
}
impl<T: TypePath + FromReflect + erased_serde::Serialize> FromType<T> for ReflectSerialize {
fn from_type() -> Self {
ReflectSerialize {
get_serializable: |value| {
value
.downcast_ref::<T>()
.map(|value| Serializable::Borrowed(value))
.or_else(|| T::from_reflect(value.as_partial_reflect()).map(|value| Serializable::Owned(Box::new(value))))
.unwrap_or_else(|| {
panic!(
"FromReflect::from_reflect failed when called on type `{}` with this value: {value:?}",
T::type_path(),
);
})
},
}
}
}
impl ReflectSerialize {
pub fn get_serializable<'a>(&self, value: &'a dyn Reflect) -> Serializable<'a> {
(self.get_serializable)(value)
}
pub fn serialize<S>(&self, value: &dyn Reflect, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
(self.get_serializable)(value).serialize(serializer)
}
}
#[derive(Clone)]
pub struct ReflectDeserialize {
pub func: fn(
deserializer: &mut dyn erased_serde::Deserializer,
) -> Result<Box<dyn Reflect>, erased_serde::Error>,
}
impl ReflectDeserialize {
pub fn deserialize<'de, D>(&self, deserializer: D) -> Result<Box<dyn Reflect>, D::Error>
where
D: serde::Deserializer<'de>,
{
let mut erased = <dyn erased_serde::Deserializer>::erase(deserializer);
(self.func)(&mut erased)
.map_err(<<D as serde::Deserializer<'de>>::Error as serde::de::Error>::custom)
}
}
impl<T: for<'a> Deserialize<'a> + Reflect> FromType<T> for ReflectDeserialize {
fn from_type() -> Self {
ReflectDeserialize {
func: |deserializer| Ok(Box::new(T::deserialize(deserializer)?)),
}
}
}
#[derive(Clone)]
pub struct ReflectFromPtr {
type_id: TypeId,
from_ptr: unsafe fn(Ptr) -> &dyn Reflect,
from_ptr_mut: unsafe fn(PtrMut) -> &mut dyn Reflect,
}
#[expect(
unsafe_code,
reason = "We must interact with pointers here, which are inherently unsafe."
)]
impl ReflectFromPtr {
pub fn type_id(&self) -> TypeId {
self.type_id
}
pub unsafe fn as_reflect<'a>(&self, val: Ptr<'a>) -> &'a dyn Reflect {
unsafe { (self.from_ptr)(val) }
}
pub unsafe fn as_reflect_mut<'a>(&self, val: PtrMut<'a>) -> &'a mut dyn Reflect {
unsafe { (self.from_ptr_mut)(val) }
}
pub fn from_ptr(&self) -> unsafe fn(Ptr) -> &dyn Reflect {
self.from_ptr
}
pub fn from_ptr_mut(&self) -> unsafe fn(PtrMut) -> &mut dyn Reflect {
self.from_ptr_mut
}
}
#[expect(
unsafe_code,
reason = "We must interact with pointers here, which are inherently unsafe."
)]
impl<T: Reflect> FromType<T> for ReflectFromPtr {
fn from_type() -> Self {
ReflectFromPtr {
type_id: TypeId::of::<T>(),
from_ptr: |ptr| {
unsafe { ptr.deref::<T>() as &dyn Reflect }
},
from_ptr_mut: |ptr| {
unsafe { ptr.deref_mut::<T>() as &mut dyn Reflect }
},
}
}
}
#[cfg(test)]
#[expect(
unsafe_code,
reason = "We must interact with pointers here, which are inherently unsafe."
)]
mod test {
use super::*;
#[test]
fn test_reflect_from_ptr() {
#[derive(Reflect)]
struct Foo {
a: f32,
}
let foo_registration = <Foo as GetTypeRegistration>::get_type_registration();
let reflect_from_ptr = foo_registration.data::<ReflectFromPtr>().unwrap();
assert_eq!(reflect_from_ptr.type_id(), TypeId::of::<Foo>());
let mut value = Foo { a: 1.0 };
{
let value = PtrMut::from(&mut value);
let dyn_reflect = unsafe { reflect_from_ptr.as_reflect_mut(value) };
match dyn_reflect.reflect_mut() {
bevy_reflect::ReflectMut::Struct(strukt) => {
strukt.field_mut("a").unwrap().apply(&2.0f32);
}
_ => panic!("invalid reflection"),
}
}
{
let dyn_reflect = unsafe { reflect_from_ptr.as_reflect(Ptr::from(&value)) };
match dyn_reflect.reflect_ref() {
bevy_reflect::ReflectRef::Struct(strukt) => {
let a = strukt
.field("a")
.unwrap()
.try_downcast_ref::<f32>()
.unwrap();
assert_eq!(*a, 2.0);
}
_ => panic!("invalid reflection"),
}
}
}
#[test]
fn type_data_iter() {
#[derive(Reflect)]
struct Foo;
#[derive(Clone)]
struct DataA(i32);
let mut registration = TypeRegistration::of::<Foo>();
registration.insert(DataA(123));
let mut iter = registration.iter();
let (id, data) = iter.next().unwrap();
assert_eq!(id, TypeId::of::<DataA>());
assert_eq!(data.downcast_ref::<DataA>().unwrap().0, 123);
assert!(iter.next().is_none());
}
#[test]
fn type_data_iter_mut() {
#[derive(Reflect)]
struct Foo;
#[derive(Clone)]
struct DataA(i32);
let mut registration = TypeRegistration::of::<Foo>();
registration.insert(DataA(123));
{
let mut iter = registration.iter_mut();
let (_, data) = iter.next().unwrap();
data.downcast_mut::<DataA>().unwrap().0 = 456;
assert!(iter.next().is_none());
}
let data = registration.data::<DataA>().unwrap();
assert_eq!(data.0, 456);
}
}