bevy_reflect: Add `ReflectFromReflect` (v2) (#6245)
# Objective
Resolves #4597 (based on the work from #6056 and a refresh of #4147)
When using reflection, we may often end up in a scenario where we have a Dynamic representing a certain type. Unfortunately, we can't just call `MyType::from_reflect` as we do not have knowledge of the concrete type (`MyType`) at runtime.
Such scenarios happen when we call `Reflect::clone_value`, use the reflection deserializers, or create the Dynamic type ourselves.
## Solution
Add a `ReflectFromReflect` type data struct.
This struct allows us to easily convert Dynamic representations of our types into their respective concrete instances.
```rust
#[derive(Reflect, FromReflect)]
#[reflect(FromReflect)] // <- Register `ReflectFromReflect`
struct MyStruct(String);
let type_id = TypeId::of::<MyStruct>();
// Register our type
let mut registry = TypeRegistry::default();
registry.register::<MyStruct>();
// Create a concrete instance
let my_struct = MyStruct("Hello world".to_string());
// `Reflect::clone_value` will generate a `DynamicTupleStruct` for tuple struct types
let dynamic_value: Box<dyn Reflect> = my_struct.clone_value();
assert!(!dynamic_value.is::<MyStruct>());
// Get the `ReflectFromReflect` type data from the registry
let rfr: &ReflectFromReflect = registry
.get_type_data::<ReflectFromReflect>(type_id)
.unwrap();
// Call `FromReflect::from_reflect` on our Dynamic value
let concrete_value: Box<dyn Reflect> = rfr.from_reflect(&dynamic_value);
assert!(concrete_value.is::<MyStruct>());
```
### Why this PR?
###### Why now?
The three main reasons I closed #4147 were that:
1. Registering `ReflectFromReflect` is clunky (deriving `FromReflect` *and* registering `ReflectFromReflect`)
2. The ecosystem and Bevy itself didn't seem to pay much attention to deriving `FromReflect`
3. I didn't see a lot of desire from the community for such a feature
However, as time has passed it seems 2 and 3 are not really true anymore. Bevy is internally adding lots more `FromReflect` derives, which should make this feature all the more useful. Additionally, I have seen a growing number of people look for something like `ReflectFromReflect`.
I think 1 is still an issue, but not a horrible one. Plus it could be made much, much better using #6056. And I think splitting this feature out of #6056 could lead to #6056 being adopted sooner (or at least make the need more clear to users).
###### Why not just re-open #4147?
The main reason is so that this PR can garner more attention than simply re-opening the old one. This helps bring fresh eyes to the PR for potentially more perspectives/reviews.
---
## Changelog
* Added `ReflectFromReflect`
Co-authored-by: Gino Valente <49806985+MrGVSV@users.noreply.github.com>
2022-12-11 17:52:48 +00:00
|
|
|
use crate::{FromType, Reflect};
|
|
|
|
|
2023-02-18 20:42:01 +00:00
|
|
|
/// A trait that enables types to be dynamically constructed from reflected data.
|
bevy_reflect: Add `ReflectFromReflect` (v2) (#6245)
# Objective
Resolves #4597 (based on the work from #6056 and a refresh of #4147)
When using reflection, we may often end up in a scenario where we have a Dynamic representing a certain type. Unfortunately, we can't just call `MyType::from_reflect` as we do not have knowledge of the concrete type (`MyType`) at runtime.
Such scenarios happen when we call `Reflect::clone_value`, use the reflection deserializers, or create the Dynamic type ourselves.
## Solution
Add a `ReflectFromReflect` type data struct.
This struct allows us to easily convert Dynamic representations of our types into their respective concrete instances.
```rust
#[derive(Reflect, FromReflect)]
#[reflect(FromReflect)] // <- Register `ReflectFromReflect`
struct MyStruct(String);
let type_id = TypeId::of::<MyStruct>();
// Register our type
let mut registry = TypeRegistry::default();
registry.register::<MyStruct>();
// Create a concrete instance
let my_struct = MyStruct("Hello world".to_string());
// `Reflect::clone_value` will generate a `DynamicTupleStruct` for tuple struct types
let dynamic_value: Box<dyn Reflect> = my_struct.clone_value();
assert!(!dynamic_value.is::<MyStruct>());
// Get the `ReflectFromReflect` type data from the registry
let rfr: &ReflectFromReflect = registry
.get_type_data::<ReflectFromReflect>(type_id)
.unwrap();
// Call `FromReflect::from_reflect` on our Dynamic value
let concrete_value: Box<dyn Reflect> = rfr.from_reflect(&dynamic_value);
assert!(concrete_value.is::<MyStruct>());
```
### Why this PR?
###### Why now?
The three main reasons I closed #4147 were that:
1. Registering `ReflectFromReflect` is clunky (deriving `FromReflect` *and* registering `ReflectFromReflect`)
2. The ecosystem and Bevy itself didn't seem to pay much attention to deriving `FromReflect`
3. I didn't see a lot of desire from the community for such a feature
However, as time has passed it seems 2 and 3 are not really true anymore. Bevy is internally adding lots more `FromReflect` derives, which should make this feature all the more useful. Additionally, I have seen a growing number of people look for something like `ReflectFromReflect`.
I think 1 is still an issue, but not a horrible one. Plus it could be made much, much better using #6056. And I think splitting this feature out of #6056 could lead to #6056 being adopted sooner (or at least make the need more clear to users).
###### Why not just re-open #4147?
The main reason is so that this PR can garner more attention than simply re-opening the old one. This helps bring fresh eyes to the PR for potentially more perspectives/reviews.
---
## Changelog
* Added `ReflectFromReflect`
Co-authored-by: Gino Valente <49806985+MrGVSV@users.noreply.github.com>
2022-12-11 17:52:48 +00:00
|
|
|
///
|
2023-02-18 20:42:01 +00:00
|
|
|
/// It's recommended to use the [derive macro] rather than manually implementing this trait.
|
|
|
|
///
|
|
|
|
/// `FromReflect` allows dynamic proxy types, like [`DynamicStruct`], to be used to generate
|
|
|
|
/// their concrete counterparts.
|
|
|
|
/// It can also be used to partially or fully clone a type (depending on whether it has
|
|
|
|
/// ignored fields or not).
|
|
|
|
///
|
|
|
|
/// In some cases, this trait may even be required.
|
|
|
|
/// Deriving [`Reflect`] on an enum requires all its fields to implement `FromReflect`.
|
|
|
|
/// Additionally, some complex types like `Vec<T>` require that their element types
|
bevy_reflect: Add `ReflectFromReflect` (v2) (#6245)
# Objective
Resolves #4597 (based on the work from #6056 and a refresh of #4147)
When using reflection, we may often end up in a scenario where we have a Dynamic representing a certain type. Unfortunately, we can't just call `MyType::from_reflect` as we do not have knowledge of the concrete type (`MyType`) at runtime.
Such scenarios happen when we call `Reflect::clone_value`, use the reflection deserializers, or create the Dynamic type ourselves.
## Solution
Add a `ReflectFromReflect` type data struct.
This struct allows us to easily convert Dynamic representations of our types into their respective concrete instances.
```rust
#[derive(Reflect, FromReflect)]
#[reflect(FromReflect)] // <- Register `ReflectFromReflect`
struct MyStruct(String);
let type_id = TypeId::of::<MyStruct>();
// Register our type
let mut registry = TypeRegistry::default();
registry.register::<MyStruct>();
// Create a concrete instance
let my_struct = MyStruct("Hello world".to_string());
// `Reflect::clone_value` will generate a `DynamicTupleStruct` for tuple struct types
let dynamic_value: Box<dyn Reflect> = my_struct.clone_value();
assert!(!dynamic_value.is::<MyStruct>());
// Get the `ReflectFromReflect` type data from the registry
let rfr: &ReflectFromReflect = registry
.get_type_data::<ReflectFromReflect>(type_id)
.unwrap();
// Call `FromReflect::from_reflect` on our Dynamic value
let concrete_value: Box<dyn Reflect> = rfr.from_reflect(&dynamic_value);
assert!(concrete_value.is::<MyStruct>());
```
### Why this PR?
###### Why now?
The three main reasons I closed #4147 were that:
1. Registering `ReflectFromReflect` is clunky (deriving `FromReflect` *and* registering `ReflectFromReflect`)
2. The ecosystem and Bevy itself didn't seem to pay much attention to deriving `FromReflect`
3. I didn't see a lot of desire from the community for such a feature
However, as time has passed it seems 2 and 3 are not really true anymore. Bevy is internally adding lots more `FromReflect` derives, which should make this feature all the more useful. Additionally, I have seen a growing number of people look for something like `ReflectFromReflect`.
I think 1 is still an issue, but not a horrible one. Plus it could be made much, much better using #6056. And I think splitting this feature out of #6056 could lead to #6056 being adopted sooner (or at least make the need more clear to users).
###### Why not just re-open #4147?
The main reason is so that this PR can garner more attention than simply re-opening the old one. This helps bring fresh eyes to the PR for potentially more perspectives/reviews.
---
## Changelog
* Added `ReflectFromReflect`
Co-authored-by: Gino Valente <49806985+MrGVSV@users.noreply.github.com>
2022-12-11 17:52:48 +00:00
|
|
|
/// implement this trait.
|
2023-02-18 20:42:01 +00:00
|
|
|
/// The reason for such requirements is that some operations require new data to be constructed,
|
|
|
|
/// such as swapping to a new variant or pushing data to a homogenous list.
|
|
|
|
///
|
|
|
|
/// See the [crate-level documentation] to see how this trait can be used.
|
bevy_reflect: Add `ReflectFromReflect` (v2) (#6245)
# Objective
Resolves #4597 (based on the work from #6056 and a refresh of #4147)
When using reflection, we may often end up in a scenario where we have a Dynamic representing a certain type. Unfortunately, we can't just call `MyType::from_reflect` as we do not have knowledge of the concrete type (`MyType`) at runtime.
Such scenarios happen when we call `Reflect::clone_value`, use the reflection deserializers, or create the Dynamic type ourselves.
## Solution
Add a `ReflectFromReflect` type data struct.
This struct allows us to easily convert Dynamic representations of our types into their respective concrete instances.
```rust
#[derive(Reflect, FromReflect)]
#[reflect(FromReflect)] // <- Register `ReflectFromReflect`
struct MyStruct(String);
let type_id = TypeId::of::<MyStruct>();
// Register our type
let mut registry = TypeRegistry::default();
registry.register::<MyStruct>();
// Create a concrete instance
let my_struct = MyStruct("Hello world".to_string());
// `Reflect::clone_value` will generate a `DynamicTupleStruct` for tuple struct types
let dynamic_value: Box<dyn Reflect> = my_struct.clone_value();
assert!(!dynamic_value.is::<MyStruct>());
// Get the `ReflectFromReflect` type data from the registry
let rfr: &ReflectFromReflect = registry
.get_type_data::<ReflectFromReflect>(type_id)
.unwrap();
// Call `FromReflect::from_reflect` on our Dynamic value
let concrete_value: Box<dyn Reflect> = rfr.from_reflect(&dynamic_value);
assert!(concrete_value.is::<MyStruct>());
```
### Why this PR?
###### Why now?
The three main reasons I closed #4147 were that:
1. Registering `ReflectFromReflect` is clunky (deriving `FromReflect` *and* registering `ReflectFromReflect`)
2. The ecosystem and Bevy itself didn't seem to pay much attention to deriving `FromReflect`
3. I didn't see a lot of desire from the community for such a feature
However, as time has passed it seems 2 and 3 are not really true anymore. Bevy is internally adding lots more `FromReflect` derives, which should make this feature all the more useful. Additionally, I have seen a growing number of people look for something like `ReflectFromReflect`.
I think 1 is still an issue, but not a horrible one. Plus it could be made much, much better using #6056. And I think splitting this feature out of #6056 could lead to #6056 being adopted sooner (or at least make the need more clear to users).
###### Why not just re-open #4147?
The main reason is so that this PR can garner more attention than simply re-opening the old one. This helps bring fresh eyes to the PR for potentially more perspectives/reviews.
---
## Changelog
* Added `ReflectFromReflect`
Co-authored-by: Gino Valente <49806985+MrGVSV@users.noreply.github.com>
2022-12-11 17:52:48 +00:00
|
|
|
///
|
2023-02-18 20:42:01 +00:00
|
|
|
/// [derive macro]: bevy_reflect_derive::FromReflect
|
|
|
|
/// [`DynamicStruct`]: crate::DynamicStruct
|
|
|
|
/// [crate-level documentation]: crate
|
bevy_reflect: Add `ReflectFromReflect` (v2) (#6245)
# Objective
Resolves #4597 (based on the work from #6056 and a refresh of #4147)
When using reflection, we may often end up in a scenario where we have a Dynamic representing a certain type. Unfortunately, we can't just call `MyType::from_reflect` as we do not have knowledge of the concrete type (`MyType`) at runtime.
Such scenarios happen when we call `Reflect::clone_value`, use the reflection deserializers, or create the Dynamic type ourselves.
## Solution
Add a `ReflectFromReflect` type data struct.
This struct allows us to easily convert Dynamic representations of our types into their respective concrete instances.
```rust
#[derive(Reflect, FromReflect)]
#[reflect(FromReflect)] // <- Register `ReflectFromReflect`
struct MyStruct(String);
let type_id = TypeId::of::<MyStruct>();
// Register our type
let mut registry = TypeRegistry::default();
registry.register::<MyStruct>();
// Create a concrete instance
let my_struct = MyStruct("Hello world".to_string());
// `Reflect::clone_value` will generate a `DynamicTupleStruct` for tuple struct types
let dynamic_value: Box<dyn Reflect> = my_struct.clone_value();
assert!(!dynamic_value.is::<MyStruct>());
// Get the `ReflectFromReflect` type data from the registry
let rfr: &ReflectFromReflect = registry
.get_type_data::<ReflectFromReflect>(type_id)
.unwrap();
// Call `FromReflect::from_reflect` on our Dynamic value
let concrete_value: Box<dyn Reflect> = rfr.from_reflect(&dynamic_value);
assert!(concrete_value.is::<MyStruct>());
```
### Why this PR?
###### Why now?
The three main reasons I closed #4147 were that:
1. Registering `ReflectFromReflect` is clunky (deriving `FromReflect` *and* registering `ReflectFromReflect`)
2. The ecosystem and Bevy itself didn't seem to pay much attention to deriving `FromReflect`
3. I didn't see a lot of desire from the community for such a feature
However, as time has passed it seems 2 and 3 are not really true anymore. Bevy is internally adding lots more `FromReflect` derives, which should make this feature all the more useful. Additionally, I have seen a growing number of people look for something like `ReflectFromReflect`.
I think 1 is still an issue, but not a horrible one. Plus it could be made much, much better using #6056. And I think splitting this feature out of #6056 could lead to #6056 being adopted sooner (or at least make the need more clear to users).
###### Why not just re-open #4147?
The main reason is so that this PR can garner more attention than simply re-opening the old one. This helps bring fresh eyes to the PR for potentially more perspectives/reviews.
---
## Changelog
* Added `ReflectFromReflect`
Co-authored-by: Gino Valente <49806985+MrGVSV@users.noreply.github.com>
2022-12-11 17:52:48 +00:00
|
|
|
pub trait FromReflect: Reflect + Sized {
|
|
|
|
/// Constructs a concrete instance of `Self` from a reflected value.
|
|
|
|
fn from_reflect(reflect: &dyn Reflect) -> Option<Self>;
|
2023-01-11 16:25:37 +00:00
|
|
|
|
|
|
|
/// Attempts to downcast the given value to `Self` using,
|
|
|
|
/// constructing the value using [`from_reflect`] if that fails.
|
|
|
|
///
|
|
|
|
/// This method is more efficient than using [`from_reflect`] for cases where
|
|
|
|
/// the given value is likely a boxed instance of `Self` (i.e. `Box<Self>`)
|
|
|
|
/// rather than a boxed dynamic type (e.g. [`DynamicStruct`], [`DynamicList`], etc.).
|
|
|
|
///
|
|
|
|
/// [`from_reflect`]: Self::from_reflect
|
|
|
|
/// [`DynamicStruct`]: crate::DynamicStruct
|
|
|
|
/// [`DynamicList`]: crate::DynamicList
|
|
|
|
fn take_from_reflect(reflect: Box<dyn Reflect>) -> Result<Self, Box<dyn Reflect>> {
|
|
|
|
match reflect.take::<Self>() {
|
|
|
|
Ok(value) => Ok(value),
|
|
|
|
Err(value) => match Self::from_reflect(value.as_ref()) {
|
|
|
|
None => Err(value),
|
|
|
|
Some(value) => Ok(value),
|
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|
bevy_reflect: Add `ReflectFromReflect` (v2) (#6245)
# Objective
Resolves #4597 (based on the work from #6056 and a refresh of #4147)
When using reflection, we may often end up in a scenario where we have a Dynamic representing a certain type. Unfortunately, we can't just call `MyType::from_reflect` as we do not have knowledge of the concrete type (`MyType`) at runtime.
Such scenarios happen when we call `Reflect::clone_value`, use the reflection deserializers, or create the Dynamic type ourselves.
## Solution
Add a `ReflectFromReflect` type data struct.
This struct allows us to easily convert Dynamic representations of our types into their respective concrete instances.
```rust
#[derive(Reflect, FromReflect)]
#[reflect(FromReflect)] // <- Register `ReflectFromReflect`
struct MyStruct(String);
let type_id = TypeId::of::<MyStruct>();
// Register our type
let mut registry = TypeRegistry::default();
registry.register::<MyStruct>();
// Create a concrete instance
let my_struct = MyStruct("Hello world".to_string());
// `Reflect::clone_value` will generate a `DynamicTupleStruct` for tuple struct types
let dynamic_value: Box<dyn Reflect> = my_struct.clone_value();
assert!(!dynamic_value.is::<MyStruct>());
// Get the `ReflectFromReflect` type data from the registry
let rfr: &ReflectFromReflect = registry
.get_type_data::<ReflectFromReflect>(type_id)
.unwrap();
// Call `FromReflect::from_reflect` on our Dynamic value
let concrete_value: Box<dyn Reflect> = rfr.from_reflect(&dynamic_value);
assert!(concrete_value.is::<MyStruct>());
```
### Why this PR?
###### Why now?
The three main reasons I closed #4147 were that:
1. Registering `ReflectFromReflect` is clunky (deriving `FromReflect` *and* registering `ReflectFromReflect`)
2. The ecosystem and Bevy itself didn't seem to pay much attention to deriving `FromReflect`
3. I didn't see a lot of desire from the community for such a feature
However, as time has passed it seems 2 and 3 are not really true anymore. Bevy is internally adding lots more `FromReflect` derives, which should make this feature all the more useful. Additionally, I have seen a growing number of people look for something like `ReflectFromReflect`.
I think 1 is still an issue, but not a horrible one. Plus it could be made much, much better using #6056. And I think splitting this feature out of #6056 could lead to #6056 being adopted sooner (or at least make the need more clear to users).
###### Why not just re-open #4147?
The main reason is so that this PR can garner more attention than simply re-opening the old one. This helps bring fresh eyes to the PR for potentially more perspectives/reviews.
---
## Changelog
* Added `ReflectFromReflect`
Co-authored-by: Gino Valente <49806985+MrGVSV@users.noreply.github.com>
2022-12-11 17:52:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Type data that represents the [`FromReflect`] trait and allows it to be used dynamically.
|
|
|
|
///
|
|
|
|
/// `FromReflect` allows dynamic types (e.g. [`DynamicStruct`], [`DynamicEnum`], etc.) to be converted
|
|
|
|
/// to their full, concrete types. This is most important when it comes to deserialization where it isn't
|
|
|
|
/// guaranteed that every field exists when trying to construct the final output.
|
|
|
|
///
|
|
|
|
/// However, to do this, you normally need to specify the exact concrete type:
|
|
|
|
///
|
|
|
|
/// ```
|
|
|
|
/// # use bevy_reflect::{DynamicTupleStruct, FromReflect, Reflect};
|
|
|
|
/// #[derive(Reflect, FromReflect, PartialEq, Eq, Debug)]
|
|
|
|
/// struct Foo(#[reflect(default = "default_value")] usize);
|
|
|
|
///
|
|
|
|
/// fn default_value() -> usize { 123 }
|
|
|
|
///
|
|
|
|
/// let reflected = DynamicTupleStruct::default();
|
|
|
|
///
|
|
|
|
/// let concrete: Foo = <Foo as FromReflect>::from_reflect(&reflected).unwrap();
|
|
|
|
///
|
|
|
|
/// assert_eq!(Foo(123), concrete);
|
|
|
|
/// ```
|
|
|
|
///
|
|
|
|
/// In a dynamic context where the type might not be known at compile-time, this is nearly impossible to do.
|
|
|
|
/// That is why this type data struct exists— it allows us to construct the full type without knowing
|
|
|
|
/// what the actual type is.
|
|
|
|
///
|
|
|
|
/// # Example
|
|
|
|
///
|
|
|
|
/// ```
|
|
|
|
/// # use bevy_reflect::{DynamicTupleStruct, FromReflect, Reflect, ReflectFromReflect, TypeRegistry};
|
|
|
|
/// # #[derive(Reflect, FromReflect, PartialEq, Eq, Debug)]
|
|
|
|
/// # #[reflect(FromReflect)]
|
|
|
|
/// # struct Foo(#[reflect(default = "default_value")] usize);
|
|
|
|
/// # fn default_value() -> usize { 123 }
|
|
|
|
/// # let mut registry = TypeRegistry::new();
|
|
|
|
/// # registry.register::<Foo>();
|
|
|
|
///
|
|
|
|
/// let mut reflected = DynamicTupleStruct::default();
|
|
|
|
/// reflected.set_name(std::any::type_name::<Foo>().to_string());
|
|
|
|
///
|
|
|
|
/// let registration = registry.get_with_name(reflected.type_name()).unwrap();
|
|
|
|
/// let rfr = registration.data::<ReflectFromReflect>().unwrap();
|
|
|
|
///
|
|
|
|
/// let concrete: Box<dyn Reflect> = rfr.from_reflect(&reflected).unwrap();
|
|
|
|
///
|
|
|
|
/// assert_eq!(Foo(123), concrete.take::<Foo>().unwrap());
|
|
|
|
/// ```
|
|
|
|
///
|
|
|
|
/// [`DynamicStruct`]: crate::DynamicStruct
|
|
|
|
/// [`DynamicEnum`]: crate::DynamicEnum
|
|
|
|
#[derive(Clone)]
|
|
|
|
pub struct ReflectFromReflect {
|
|
|
|
from_reflect: fn(&dyn Reflect) -> Option<Box<dyn Reflect>>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl ReflectFromReflect {
|
|
|
|
/// Perform a [`FromReflect::from_reflect`] conversion on the given reflection object.
|
|
|
|
///
|
|
|
|
/// This will convert the object to a concrete type if it wasn't already, and return
|
|
|
|
/// the value as `Box<dyn Reflect>`.
|
|
|
|
#[allow(clippy::wrong_self_convention)]
|
|
|
|
pub fn from_reflect(&self, reflect_value: &dyn Reflect) -> Option<Box<dyn Reflect>> {
|
|
|
|
(self.from_reflect)(reflect_value)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<T: FromReflect> FromType<T> for ReflectFromReflect {
|
|
|
|
fn from_type() -> Self {
|
|
|
|
Self {
|
|
|
|
from_reflect: |reflect_value| {
|
|
|
|
T::from_reflect(reflect_value).map(|value| Box::new(value) as Box<dyn Reflect>)
|
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|