mirror of
https://github.com/bevyengine/bevy
synced 2024-12-25 04:23:08 +00:00
cd1737ecca
# Objective
`bevy_reflect` can be a moderately complex crate to try and understand. It has many moving parts, a handful of gotchas, and a few subtle contracts that aren't immediately obvious to users and even other contributors.
The current README does an okay job demonstrating how the crate can be used. However, the crate's actual documentation should give a better overview of the crate, its inner-workings, and show some of its own examples.
## Solution
Added crate-level documentation that attempts to summarize the main parts of `bevy_reflect` into small sections.
This PR also updates the documentation for:
- `Reflect`
- `FromReflect`
- The reflection subtraits
- Other important types and traits
- The reflection macros (including the derive macros)
- Crate features
### Open Questions
1. ~~Should I update the docs for the Dynamic types? I was originally going to, but I'm getting a little concerned about the size of this PR 😅~~ Decided to not do this in this PR. It'll be better served from its own PR.
2. Should derive macro documentation be moved to the trait itself? This could improve visibility and allow for better doc links, but could also clutter up the trait's documentation (as well as not being on the actual derive macro's documentation).
### TODO
- [ ] ~~Document Dynamic types (?)~~ I think this should be done in a separate PR.
- [x] Document crate features
- [x] Update docs for `GetTypeRegistration`
- [x] Update docs for `TypeRegistration`
- [x] Update docs for `derive_from_reflect`
- [x] Document `reflect_trait`
- [x] Document `impl_reflect_value`
- [x] Document `impl_from_reflect_value`
---
## Changelog
- Updated documentation across the `bevy_reflect` crate
- Removed `#[module]` helper attribute for `Reflect` derives (this is not currently used)
## Migration Guide
- Removed `#[module]` helper attribute for `Reflect` derives. If your code is relying on this attribute, please replace it with either `#[reflect]` or `#[reflect_value]` (dependent on use-case).
Co-authored-by: Gino Valente <49806985+MrGVSV@users.noreply.github.com>
123 lines
4.9 KiB
Rust
123 lines
4.9 KiB
Rust
use crate::{FromType, Reflect};
|
|
|
|
/// A trait that enables types to be dynamically constructed from reflected data.
|
|
///
|
|
/// 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
|
|
/// implement this trait.
|
|
/// 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.
|
|
///
|
|
/// [derive macro]: bevy_reflect_derive::FromReflect
|
|
/// [`DynamicStruct`]: crate::DynamicStruct
|
|
/// [crate-level documentation]: crate
|
|
pub trait FromReflect: Reflect + Sized {
|
|
/// Constructs a concrete instance of `Self` from a reflected value.
|
|
fn from_reflect(reflect: &dyn Reflect) -> Option<Self>;
|
|
|
|
/// 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),
|
|
},
|
|
}
|
|
}
|
|
}
|
|
|
|
/// 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>)
|
|
},
|
|
}
|
|
}
|
|
}
|