2022-05-02 18:04:48 +00:00
|
|
|
use crate::{
|
bevy_reflect: Small refactor and default `Reflect` methods (#4739)
# Objective
Quick followup to #4712.
While updating some [other PRs](https://github.com/bevyengine/bevy/pull/4218), I realized the `ReflectTraits` struct could be improved. The issue with the current implementation is that `ReflectTraits::get_xxx_impl(...)` returns just the _logic_ to the corresponding `Reflect` trait method, rather than the entire function.
This makes it slightly more annoying to manage since the variable names need to be consistent across files. For example, `get_partial_eq_impl` uses a `value` variable. But the name "value" isn't defined in the `get_partial_eq_impl` method, it's defined in three other methods in a completely separate file.
It's not likely to cause any bugs if we keep it as it is since differing variable names will probably just result in a compile error (except in very particular cases). But it would be useful to someone who wanted to edit/add/remove a method.
## Solution
Made `get_hash_impl`, `get_partial_eq_impl` and `get_serialize_impl` return the entire method implementation for `reflect_hash`, `reflect_partial_eq`, and `serializable`, respectively.
As a result of this, those three `Reflect` methods were also given default implementations. This was fairly simple to do since all three could just be made to return `None`.
---
## Changelog
* Small cleanup/refactor to `ReflectTraits` in `bevy_reflect_derive`
* Gave `Reflect::reflect_hash`, `Reflect::reflect_partial_eq`, and `Reflect::serializable` default implementations
2022-05-18 12:26:11 +00:00
|
|
|
FromReflect, FromType, GetTypeRegistration, Reflect, ReflectDeserialize, ReflectMut,
|
|
|
|
ReflectRef, TypeRegistration,
|
2022-05-02 18:04:48 +00:00
|
|
|
};
|
|
|
|
use serde::Deserialize;
|
2021-01-08 03:50:09 +00:00
|
|
|
use std::any::Any;
|
|
|
|
|
2022-01-08 20:45:24 +00:00
|
|
|
/// A reflected Rust tuple.
|
|
|
|
///
|
|
|
|
/// This trait is automatically implemented for arbitrary tuples of up to 12
|
|
|
|
/// elements, provided that each element implements [`Reflect`].
|
|
|
|
///
|
|
|
|
/// # Example
|
|
|
|
///
|
|
|
|
/// ```
|
|
|
|
/// use bevy_reflect::Tuple;
|
|
|
|
///
|
|
|
|
/// # fn main() {
|
|
|
|
/// let foo = ("blue".to_string(), 42_i32);
|
|
|
|
/// assert_eq!(foo.field_len(), 2);
|
|
|
|
///
|
|
|
|
/// let first = foo.field(0).unwrap();
|
|
|
|
/// assert_eq!(first.downcast_ref::<String>(), Some(&"blue".to_string()));
|
|
|
|
/// # }
|
|
|
|
/// ```
|
2021-01-08 03:50:09 +00:00
|
|
|
pub trait Tuple: Reflect {
|
2022-01-08 20:45:24 +00:00
|
|
|
/// Returns a reference to the value of the field with index `index` as a
|
|
|
|
/// `&dyn Reflect`.
|
2021-01-08 03:50:09 +00:00
|
|
|
fn field(&self, index: usize) -> Option<&dyn Reflect>;
|
2022-01-08 20:45:24 +00:00
|
|
|
|
|
|
|
/// Returns a mutable reference to the value of the field with index `index`
|
|
|
|
/// as a `&mut dyn Reflect`.
|
2021-01-08 03:50:09 +00:00
|
|
|
fn field_mut(&mut self, index: usize) -> Option<&mut dyn Reflect>;
|
2022-01-08 20:45:24 +00:00
|
|
|
|
|
|
|
/// Returns the number of fields in the tuple.
|
2021-01-08 03:50:09 +00:00
|
|
|
fn field_len(&self) -> usize;
|
2022-01-08 20:45:24 +00:00
|
|
|
|
|
|
|
/// Returns an iterator over the values of the tuple's fields.
|
2021-01-08 03:50:09 +00:00
|
|
|
fn iter_fields(&self) -> TupleFieldIter;
|
2022-01-08 20:45:24 +00:00
|
|
|
|
|
|
|
/// Clones the struct into a [`DynamicTuple`].
|
2021-01-08 03:50:09 +00:00
|
|
|
fn clone_dynamic(&self) -> DynamicTuple;
|
|
|
|
}
|
|
|
|
|
2022-01-08 20:45:24 +00:00
|
|
|
/// An iterator over the field values of a tuple.
|
2021-01-08 03:50:09 +00:00
|
|
|
pub struct TupleFieldIter<'a> {
|
|
|
|
pub(crate) tuple: &'a dyn Tuple,
|
|
|
|
pub(crate) index: usize,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'a> TupleFieldIter<'a> {
|
|
|
|
pub fn new(value: &'a dyn Tuple) -> Self {
|
|
|
|
TupleFieldIter {
|
|
|
|
tuple: value,
|
|
|
|
index: 0,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'a> Iterator for TupleFieldIter<'a> {
|
|
|
|
type Item = &'a dyn Reflect;
|
|
|
|
|
|
|
|
fn next(&mut self) -> Option<Self::Item> {
|
|
|
|
let value = self.tuple.field(self.index);
|
|
|
|
self.index += 1;
|
|
|
|
value
|
|
|
|
}
|
2021-04-13 01:28:14 +00:00
|
|
|
|
|
|
|
fn size_hint(&self) -> (usize, Option<usize>) {
|
|
|
|
let size = self.tuple.field_len();
|
|
|
|
(size, Some(size))
|
|
|
|
}
|
2021-01-08 03:50:09 +00:00
|
|
|
}
|
|
|
|
|
2021-04-13 01:28:14 +00:00
|
|
|
impl<'a> ExactSizeIterator for TupleFieldIter<'a> {}
|
|
|
|
|
2022-01-08 20:45:24 +00:00
|
|
|
/// A convenience trait which combines fetching and downcasting of tuple
|
|
|
|
/// fields.
|
|
|
|
///
|
|
|
|
/// # Example
|
|
|
|
///
|
|
|
|
/// ```
|
|
|
|
/// use bevy_reflect::GetTupleField;
|
|
|
|
///
|
|
|
|
/// # fn main() {
|
|
|
|
/// let foo = ("blue".to_string(), 42_i32);
|
|
|
|
///
|
|
|
|
/// assert_eq!(foo.get_field::<String>(0), Some(&"blue".to_string()));
|
|
|
|
/// assert_eq!(foo.get_field::<i32>(1), Some(&42));
|
|
|
|
/// # }
|
|
|
|
/// ```
|
2021-01-08 03:50:09 +00:00
|
|
|
pub trait GetTupleField {
|
2022-01-08 20:45:24 +00:00
|
|
|
/// Returns a reference to the value of the field with index `index`,
|
|
|
|
/// downcast to `T`.
|
2021-01-08 03:50:09 +00:00
|
|
|
fn get_field<T: Reflect>(&self, index: usize) -> Option<&T>;
|
2022-01-08 20:45:24 +00:00
|
|
|
|
|
|
|
/// Returns a mutable reference to the value of the field with index
|
|
|
|
/// `index`, downcast to `T`.
|
2021-01-08 03:50:09 +00:00
|
|
|
fn get_field_mut<T: Reflect>(&mut self, index: usize) -> Option<&mut T>;
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<S: Tuple> GetTupleField for S {
|
|
|
|
fn get_field<T: Reflect>(&self, index: usize) -> Option<&T> {
|
|
|
|
self.field(index)
|
|
|
|
.and_then(|value| value.downcast_ref::<T>())
|
|
|
|
}
|
|
|
|
|
|
|
|
fn get_field_mut<T: Reflect>(&mut self, index: usize) -> Option<&mut T> {
|
|
|
|
self.field_mut(index)
|
|
|
|
.and_then(|value| value.downcast_mut::<T>())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl GetTupleField for dyn Tuple {
|
|
|
|
fn get_field<T: Reflect>(&self, index: usize) -> Option<&T> {
|
|
|
|
self.field(index)
|
|
|
|
.and_then(|value| value.downcast_ref::<T>())
|
|
|
|
}
|
|
|
|
|
|
|
|
fn get_field_mut<T: Reflect>(&mut self, index: usize) -> Option<&mut T> {
|
|
|
|
self.field_mut(index)
|
|
|
|
.and_then(|value| value.downcast_mut::<T>())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-01-08 20:45:24 +00:00
|
|
|
/// A tuple which allows fields to be added at runtime.
|
2021-01-08 03:50:09 +00:00
|
|
|
#[derive(Default)]
|
|
|
|
pub struct DynamicTuple {
|
2021-02-02 21:57:26 +00:00
|
|
|
name: String,
|
|
|
|
fields: Vec<Box<dyn Reflect>>,
|
2021-01-08 03:50:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl DynamicTuple {
|
2022-01-14 19:09:44 +00:00
|
|
|
/// Returns the type name of the tuple.
|
2022-01-08 20:45:24 +00:00
|
|
|
///
|
|
|
|
/// The tuple's name is automatically generated from its element types.
|
2021-02-02 21:57:26 +00:00
|
|
|
pub fn name(&self) -> &str {
|
|
|
|
&self.name
|
|
|
|
}
|
|
|
|
|
2022-01-14 19:09:44 +00:00
|
|
|
/// Manually sets the type name of the tuple.
|
2022-01-08 20:45:24 +00:00
|
|
|
///
|
|
|
|
/// Note that the tuple name will be overwritten when elements are added.
|
2021-02-02 21:57:26 +00:00
|
|
|
pub fn set_name(&mut self, name: String) {
|
|
|
|
self.name = name;
|
|
|
|
}
|
|
|
|
|
2022-01-08 20:45:24 +00:00
|
|
|
/// Appends an element with value `value` to the tuple.
|
2021-01-08 03:50:09 +00:00
|
|
|
pub fn insert_boxed(&mut self, value: Box<dyn Reflect>) {
|
|
|
|
self.fields.push(value);
|
2021-02-02 21:57:26 +00:00
|
|
|
self.generate_name();
|
2021-01-08 03:50:09 +00:00
|
|
|
}
|
|
|
|
|
2022-01-08 20:45:24 +00:00
|
|
|
/// Appends a typed element with value `value` to the tuple.
|
2021-01-08 03:50:09 +00:00
|
|
|
pub fn insert<T: Reflect>(&mut self, value: T) {
|
|
|
|
self.insert_boxed(Box::new(value));
|
2021-02-02 21:57:26 +00:00
|
|
|
self.generate_name();
|
|
|
|
}
|
|
|
|
|
|
|
|
fn generate_name(&mut self) {
|
|
|
|
let name = &mut self.name;
|
|
|
|
name.clear();
|
|
|
|
name.push('(');
|
|
|
|
for (i, field) in self.fields.iter().enumerate() {
|
|
|
|
if i > 0 {
|
|
|
|
name.push_str(", ");
|
|
|
|
}
|
|
|
|
name.push_str(field.type_name());
|
|
|
|
}
|
|
|
|
name.push(')');
|
2021-01-08 03:50:09 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Tuple for DynamicTuple {
|
|
|
|
#[inline]
|
|
|
|
fn field(&self, index: usize) -> Option<&dyn Reflect> {
|
|
|
|
self.fields.get(index).map(|field| &**field)
|
|
|
|
}
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
fn field_mut(&mut self, index: usize) -> Option<&mut dyn Reflect> {
|
|
|
|
self.fields.get_mut(index).map(|field| &mut **field)
|
|
|
|
}
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
fn field_len(&self) -> usize {
|
|
|
|
self.fields.len()
|
|
|
|
}
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
fn iter_fields(&self) -> TupleFieldIter {
|
|
|
|
TupleFieldIter {
|
|
|
|
tuple: self,
|
|
|
|
index: 0,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
fn clone_dynamic(&self) -> DynamicTuple {
|
|
|
|
DynamicTuple {
|
2021-02-02 21:57:26 +00:00
|
|
|
name: self.name.clone(),
|
2021-01-08 03:50:09 +00:00
|
|
|
fields: self
|
|
|
|
.fields
|
|
|
|
.iter()
|
|
|
|
.map(|value| value.clone_value())
|
|
|
|
.collect(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-03-17 22:46:46 +00:00
|
|
|
// SAFE: any and any_mut both return self
|
|
|
|
unsafe impl Reflect for DynamicTuple {
|
2021-01-08 03:50:09 +00:00
|
|
|
#[inline]
|
|
|
|
fn type_name(&self) -> &str {
|
2021-02-02 21:57:26 +00:00
|
|
|
self.name()
|
2021-01-08 03:50:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
fn any(&self) -> &dyn Any {
|
|
|
|
self
|
|
|
|
}
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
fn any_mut(&mut self) -> &mut dyn Any {
|
|
|
|
self
|
|
|
|
}
|
|
|
|
|
2022-04-25 13:54:48 +00:00
|
|
|
#[inline]
|
|
|
|
fn as_reflect(&self) -> &dyn Reflect {
|
|
|
|
self
|
|
|
|
}
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
fn as_reflect_mut(&mut self) -> &mut dyn Reflect {
|
|
|
|
self
|
|
|
|
}
|
|
|
|
|
2021-01-08 03:50:09 +00:00
|
|
|
#[inline]
|
|
|
|
fn clone_value(&self) -> Box<dyn Reflect> {
|
|
|
|
Box::new(self.clone_dynamic())
|
|
|
|
}
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
fn reflect_ref(&self) -> ReflectRef {
|
|
|
|
ReflectRef::Tuple(self)
|
|
|
|
}
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
fn reflect_mut(&mut self) -> ReflectMut {
|
|
|
|
ReflectMut::Tuple(self)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn apply(&mut self, value: &dyn Reflect) {
|
|
|
|
tuple_apply(self, value);
|
|
|
|
}
|
|
|
|
|
|
|
|
fn set(&mut self, value: Box<dyn Reflect>) -> Result<(), Box<dyn Reflect>> {
|
|
|
|
*self = value.take()?;
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
fn reflect_partial_eq(&self, value: &dyn Reflect) -> Option<bool> {
|
|
|
|
tuple_partial_eq(self, value)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-01-14 19:09:44 +00:00
|
|
|
/// Applies the elements of `b` to the corresponding elements of `a`.
|
|
|
|
///
|
|
|
|
/// # Panics
|
|
|
|
///
|
|
|
|
/// This function panics if `b` is not a tuple.
|
2021-01-08 03:50:09 +00:00
|
|
|
#[inline]
|
|
|
|
pub fn tuple_apply<T: Tuple>(a: &mut T, b: &dyn Reflect) {
|
|
|
|
if let ReflectRef::Tuple(tuple) = b.reflect_ref() {
|
|
|
|
for (i, value) in tuple.iter_fields().enumerate() {
|
|
|
|
if let Some(v) = a.field_mut(i) {
|
2022-02-13 22:33:55 +00:00
|
|
|
v.apply(value);
|
2021-01-08 03:50:09 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
panic!("Attempted to apply non-Tuple type to Tuple type.");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-01-14 19:09:44 +00:00
|
|
|
/// Compares a [`Tuple`] with a [`Reflect`] value.
|
|
|
|
///
|
|
|
|
/// Returns true if and only if all of the following are true:
|
|
|
|
/// - `b` is a tuple;
|
|
|
|
/// - `b` has the same number of elements as `a`;
|
|
|
|
/// - [`Reflect::reflect_partial_eq`] returns `Some(true)` for pairwise elements of `a` and `b`.
|
2021-01-08 03:50:09 +00:00
|
|
|
#[inline]
|
|
|
|
pub fn tuple_partial_eq<T: Tuple>(a: &T, b: &dyn Reflect) -> Option<bool> {
|
|
|
|
let b = if let ReflectRef::Tuple(tuple) = b.reflect_ref() {
|
|
|
|
tuple
|
|
|
|
} else {
|
|
|
|
return Some(false);
|
|
|
|
};
|
|
|
|
|
|
|
|
if a.field_len() != b.field_len() {
|
|
|
|
return Some(false);
|
|
|
|
}
|
|
|
|
|
|
|
|
for (a_field, b_field) in a.iter_fields().zip(b.iter_fields()) {
|
|
|
|
match a_field.reflect_partial_eq(b_field) {
|
|
|
|
Some(false) | None => return Some(false),
|
|
|
|
Some(true) => {}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Some(true)
|
|
|
|
}
|
|
|
|
|
|
|
|
macro_rules! impl_reflect_tuple {
|
|
|
|
{$($index:tt : $name:tt),*} => {
|
|
|
|
impl<$($name: Reflect),*> Tuple for ($($name,)*) {
|
|
|
|
#[inline]
|
|
|
|
fn field(&self, index: usize) -> Option<&dyn Reflect> {
|
|
|
|
match index {
|
|
|
|
$($index => Some(&self.$index as &dyn Reflect),)*
|
|
|
|
_ => None,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
fn field_mut(&mut self, index: usize) -> Option<&mut dyn Reflect> {
|
|
|
|
match index {
|
|
|
|
$($index => Some(&mut self.$index as &mut dyn Reflect),)*
|
|
|
|
_ => None,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
fn field_len(&self) -> usize {
|
|
|
|
let indices: &[usize] = &[$($index as usize),*];
|
|
|
|
indices.len()
|
|
|
|
}
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
fn iter_fields(&self) -> TupleFieldIter {
|
|
|
|
TupleFieldIter {
|
|
|
|
tuple: self,
|
|
|
|
index: 0,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
fn clone_dynamic(&self) -> DynamicTuple {
|
2021-02-02 21:57:26 +00:00
|
|
|
let mut dyn_tuple = DynamicTuple {
|
|
|
|
name: String::default(),
|
2021-01-08 03:50:09 +00:00
|
|
|
fields: self
|
|
|
|
.iter_fields()
|
|
|
|
.map(|value| value.clone_value())
|
|
|
|
.collect(),
|
2021-02-02 21:57:26 +00:00
|
|
|
};
|
|
|
|
dyn_tuple.generate_name();
|
|
|
|
dyn_tuple
|
2021-01-08 03:50:09 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-03-17 22:46:46 +00:00
|
|
|
// SAFE: any and any_mut both return self
|
|
|
|
unsafe impl<$($name: Reflect),*> Reflect for ($($name,)*) {
|
2021-01-08 03:50:09 +00:00
|
|
|
fn type_name(&self) -> &str {
|
|
|
|
std::any::type_name::<Self>()
|
|
|
|
}
|
|
|
|
|
|
|
|
fn any(&self) -> &dyn Any {
|
|
|
|
self
|
|
|
|
}
|
|
|
|
|
|
|
|
fn any_mut(&mut self) -> &mut dyn Any {
|
|
|
|
self
|
|
|
|
}
|
|
|
|
|
2022-04-25 13:54:48 +00:00
|
|
|
fn as_reflect(&self) -> &dyn Reflect {
|
|
|
|
self
|
|
|
|
}
|
|
|
|
|
|
|
|
fn as_reflect_mut(&mut self) -> &mut dyn Reflect {
|
|
|
|
self
|
|
|
|
}
|
|
|
|
|
2021-01-08 03:50:09 +00:00
|
|
|
fn apply(&mut self, value: &dyn Reflect) {
|
|
|
|
crate::tuple_apply(self, value);
|
|
|
|
}
|
|
|
|
|
|
|
|
fn set(&mut self, value: Box<dyn Reflect>) -> Result<(), Box<dyn Reflect>> {
|
|
|
|
*self = value.take()?;
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
fn reflect_ref(&self) -> ReflectRef {
|
|
|
|
ReflectRef::Tuple(self)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn reflect_mut(&mut self) -> ReflectMut {
|
|
|
|
ReflectMut::Tuple(self)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn clone_value(&self) -> Box<dyn Reflect> {
|
|
|
|
Box::new(self.clone_dynamic())
|
|
|
|
}
|
|
|
|
|
|
|
|
fn reflect_partial_eq(&self, value: &dyn Reflect) -> Option<bool> {
|
|
|
|
crate::tuple_partial_eq(self, value)
|
|
|
|
}
|
|
|
|
}
|
Add FromReflect trait to convert dynamic types to concrete types (#1395)
Dynamic types (`DynamicStruct`, `DynamicTupleStruct`, `DynamicTuple`, `DynamicList` and `DynamicMap`) are used when deserializing scenes, but currently they can only be applied to existing concrete types. This leads to issues when trying to spawn non trivial deserialized scene.
For components, the issue is avoided by requiring that reflected components implement ~~`FromResources`~~ `FromWorld` (or `Default`). When spawning, a new concrete type is created that way, and the dynamic type is applied to it. Unfortunately, some components don't have any valid implementation of these traits.
In addition, any `Vec` or `HashMap` inside a component will panic when a dynamic type is pushed into it (for instance, `Text` panics when adding a text section).
To solve this issue, this PR adds the `FromReflect` trait that creates a concrete type from a dynamic type that represent it, derives the trait alongside the `Reflect` trait, drops the ~~`FromResources`~~ `FromWorld` requirement on reflected components, ~~and enables reflection for UI and Text bundles~~. It also adds the requirement that fields ignored with `#[reflect(ignore)]` implement `Default`, since we need to initialize them somehow.
Co-authored-by: Carter Anderson <mcanders1@gmail.com>
2021-12-26 18:49:01 +00:00
|
|
|
|
2022-05-02 18:04:48 +00:00
|
|
|
impl<$($name: Reflect + for<'de> Deserialize<'de>),*> GetTypeRegistration for ($($name,)*) {
|
|
|
|
fn get_type_registration() -> TypeRegistration {
|
|
|
|
let mut registration = TypeRegistration::of::<($($name,)*)>();
|
|
|
|
registration.insert::<ReflectDeserialize>(FromType::<($($name,)*)>::from_type());
|
|
|
|
registration
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
Add FromReflect trait to convert dynamic types to concrete types (#1395)
Dynamic types (`DynamicStruct`, `DynamicTupleStruct`, `DynamicTuple`, `DynamicList` and `DynamicMap`) are used when deserializing scenes, but currently they can only be applied to existing concrete types. This leads to issues when trying to spawn non trivial deserialized scene.
For components, the issue is avoided by requiring that reflected components implement ~~`FromResources`~~ `FromWorld` (or `Default`). When spawning, a new concrete type is created that way, and the dynamic type is applied to it. Unfortunately, some components don't have any valid implementation of these traits.
In addition, any `Vec` or `HashMap` inside a component will panic when a dynamic type is pushed into it (for instance, `Text` panics when adding a text section).
To solve this issue, this PR adds the `FromReflect` trait that creates a concrete type from a dynamic type that represent it, derives the trait alongside the `Reflect` trait, drops the ~~`FromResources`~~ `FromWorld` requirement on reflected components, ~~and enables reflection for UI and Text bundles~~. It also adds the requirement that fields ignored with `#[reflect(ignore)]` implement `Default`, since we need to initialize them somehow.
Co-authored-by: Carter Anderson <mcanders1@gmail.com>
2021-12-26 18:49:01 +00:00
|
|
|
impl<$($name: FromReflect),*> FromReflect for ($($name,)*)
|
|
|
|
{
|
|
|
|
fn from_reflect(reflect: &dyn Reflect) -> Option<Self> {
|
|
|
|
if let ReflectRef::Tuple(_ref_tuple) = reflect.reflect_ref() {
|
|
|
|
Some(
|
|
|
|
(
|
|
|
|
$(
|
|
|
|
<$name as FromReflect>::from_reflect(_ref_tuple.field($index)?)?,
|
|
|
|
)*
|
|
|
|
)
|
|
|
|
)
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2021-01-08 03:50:09 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl_reflect_tuple! {}
|
|
|
|
impl_reflect_tuple! {0: A}
|
|
|
|
impl_reflect_tuple! {0: A, 1: B}
|
|
|
|
impl_reflect_tuple! {0: A, 1: B, 2: C}
|
|
|
|
impl_reflect_tuple! {0: A, 1: B, 2: C, 3: D}
|
|
|
|
impl_reflect_tuple! {0: A, 1: B, 2: C, 3: D, 4: E}
|
|
|
|
impl_reflect_tuple! {0: A, 1: B, 2: C, 3: D, 4: E, 5: F}
|
|
|
|
impl_reflect_tuple! {0: A, 1: B, 2: C, 3: D, 4: E, 5: F, 6: G}
|
|
|
|
impl_reflect_tuple! {0: A, 1: B, 2: C, 3: D, 4: E, 5: F, 6: G, 7: H}
|
|
|
|
impl_reflect_tuple! {0: A, 1: B, 2: C, 3: D, 4: E, 5: F, 6: G, 7: H, 8: I}
|
|
|
|
impl_reflect_tuple! {0: A, 1: B, 2: C, 3: D, 4: E, 5: F, 6: G, 7: H, 8: I, 9: J}
|
|
|
|
impl_reflect_tuple! {0: A, 1: B, 2: C, 3: D, 4: E, 5: F, 6: G, 7: H, 8: I, 9: J, 10: K}
|
|
|
|
impl_reflect_tuple! {0: A, 1: B, 2: C, 3: D, 4: E, 5: F, 6: G, 7: H, 8: I, 9: J, 10: K, 11: L}
|