Skip to content

Commit b3ce68d

Browse files
committed
Added ReflectFromReflect
1 parent 000e6e2 commit b3ce68d

File tree

3 files changed

+134
-15
lines changed

3 files changed

+134
-15
lines changed
+93
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
use crate::{FromType, Reflect};
2+
3+
/// A trait for types which can be constructed from a reflected type.
4+
///
5+
/// This trait can be derived on types which implement [`Reflect`]. Some complex
6+
/// types (such as `Vec<T>`) may only be reflected if their element types
7+
/// implement this trait.
8+
///
9+
/// For structs and tuple structs, fields marked with the `#[reflect(ignore)]`
10+
/// attribute will be constructed using the `Default` implementation of the
11+
/// field type, rather than the corresponding field value (if any) of the
12+
/// reflected value.
13+
pub trait FromReflect: Reflect + Sized {
14+
/// Constructs a concrete instance of `Self` from a reflected value.
15+
fn from_reflect(reflect: &dyn Reflect) -> Option<Self>;
16+
}
17+
18+
/// Type data that represents the [`FromReflect`] trait and allows it to be used dynamically.
19+
///
20+
/// `FromReflect` allows dynamic types (e.g. [`DynamicStruct`], [`DynamicEnum`], etc.) to be converted
21+
/// to their full, concrete types. This is most important when it comes to deserialization where it isn't
22+
/// guaranteed that every field exists when trying to construct the final output.
23+
///
24+
/// However, to do this, you normally need to specify the exact concrete type:
25+
///
26+
/// ```
27+
/// # use bevy_reflect::{DynamicTupleStruct, FromReflect, Reflect};
28+
/// #[derive(Reflect, FromReflect, PartialEq, Eq, Debug)]
29+
/// #[reflect(FromReflect)]
30+
/// struct Foo(#[reflect(default = "default_value")] usize);
31+
///
32+
/// fn default_value() -> usize { 123 }
33+
///
34+
/// let reflected = DynamicTupleStruct::default();
35+
///
36+
/// let concrete: Foo = <Foo as FromReflect>::from_reflect(&reflected).unwrap();
37+
///
38+
/// assert_eq!(Foo(123), concrete);
39+
/// ```
40+
///
41+
/// In a dynamic context where the type might not be known at compile-time, this is nearly impossible to do.
42+
/// That is why this type data struct exists— it allows us to construct the full type without knowing
43+
/// what the actual type is.
44+
///
45+
/// # Example
46+
///
47+
/// ```
48+
/// # use bevy_reflect::{DynamicTupleStruct, FromReflect, Reflect, ReflectFromReflect, TypeRegistry};
49+
/// # #[derive(Reflect, FromReflect, PartialEq, Eq, Debug)]
50+
/// # #[reflect(FromReflect)]
51+
/// # struct Foo(#[reflect(default = "default_value")] usize);
52+
/// # fn default_value() -> usize { 123 }
53+
/// # let mut registry = TypeRegistry::new();
54+
/// # registry.register::<Foo>();
55+
///
56+
/// let mut reflected = DynamicTupleStruct::default();
57+
/// reflected.set_name(std::any::type_name::<Foo>().to_string());
58+
///
59+
/// let registration = registry.get_with_name(reflected.type_name()).unwrap();
60+
/// let rfr = registration.data::<ReflectFromReflect>().unwrap();
61+
///
62+
/// let concrete: Box<dyn Reflect> = rfr.from_reflect(&reflected).unwrap();
63+
///
64+
/// assert_eq!(Foo(123), concrete.take::<Foo>().unwrap());
65+
/// ```
66+
///
67+
/// [`DynamicStruct`]: crate::DynamicStruct
68+
/// [`DynamicEnum`]: crate::DynamicEnum
69+
#[derive(Clone)]
70+
pub struct ReflectFromReflect {
71+
from_reflect: fn(&dyn Reflect) -> Option<Box<dyn Reflect>>,
72+
}
73+
74+
impl ReflectFromReflect {
75+
/// Perform a [`FromReflect::from_reflect`] conversion on the given reflection object.
76+
///
77+
/// This will convert the object to a concrete type if it wasn't already, and return
78+
/// the value as `Box<dyn Reflect>`.
79+
#[allow(clippy::wrong_self_convention)]
80+
pub fn from_reflect(&self, reflect_value: &dyn Reflect) -> Option<Box<dyn Reflect>> {
81+
(self.from_reflect)(reflect_value)
82+
}
83+
}
84+
85+
impl<T: FromReflect + Reflect> FromType<T> for ReflectFromReflect {
86+
fn from_type() -> Self {
87+
Self {
88+
from_reflect: |reflect_value| {
89+
T::from_reflect(reflect_value).map(|value| Box::new(value) as Box<dyn Reflect>)
90+
},
91+
}
92+
}
93+
}

