Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Merged by Bors] - remove blanket Serialize + Deserialize requirement for Reflect on generic types #5197

42 changes: 41 additions & 1 deletion crates/bevy_app/src/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -862,7 +862,14 @@ impl App {
self
}

/// Adds the type `T` to the type registry [`Resource`].
/// Registers the type `T` in the [`TypeRegistry`](bevy_reflect::TypeRegistry) resource,
/// adding reflect data as specified in the [`Reflect`](bevy_reflect::Reflect) derive:
/// ```rust,ignore
/// #[derive(Reflect)]
/// #[reflect(Component, Serialize, Deserialize)] // will register ReflectComponent, ReflectSerialize, ReflectDeserialize
/// ```
///
/// See [`bevy_reflect::TypeRegistry::register`].
#[cfg(feature = "bevy_reflect")]
pub fn register_type<T: bevy_reflect::GetTypeRegistration>(&mut self) -> &mut Self {
{
Expand All @@ -872,6 +879,39 @@ impl App {
self
}

/// Adds the type data `D` to type `T` in the [`TypeRegistry`](bevy_reflect::TypeRegistry) resource.
///
/// Most of the time [`App::register_type`] can be used instead to register a type you derived [`Reflect`](bevy_reflect::Reflect) for.
/// However, in cases where you want to add a piece of type data that was not included in the list of `#[reflect(...)]` type data in the derive,
/// or where the type is generic and cannot register e.g. `ReflectSerialize` unconditionally without knowing the specific type parameters,
/// this method can be used to insert additional type data.
///
/// # Example
/// ```rust
/// use bevy_app::App;
/// use bevy_reflect::{ReflectSerialize, ReflectDeserialize};
///
/// App::new()
/// .register_type::<Option<String>>()
/// .register_type_data::<Option<String>, ReflectSerialize>()
/// .register_type_data::<Option<String>, ReflectDeserialize>();
/// ```
///
/// See [`bevy_reflect::TypeRegistry::register_type_data`].
#[cfg(feature = "bevy_reflect")]
pub fn register_type_data<
T: bevy_reflect::Reflect + 'static,
D: bevy_reflect::TypeData + bevy_reflect::FromType<T>,
>(
&mut self,
) -> &mut Self {
{
let registry = self.world.resource_mut::<bevy_reflect::TypeRegistryArc>();
registry.write().register_type_data::<T, D>();
}
self
}

/// Adds an [`App`] as a child of the current one.
///
/// The provided function `f` is called by the [`update`](Self::update) method. The [`World`]
Expand Down
37 changes: 14 additions & 23 deletions crates/bevy_reflect/src/impls/std.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,7 @@ use crate::{

use crate::utility::{GenericTypeInfoCell, NonGenericTypeInfoCell};
use bevy_reflect_derive::{impl_from_reflect_value, impl_reflect_value};
use bevy_utils::{Duration, HashMap, HashSet};
use serde::{Deserialize, Serialize};
use bevy_utils::{Duration, HashMap, HashSet, Instant};
use std::{
any::Any,
borrow::Cow,
Expand All @@ -33,10 +32,12 @@ impl_reflect_value!(isize(Debug, Hash, PartialEq, Serialize, Deserialize));
impl_reflect_value!(f32(Debug, PartialEq, Serialize, Deserialize));
impl_reflect_value!(f64(Debug, PartialEq, Serialize, Deserialize));
impl_reflect_value!(String(Debug, Hash, PartialEq, Serialize, Deserialize));
impl_reflect_value!(Option<T: Serialize + Clone + for<'de> Deserialize<'de> + Reflect + 'static>(Serialize, Deserialize));
impl_reflect_value!(HashSet<T: Serialize + Hash + Eq + Clone + for<'de> Deserialize<'de> + Send + Sync + 'static>(Serialize, Deserialize));
impl_reflect_value!(Range<T: Serialize + Clone + for<'de> Deserialize<'de> + Send + Sync + 'static>(Serialize, Deserialize));
impl_reflect_value!(Option<T: Clone + Reflect + 'static>());
impl_reflect_value!(Result<T: Clone + Reflect + 'static, E: Clone + Reflect + 'static>());
impl_reflect_value!(HashSet<T: Hash + Eq + Clone + Send + Sync + 'static>());
impl_reflect_value!(Range<T: Clone + Send + Sync + 'static>());
impl_reflect_value!(Duration(Debug, Hash, PartialEq, Serialize, Deserialize));
impl_reflect_value!(Instant(Debug, Hash, PartialEq));

impl_from_reflect_value!(bool);
impl_from_reflect_value!(char);
Expand All @@ -55,15 +56,9 @@ impl_from_reflect_value!(isize);
impl_from_reflect_value!(f32);
impl_from_reflect_value!(f64);
impl_from_reflect_value!(String);
impl_from_reflect_value!(
Option<T: Serialize + Clone + for<'de> Deserialize<'de> + Reflect + 'static>
);
impl_from_reflect_value!(
HashSet<T: Serialize + Hash + Eq + Clone + for<'de> Deserialize<'de> + Send + Sync + 'static>
);
impl_from_reflect_value!(
Range<T: Serialize + Clone + for<'de> Deserialize<'de> + Send + Sync + 'static>
);
impl_from_reflect_value!(Option<T: Clone + Reflect + 'static>);
impl_from_reflect_value!(HashSet<T: Hash + Eq + Clone + Send + Sync + 'static>);
impl_from_reflect_value!(Range<T: Clone + Send + Sync + 'static>);
impl_from_reflect_value!(Duration);

impl<T: FromReflect> Array for Vec<T> {
Expand Down Expand Up @@ -171,10 +166,9 @@ impl<T: FromReflect> Typed for Vec<T> {
}
}

impl<T: FromReflect + for<'de> Deserialize<'de>> GetTypeRegistration for Vec<T> {
impl<T: FromReflect> GetTypeRegistration for Vec<T> {
fn get_type_registration() -> TypeRegistration {
let mut registration = TypeRegistration::of::<Vec<T>>();
registration.insert::<ReflectDeserialize>(FromType::<Vec<T>>::from_type());
registration.insert::<ReflectFromPtr>(FromType::<Vec<T>>::from_type());
registration
}
Expand Down Expand Up @@ -323,12 +317,11 @@ impl<K: FromReflect + Eq + Hash, V: FromReflect> Typed for HashMap<K, V> {

impl<K, V> GetTypeRegistration for HashMap<K, V>
where
K: FromReflect + Clone + Eq + Hash + for<'de> Deserialize<'de>,
V: FromReflect + Clone + for<'de> Deserialize<'de>,
K: FromReflect + Clone + Eq + Hash,
V: FromReflect + Clone,
{
fn get_type_registration() -> TypeRegistration {
let mut registration = TypeRegistration::of::<HashMap<K, V>>();
registration.insert::<ReflectDeserialize>(FromType::<HashMap<K, V>>::from_type());
registration.insert::<ReflectFromPtr>(FromType::<HashMap<K, V>>::from_type());
registration
}
Expand Down Expand Up @@ -476,11 +469,9 @@ impl<T: Reflect, const N: usize> Typed for [T; N] {
macro_rules! impl_array_get_type_registration {
($($N:expr)+) => {
$(
impl<T: Reflect + for<'de> Deserialize<'de>> GetTypeRegistration for [T; $N] {
impl<T: Reflect > GetTypeRegistration for [T; $N] {
fn get_type_registration() -> TypeRegistration {
let mut registration = TypeRegistration::of::<[T; $N]>();
registration.insert::<ReflectDeserialize>(FromType::<[T; $N]>::from_type());
registration
TypeRegistration::of::<[T; $N]>()
}
}
)+
Expand Down
11 changes: 4 additions & 7 deletions crates/bevy_reflect/src/tuple.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
use crate::utility::NonGenericTypeInfoCell;
use crate::{
DynamicInfo, FromReflect, FromType, GetTypeRegistration, Reflect, ReflectDeserialize,
ReflectMut, ReflectRef, TypeInfo, TypeRegistration, Typed, UnnamedField,
DynamicInfo, FromReflect, GetTypeRegistration, Reflect, ReflectMut, ReflectRef, TypeInfo,
TypeRegistration, Typed, UnnamedField,
};
use serde::Deserialize;
use std::any::{Any, TypeId};
use std::fmt::{Debug, Formatter};
use std::slice::Iter;
Expand Down Expand Up @@ -534,11 +533,9 @@ macro_rules! impl_reflect_tuple {
}
}

impl<$($name: Reflect + Typed + for<'de> Deserialize<'de>),*> GetTypeRegistration for ($($name,)*) {
impl<$($name: Reflect + Typed),*> GetTypeRegistration for ($($name,)*) {
fn get_type_registration() -> TypeRegistration {
let mut registration = TypeRegistration::of::<($($name,)*)>();
registration.insert::<ReflectDeserialize>(FromType::<($($name,)*)>::from_type());
registration
TypeRegistration::of::<($($name,)*)>()
}
}

Expand Down
33 changes: 32 additions & 1 deletion crates/bevy_reflect/src/type_registry.rs
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,11 @@ impl TypeRegistry {
registry
}

/// Registers the type `T`.
/// Registers the type `T`, adding reflect data as specified in the [`Reflect`] derive:
/// ```rust,ignore
/// #[derive(Reflect)]
/// #[reflect(Component, Serialize, Deserialize)] // will register ReflectComponent, ReflectSerialize, ReflectDeserialize
/// ```
pub fn register<T>(&mut self)
where
T: GetTypeRegistration,
Expand All @@ -100,6 +104,33 @@ impl TypeRegistry {
.insert(registration.type_id(), registration);
}

/// Registers the type data `D` for type `T`.
///
/// Most of the time [`TypeRegistry::register`] can be used instead to register a type you derived [`Reflect`] for.
/// However, in cases where you want to add a piece of type data that was not included in the list of `#[reflect(...)]` type data in the derive,
/// or where the type is generic and cannot register e.g. `ReflectSerialize` unconditionally without knowing the specific type parameters,
/// this method can be used to insert additional type data.
///
/// # Example
jakobhellermann marked this conversation as resolved.
Show resolved Hide resolved
/// ```rust
/// use bevy_reflect::{TypeRegistry, ReflectSerialize, ReflectDeserialize};
///
/// let mut type_registry = TypeRegistry::default();
/// type_registry.register::<Option<String>>();
/// type_registry.register_type_data::<Option<String>, ReflectSerialize>();
/// type_registry.register_type_data::<Option<String>, ReflectDeserialize>();
/// ```
pub fn register_type_data<T: Reflect + 'static, 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 = std::any::type_name::<T>(),
D = std::any::type_name::<D>(),
)
});
data.insert(D::from_type());
}

/// Returns a reference to the [`TypeRegistration`] of the type with the
/// given [`TypeId`].
///
Expand Down
5 changes: 4 additions & 1 deletion crates/bevy_time/src/time.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
use bevy_ecs::reflect::ReflectResource;
use bevy_reflect::Reflect;
use bevy_utils::{Duration, Instant};

/// Tracks elapsed time since the last update and since the App has started
#[derive(Debug, Clone)]
#[derive(Reflect, Debug, Clone)]
#[reflect(Resource)]
pub struct Time {
delta: Duration,
last_update: Option<Instant>,
Expand Down