Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bevyengine
GitHub Repository: bevyengine/bevy
Path: blob/main/crates/bevy_reflect/src/from_reflect.rs
6598 views
1
use crate::{FromType, PartialReflect, Reflect};
2
use alloc::boxed::Box;
3
4
/// A trait that enables types to be dynamically constructed from reflected data.
5
///
6
/// It's recommended to use the [derive macro] rather than manually implementing this trait.
7
///
8
/// `FromReflect` allows dynamic proxy types, like [`DynamicStruct`], to be used to generate
9
/// their concrete counterparts.
10
/// It can also be used to partially or fully clone a type (depending on whether it has
11
/// ignored fields or not).
12
///
13
/// In some cases, this trait may even be required.
14
/// Deriving [`Reflect`] on an enum requires all its fields to implement `FromReflect`.
15
/// Additionally, some complex types like `Vec<T>` require that their element types
16
/// implement this trait.
17
/// The reason for such requirements is that some operations require new data to be constructed,
18
/// such as swapping to a new variant or pushing data to a homogeneous list.
19
///
20
/// See the [crate-level documentation] to see how this trait can be used.
21
///
22
/// [derive macro]: bevy_reflect_derive::FromReflect
23
/// [`DynamicStruct`]: crate::DynamicStruct
24
/// [crate-level documentation]: crate
25
#[diagnostic::on_unimplemented(
26
message = "`{Self}` does not implement `FromReflect` so cannot be created through reflection",
27
note = "consider annotating `{Self}` with `#[derive(Reflect)]`"
28
)]
29
pub trait FromReflect: Reflect + Sized {
30
/// Constructs a concrete instance of `Self` from a reflected value.
31
fn from_reflect(reflect: &dyn PartialReflect) -> Option<Self>;
32
33
/// Attempts to downcast the given value to `Self` using,
34
/// constructing the value using [`from_reflect`] if that fails.
35
///
36
/// This method is more efficient than using [`from_reflect`] for cases where
37
/// the given value is likely a boxed instance of `Self` (i.e. `Box<Self>`)
38
/// rather than a boxed dynamic type (e.g. [`DynamicStruct`], [`DynamicList`], etc.).
39
///
40
/// [`from_reflect`]: Self::from_reflect
41
/// [`DynamicStruct`]: crate::DynamicStruct
42
/// [`DynamicList`]: crate::DynamicList
43
fn take_from_reflect(
44
reflect: Box<dyn PartialReflect>,
45
) -> Result<Self, Box<dyn PartialReflect>> {
46
match reflect.try_take::<Self>() {
47
Ok(value) => Ok(value),
48
Err(value) => match Self::from_reflect(value.as_ref()) {
49
None => Err(value),
50
Some(value) => Ok(value),
51
},
52
}
53
}
54
}
55
56
/// Type data that represents the [`FromReflect`] trait and allows it to be used dynamically.
57
///
58
/// `FromReflect` allows dynamic types (e.g. [`DynamicStruct`], [`DynamicEnum`], etc.) to be converted
59
/// to their full, concrete types. This is most important when it comes to deserialization where it isn't
60
/// guaranteed that every field exists when trying to construct the final output.
61
///
62
/// However, to do this, you normally need to specify the exact concrete type:
63
///
64
/// ```
65
/// # use bevy_reflect::{DynamicTupleStruct, FromReflect, Reflect};
66
/// #[derive(Reflect, PartialEq, Eq, Debug)]
67
/// struct Foo(#[reflect(default = "default_value")] usize);
68
///
69
/// fn default_value() -> usize { 123 }
70
///
71
/// let reflected = DynamicTupleStruct::default();
72
///
73
/// let concrete: Foo = <Foo as FromReflect>::from_reflect(&reflected).unwrap();
74
///
75
/// assert_eq!(Foo(123), concrete);
76
/// ```
77
///
78
/// In a dynamic context where the type might not be known at compile-time, this is nearly impossible to do.
79
/// That is why this type data struct exists— it allows us to construct the full type without knowing
80
/// what the actual type is.
81
///
82
/// # Example
83
///
84
/// ```
85
/// # use bevy_reflect::{DynamicTupleStruct, Reflect, ReflectFromReflect, Typed, TypeRegistry, TypePath};
86
/// # #[derive(Reflect, PartialEq, Eq, Debug)]
87
/// # struct Foo(#[reflect(default = "default_value")] usize);
88
/// # fn default_value() -> usize { 123 }
89
/// # let mut registry = TypeRegistry::new();
90
/// # registry.register::<Foo>();
91
///
92
/// let mut reflected = DynamicTupleStruct::default();
93
/// reflected.set_represented_type(Some(<Foo as Typed>::type_info()));
94
///
95
/// let registration = registry.get_with_type_path(<Foo as TypePath>::type_path()).unwrap();
96
/// let rfr = registration.data::<ReflectFromReflect>().unwrap();
97
///
98
/// let concrete: Box<dyn Reflect> = rfr.from_reflect(&reflected).unwrap();
99
///
100
/// assert_eq!(Foo(123), concrete.take::<Foo>().unwrap());
101
/// ```
102
///
103
/// [`DynamicStruct`]: crate::DynamicStruct
104
/// [`DynamicEnum`]: crate::DynamicEnum
105
#[derive(Clone)]
106
pub struct ReflectFromReflect {
107
from_reflect: fn(&dyn PartialReflect) -> Option<Box<dyn Reflect>>,
108
}
109
110
impl ReflectFromReflect {
111
/// Perform a [`FromReflect::from_reflect`] conversion on the given reflection object.
112
///
113
/// This will convert the object to a concrete type if it wasn't already, and return
114
/// the value as `Box<dyn Reflect>`.
115
pub fn from_reflect(&self, reflect_value: &dyn PartialReflect) -> Option<Box<dyn Reflect>> {
116
(self.from_reflect)(reflect_value)
117
}
118
}
119
120
impl<T: FromReflect> FromType<T> for ReflectFromReflect {
121
fn from_type() -> Self {
122
Self {
123
from_reflect: |reflect_value| {
124
T::from_reflect(reflect_value).map(|value| Box::new(value) as Box<dyn Reflect>)
125
},
126
}
127
}
128
}
129
130