crates/bevy_reflect/src/lib.rs

+39
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
mod array;
44
mod fields;
5+
mod from_reflect;
56
mod list;
67
mod map;
78
mod path;
@@ -47,6 +48,7 @@ pub mod prelude {
4748
pub use array::*;
4849
pub use enums::*;
4950
pub use fields::*;
51+
pub use from_reflect::*;
5052
pub use impls::*;
5153
pub use list::*;
5254
pub use map::*;
@@ -103,6 +105,7 @@ mod tests {
103105
ser::{to_string_pretty, PrettyConfig},
104106
Deserializer,
105107
};
108+
use std::any::TypeId;
106109
use std::fmt::{Debug, Formatter};
107110

108111
use super::prelude::*;
@@ -244,6 +247,42 @@ mod tests {
244247
assert_eq!(values, vec![1]);
245248
}
246249

250+
#[test]
251+
fn should_call_from_reflect_dynamically() {
252+
#[derive(Reflect, FromReflect)]
253+
#[reflect(FromReflect)]
254+
struct MyStruct {
255+
foo: usize,
256+
}
257+
258+
// Register
259+
let mut registry = TypeRegistry::default();
260+
registry.register::<MyStruct>();
261+
262+
// Get type data
263+
let type_id = TypeId::of::<MyStruct>();
264+
let rfr = registry
265+
.get_type_data::<ReflectFromReflect>(type_id)
266+
.expect("the FromReflect trait should be registered");
267+
268+
// Call from_reflect
269+
let mut dynamic_struct = DynamicStruct::default();
270+
dynamic_struct.insert("foo", 123usize);
271+
let reflected = rfr
272+
.from_reflect(&dynamic_struct)
273+
.expect("the type should be properly reflected");
274+
275+
// Assert
276+
let expected = MyStruct { foo: 123 };
277+
assert!(expected
278+
.reflect_partial_eq(reflected.as_ref())
279+
.unwrap_or_default());
280+
let not_expected = MyStruct { foo: 321 };
281+
assert!(!not_expected
282+
.reflect_partial_eq(reflected.as_ref())
283+
.unwrap_or_default());
284+
}
285+
247286
#[test]
248287
fn from_reflect_should_use_default_field_attributes() {
249288
#[derive(Reflect, FromReflect, Eq, PartialEq, Debug)]

crates/bevy_reflect/src/reflect.rs

+2-15
Original file line numberDiff line numberDiff line change
@@ -190,21 +190,6 @@ pub trait Reflect: Any + Send + Sync {
190190
}
191191
}
192192

193-
/// A trait for types which can be constructed from a reflected type.
194-
///
195-
/// This trait can be derived on types which implement [`Reflect`]. Some complex
196-
/// types (such as `Vec<T>`) may only be reflected if their element types
197-
/// implement this trait.
198-
///
199-
/// For structs and tuple structs, fields marked with the `#[reflect(ignore)]`
200-
/// attribute will be constructed using the `Default` implementation of the
201-
/// field type, rather than the corresponding field value (if any) of the
202-
/// reflected value.
203-
pub trait FromReflect: Reflect + Sized {
204-
/// Constructs a concrete instance of `Self` from a reflected value.
205-
fn from_reflect(reflect: &dyn Reflect) -> Option<Self>;
206-
}
207-
208193
impl Debug for dyn Reflect {
209194
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
210195
self.debug(f)
@@ -255,6 +240,8 @@ impl dyn Reflect {
255240
/// a different type, like the Dynamic\*\*\* types do, you can call `represents`
256241
/// to determine what type they represent. Represented types cannot be downcasted
257242
/// to, but you can use [`FromReflect`] to create a value of the represented type from them.
243+
///
244+
/// [`FromReflect`]: crate::FromReflect
258245
#[inline]
259246
pub fn is<T: Reflect>(&self) -> bool {
260247
self.type_id() == TypeId::of::<T>()

0 commit comments

Comments
 (0)