mirror of
https://github.com/bevyengine/bevy
synced 2024-11-10 15:14:50 +00:00
bevy_reflect: Improved documentation (#7148)
# 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>
This commit is contained in:
parent
78b67906c9
commit
cd1737ecca
13 changed files with 848 additions and 86 deletions
|
@ -41,7 +41,89 @@ use type_uuid::TypeUuidDef;
|
|||
pub(crate) static REFLECT_ATTRIBUTE_NAME: &str = "reflect";
|
||||
pub(crate) static REFLECT_VALUE_ATTRIBUTE_NAME: &str = "reflect_value";
|
||||
|
||||
#[proc_macro_derive(Reflect, attributes(reflect, reflect_value, module))]
|
||||
/// The main derive macro used by `bevy_reflect` for deriving its `Reflect` trait.
|
||||
///
|
||||
/// This macro can be used on all structs and enums (unions are not supported).
|
||||
/// It will automatically generate the implementations for `Reflect`, `Typed`, and `GetTypeRegistration`.
|
||||
/// And, depending on the item's structure, will either implement `Struct`, `TupleStruct`, or `Enum`.
|
||||
///
|
||||
/// # Container Attributes
|
||||
///
|
||||
/// This macro comes with some helper attributes that can be added to the container item
|
||||
/// in order to provide additional functionality or alter the generated implementations.
|
||||
///
|
||||
/// ## `#[reflect(Ident)]`
|
||||
///
|
||||
/// The `#[reflect(Ident)]` attribute is used to add type data registrations to the `GetTypeRegistration`
|
||||
/// implementation corresponding to the given identifier, prepended by `Reflect`.
|
||||
///
|
||||
/// For example, `#[reflect(Foo, Bar)]` would add two registrations:
|
||||
/// one for `ReflectFoo` and another for `ReflectBar`.
|
||||
/// This assumes these types are indeed in-scope wherever this macro is called.
|
||||
///
|
||||
/// This is often used with traits that have been marked by the [`#[reflect_trait]`](macro@reflect_trait)
|
||||
/// macro in order to register the type's implementation of that trait.
|
||||
///
|
||||
/// ### Special Identifiers
|
||||
///
|
||||
/// There are a few "special" identifiers that work a bit differently:
|
||||
///
|
||||
/// * `#[reflect(Debug)]` will force the implementation of `Reflect::reflect_debug` to rely on
|
||||
/// the type's [`Debug`] implementation.
|
||||
/// A custom implementation may be provided using `#[reflect(Debug(my_debug_func))]` where
|
||||
/// `my_debug_func` is the path to a function matching the signature:
|
||||
/// `(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result`.
|
||||
/// * `#[reflect(PartialEq)]` will force the implementation of `Reflect::reflect_partial_eq` to rely on
|
||||
/// the type's [`PartialEq`] implementation.
|
||||
/// A custom implementation may be provided using `#[reflect(PartialEq(my_partial_eq_func))]` where
|
||||
/// `my_partial_eq_func` is the path to a function matching the signature:
|
||||
/// `(&self, value: &dyn #bevy_reflect_path::Reflect) -> bool`.
|
||||
/// * `#[reflect(Hash)]` will force the implementation of `Reflect::reflect_hash` to rely on
|
||||
/// the type's [`Hash`] implementation.
|
||||
/// A custom implementation may be provided using `#[reflect(Hash(my_hash_func))]` where
|
||||
/// `my_hash_func` is the path to a function matching the signature: `(&self) -> u64`.
|
||||
/// * `#[reflect(Default)]` will register the `ReflectDefault` type data as normal.
|
||||
/// However, it will also affect how certain other operations are performed in order
|
||||
/// to improve performance and/or robustness.
|
||||
/// An example of where this is used is in the [`FromReflect`] derive macro,
|
||||
/// where adding this attribute will cause the `FromReflect` implementation to create
|
||||
/// a base value using its [`Default`] implementation avoiding issues with ignored fields.
|
||||
///
|
||||
/// ## `#[reflect_value]`
|
||||
///
|
||||
/// The `#[reflect_value]` attribute (which may also take the form `#[reflect_value(Ident)]`),
|
||||
/// denotes that the item should implement `Reflect` as though it were a base value type.
|
||||
/// This means that it will forgo implementing `Struct`, `TupleStruct`, or `Enum`.
|
||||
///
|
||||
/// Furthermore, it requires that the type implements [`Clone`].
|
||||
/// If planning to serialize this type using the reflection serializers,
|
||||
/// then the `Serialize` and `Deserialize` traits will need to be implemented and registered as well.
|
||||
///
|
||||
/// # Field Attributes
|
||||
///
|
||||
/// Along with the container attributes, this macro comes with some attributes that may be applied
|
||||
/// to the contained fields themselves.
|
||||
///
|
||||
/// ## `#[reflect(ignore)]`
|
||||
///
|
||||
/// This attribute simply marks a field to be ignored by the reflection API.
|
||||
///
|
||||
/// This allows fields to completely opt-out of reflection,
|
||||
/// which may be useful for maintaining invariants, keeping certain data private,
|
||||
/// or allowing the use of types that do not implement `Reflect` within the container.
|
||||
///
|
||||
/// ## `#[reflect(skip_serializing)]`
|
||||
///
|
||||
/// This works similar to `#[reflect(ignore)]`, but rather than opting out of _all_ of reflection,
|
||||
/// it simply opts the field out of both serialization and deserialization.
|
||||
/// This can be useful when a field should be accessible via reflection, but may not make
|
||||
/// sense in a serialized form, such as computed data.
|
||||
///
|
||||
/// What this does is register the `SerializationData` type within the `GetTypeRegistration` implementation,
|
||||
/// which will be used by the reflection serializers to determine whether or not the field is serializable.
|
||||
///
|
||||
/// [`reflect_trait`]: macro@reflect_trait
|
||||
#[proc_macro_derive(Reflect, attributes(reflect, reflect_value))]
|
||||
pub fn derive_reflect(input: TokenStream) -> TokenStream {
|
||||
let ast = parse_macro_input!(input as DeriveInput);
|
||||
|
||||
|
@ -62,11 +144,30 @@ pub fn derive_reflect(input: TokenStream) -> TokenStream {
|
|||
|
||||
/// Derives the `FromReflect` trait.
|
||||
///
|
||||
/// This macro supports the following field attributes:
|
||||
/// * `#[reflect(ignore)]`: Ignores the field. This requires the field to implement [`Default`].
|
||||
/// * `#[reflect(default)]`: If the field's value cannot be read, uses its [`Default`] implementation.
|
||||
/// * `#[reflect(default = "some_func")]`: If the field's value cannot be read, uses the function with the given name.
|
||||
/// # Field Attributes
|
||||
///
|
||||
/// ## `#[reflect(ignore)]`
|
||||
///
|
||||
/// The `#[reflect(ignore)]` attribute is shared with the [`#[derive(Reflect)]`](Reflect) macro and has much of the same
|
||||
/// functionality in that it denotes that a field will be ignored by the reflection API.
|
||||
///
|
||||
/// The only major difference is that using it with this derive requires that the field implements [`Default`].
|
||||
/// Without this requirement, there would be no way for `FromReflect` to automatically construct missing fields
|
||||
/// that have been ignored.
|
||||
///
|
||||
/// ## `#[reflect(default)]`
|
||||
///
|
||||
/// If a field cannot be read, this attribute specifies a default value to be used in its place.
|
||||
///
|
||||
/// By default, this attribute denotes that the field's type implements [`Default`].
|
||||
/// However, it can also take in a path string to a user-defined function that will return the default value.
|
||||
/// This takes the form: `#[reflect(default = "path::to::my_function)]` where `my_function` is a parameterless
|
||||
/// function that must return some default value for the type.
|
||||
///
|
||||
/// Specifying a custom default can be used to give different fields their own specialized defaults,
|
||||
/// or to remove the `Default` requirement on fields marked with `#[reflect(ignore)]`.
|
||||
/// Additionally, either form of this attribute can be used to fill in fields that are simply missing,
|
||||
/// such as when converting a partially-constructed dynamic type to a concrete one.
|
||||
#[proc_macro_derive(FromReflect, attributes(reflect))]
|
||||
pub fn derive_from_reflect(input: TokenStream) -> TokenStream {
|
||||
let ast = parse_macro_input!(input as DeriveInput);
|
||||
|
@ -92,11 +193,82 @@ pub fn derive_type_uuid(input: TokenStream) -> TokenStream {
|
|||
type_uuid::type_uuid_derive(input)
|
||||
}
|
||||
|
||||
/// A macro that automatically generates type data for traits, which their implementors can then register.
|
||||
///
|
||||
/// The output of this macro is a struct that takes reflected instances of the implementor's type
|
||||
/// and returns the value as a trait object.
|
||||
/// Because of this, **it can only be used on [object-safe] traits.**
|
||||
///
|
||||
/// For a trait named `MyTrait`, this will generate the struct `ReflectMyTrait`.
|
||||
/// The generated struct can be created using `FromType` with any type that implements the trait.
|
||||
/// The creation and registration of this generated struct as type data can be automatically handled
|
||||
/// by [`#[derive(Reflect)]`](Reflect).
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```ignore
|
||||
/// # use std::any::TypeId;
|
||||
/// # use bevy_reflect_derive::{Reflect, reflect_trait};
|
||||
/// #[reflect_trait] // Generates `ReflectMyTrait`
|
||||
/// trait MyTrait {
|
||||
/// fn print(&self) -> &str;
|
||||
/// }
|
||||
///
|
||||
/// #[derive(Reflect)]
|
||||
/// #[reflect(MyTrait)] // Automatically registers `ReflectMyTrait`
|
||||
/// struct SomeStruct;
|
||||
///
|
||||
/// impl MyTrait for SomeStruct {
|
||||
/// fn print(&self) -> &str {
|
||||
/// "Hello, World!"
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
/// // We can create the type data manually if we wanted:
|
||||
/// let my_trait: ReflectMyTrait = FromType::<SomeStruct>::from_type();
|
||||
///
|
||||
/// // Or we can simply get it from the registry:
|
||||
/// let mut registry = TypeRegistry::default();
|
||||
/// registry.register::<SomeStruct>();
|
||||
/// let my_trait = registry
|
||||
/// .get_type_data::<ReflectMyTrait>(TypeId::of::<SomeStruct>())
|
||||
/// .unwrap();
|
||||
///
|
||||
/// // Then use it on reflected data
|
||||
/// let reflected: Box<dyn Reflect> = Box::new(SomeStruct);
|
||||
/// let reflected_my_trait: &dyn MyTrait = my_trait.get(&*reflected).unwrap();
|
||||
/// assert_eq!("Hello, World!", reflected_my_trait.print());
|
||||
/// ```
|
||||
///
|
||||
/// [object-safe]: https://doc.rust-lang.org/reference/items/traits.html#object-safety
|
||||
#[proc_macro_attribute]
|
||||
pub fn reflect_trait(args: TokenStream, input: TokenStream) -> TokenStream {
|
||||
trait_reflection::reflect_trait(&args, input)
|
||||
}
|
||||
|
||||
/// A macro used to generate reflection trait implementations for the given type.
|
||||
///
|
||||
/// This is functionally the same as [deriving `Reflect`] using the `#[reflect_value]` container attribute.
|
||||
///
|
||||
/// The only reason for this macro's existence is so that `bevy_reflect` can easily implement the reflection traits
|
||||
/// on primitives and other Rust types internally.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Types can be passed with or without registering type data:
|
||||
///
|
||||
/// ```ignore
|
||||
/// impl_reflect_value!(foo);
|
||||
/// impl_reflect_value!(bar(Debug, Default, Serialize, Deserialize));
|
||||
/// ```
|
||||
///
|
||||
/// Generic types can also specify their parameters and bounds:
|
||||
///
|
||||
/// ```ignore
|
||||
/// impl_reflect_value!(foo<T1, T2: Baz> where T1: Bar (Default, Serialize, Deserialize));
|
||||
/// ```
|
||||
///
|
||||
/// [deriving `Reflect`]: Reflect
|
||||
#[proc_macro]
|
||||
pub fn impl_reflect_value(input: TokenStream) -> TokenStream {
|
||||
let def = parse_macro_input!(input as ReflectValueDef);
|
||||
|
@ -178,6 +350,22 @@ pub fn impl_reflect_struct(input: TokenStream) -> TokenStream {
|
|||
}
|
||||
}
|
||||
|
||||
/// A macro used to generate a `FromReflect` trait implementation for the given type.
|
||||
///
|
||||
/// This is functionally the same as [deriving `FromReflect`] on a type that [derives `Reflect`] using
|
||||
/// the `#[reflect_value]` container attribute.
|
||||
///
|
||||
/// The only reason this macro exists is so that `bevy_reflect` can easily implement `FromReflect` on
|
||||
/// primitives and other Rust types internally.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```ignore
|
||||
/// impl_from_reflect_value!(foo<T1, T2: Baz> where T1: Bar);
|
||||
/// ```
|
||||
///
|
||||
/// [deriving `FromReflect`]: FromReflect
|
||||
/// [derives `Reflect`]: Reflect
|
||||
#[proc_macro]
|
||||
pub fn impl_from_reflect_value(input: TokenStream) -> TokenStream {
|
||||
let def = parse_macro_input!(input as ReflectValueDef);
|
||||
|
|
|
@ -8,16 +8,41 @@ use std::{
|
|||
hash::{Hash, Hasher},
|
||||
};
|
||||
|
||||
/// A static-sized array of [`Reflect`] items.
|
||||
/// A trait used to power [array-like] operations via [reflection].
|
||||
///
|
||||
/// This corresponds to types like `[T; N]` (arrays).
|
||||
/// This corresponds to true Rust arrays like `[T; N]`,
|
||||
/// but also to any fixed-size linear sequence types.
|
||||
/// It is expected that implementors of this trait uphold this contract
|
||||
/// and maintain a fixed size as returned by the [`Array::len`] method.
|
||||
///
|
||||
/// Currently, this only supports arrays of up to 32 items. It can technically
|
||||
/// contain more than 32, but the blanket [`GetTypeRegistration`] is only
|
||||
/// implemented up to the 32 item limit due to a [limitation] on `Deserialize`.
|
||||
/// Due to the [type-erasing] nature of the reflection API as a whole,
|
||||
/// this trait does not make any guarantees that the implementor's elements
|
||||
/// are homogenous (i.e. all the same type).
|
||||
///
|
||||
/// This trait has a blanket implementation over Rust arrays of up to 32 items.
|
||||
/// This implementation can technically contain more than 32,
|
||||
/// but the blanket [`GetTypeRegistration`] is only implemented up to the 32
|
||||
/// item limit due to a [limitation] on [`Deserialize`].
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// use bevy_reflect::{Reflect, Array};
|
||||
///
|
||||
/// let foo: &dyn Array = &[123_u32, 456_u32, 789_u32];
|
||||
/// assert_eq!(foo.len(), 3);
|
||||
///
|
||||
/// let field: &dyn Reflect = foo.get(0).unwrap();
|
||||
/// assert_eq!(field.downcast_ref::<u32>(), Some(&123));
|
||||
/// ```
|
||||
///
|
||||
/// [array-like]: https://doc.rust-lang.org/book/ch03-02-data-types.html#the-array-type
|
||||
/// [reflection]: crate
|
||||
/// [`List`]: crate::List
|
||||
/// [type-erasing]: https://doc.rust-lang.org/book/ch17-02-trait-objects.html
|
||||
/// [`GetTypeRegistration`]: crate::GetTypeRegistration
|
||||
/// [limitation]: https://github.com/serde-rs/serde/issues/1937
|
||||
/// [`Deserialize`]: ::serde::Deserialize
|
||||
pub trait Array: Reflect {
|
||||
/// Returns a reference to the element at `index`, or `None` if out of bounds.
|
||||
fn get(&self, index: usize) -> Option<&dyn Reflect>;
|
||||
|
|
|
@ -3,7 +3,7 @@ use bevy_utils::HashMap;
|
|||
use std::any::{Any, TypeId};
|
||||
use std::slice::Iter;
|
||||
|
||||
/// A trait representing a [reflected] enum.
|
||||
/// A trait used to power [enum-like] operations via [reflection].
|
||||
///
|
||||
/// This allows enums to be processed and modified dynamically at runtime without
|
||||
/// necessarily knowing the actual type.
|
||||
|
@ -39,7 +39,7 @@ use std::slice::Iter;
|
|||
///
|
||||
/// # Implementation
|
||||
///
|
||||
/// > 💡 This trait can be automatically implemented using the [`Reflect`] derive macro
|
||||
/// > 💡 This trait can be automatically implemented using [`#[derive(Reflect)]`](derive@crate::Reflect)
|
||||
/// > on an enum definition.
|
||||
///
|
||||
/// Despite the fact that enums can represent multiple states, traits only exist in one state
|
||||
|
@ -52,7 +52,7 @@ use std::slice::Iter;
|
|||
/// accessing fields!
|
||||
/// Again, this is to account for _all three_ variant types.
|
||||
///
|
||||
/// We recommend using the built-in [`Reflect`] derive macro to automatically handle all the
|
||||
/// We recommend using the built-in [`#[derive(Reflect)]`](derive@crate::Reflect) macro to automatically handle all the
|
||||
/// implementation details for you.
|
||||
/// However, if you _must_ implement this trait manually, there are a few things to keep in mind...
|
||||
///
|
||||
|
@ -82,7 +82,8 @@ use std::slice::Iter;
|
|||
/// It's preferred that these strings be converted to their proper `usize` representations and
|
||||
/// the [`Enum::field_at[_mut]`](Enum::field_at) methods be used instead.
|
||||
///
|
||||
/// [reflected]: crate
|
||||
/// [enum-like]: https://doc.rust-lang.org/book/ch06-01-defining-an-enum.html
|
||||
/// [reflection]: crate
|
||||
/// [`None`]: core::option::Option<T>::None
|
||||
/// [`Some`]: core::option::Option<T>::Some
|
||||
/// [`Reflect`]: bevy_reflect_derive::Reflect
|
||||
|
|
|
@ -1,15 +1,26 @@
|
|||
use crate::{FromType, Reflect};
|
||||
|
||||
/// A trait for types which can be constructed from a reflected type.
|
||||
/// A trait that enables types to be dynamically constructed from reflected data.
|
||||
///
|
||||
/// This trait can be derived on types which implement [`Reflect`]. Some complex
|
||||
/// types (such as `Vec<T>`) may only be reflected if their element types
|
||||
/// 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.
|
||||
///
|
||||
/// For structs and tuple structs, fields marked with the `#[reflect(ignore)]`
|
||||
/// attribute will be constructed using the `Default` implementation of the
|
||||
/// field type, rather than the corresponding field value (if any) of the
|
||||
/// reflected value.
|
||||
/// 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>;
|
||||
|
|
|
@ -1,4 +1,440 @@
|
|||
#![doc = include_str!("../README.md")]
|
||||
//! Reflection in Rust.
|
||||
//!
|
||||
//! [Reflection] is a powerful tool provided within many programming languages
|
||||
//! that allows for meta-programming: using information _about_ the program to
|
||||
//! _affect_ the program.
|
||||
//! In other words, reflection allows us to inspect the program itself, its
|
||||
//! syntax, and its type information at runtime.
|
||||
//!
|
||||
//! This crate adds this missing reflection functionality to Rust.
|
||||
//! Though it was made with the [Bevy] game engine in mind,
|
||||
//! it's a general-purpose solution that can be used in any Rust project.
|
||||
//!
|
||||
//! At a very high level, this crate allows you to:
|
||||
//! * Dynamically interact with Rust values
|
||||
//! * Access type metadata at runtime
|
||||
//! * Serialize and deserialize (i.e. save and load) data
|
||||
//!
|
||||
//! It's important to note that because of missing features in Rust,
|
||||
//! there are some [limitations] with this crate.
|
||||
//!
|
||||
//! # The `Reflect` Trait
|
||||
//!
|
||||
//! At the core of [`bevy_reflect`] is the [`Reflect`] trait.
|
||||
//!
|
||||
//! One of its primary purposes is to allow all implementors to be passed around
|
||||
//! as a `dyn Reflect` trait object.
|
||||
//! This allows any such type to be operated upon completely dynamically (at a small [runtime cost]).
|
||||
//!
|
||||
//! Implementing the trait is easily done using the provided [derive macro]:
|
||||
//!
|
||||
//! ```
|
||||
//! # use bevy_reflect::Reflect;
|
||||
//! #[derive(Reflect)]
|
||||
//! struct MyStruct {
|
||||
//! foo: i32
|
||||
//! }
|
||||
//! ```
|
||||
//!
|
||||
//! This will automatically generate the implementation of `Reflect` for any struct or enum.
|
||||
//!
|
||||
//! It will also generate other very important trait implementations used for reflection:
|
||||
//! * [`GetTypeRegistration`]
|
||||
//! * [`Typed`]
|
||||
//! * [`Struct`], [`TupleStruct`], or [`Enum`] depending on the type
|
||||
//!
|
||||
//! ## Requirements
|
||||
//!
|
||||
//! We can implement `Reflect` on any type that satisfies _both_ of the following conditions:
|
||||
//! * The type implements `Any`.
|
||||
//! This is true if and only if the type itself has a [`'static` lifetime].
|
||||
//! * All fields and sub-elements themselves implement `Reflect`
|
||||
//! (see the [derive macro documentation] for details on how to ignore certain fields when deriving).
|
||||
//!
|
||||
//! Additionally, using the derive macro on enums requires a third condition to be met:
|
||||
//! * All fields and sub-elements must implement [`FromReflect`]—
|
||||
//! another important reflection trait discussed in a later section.
|
||||
//!
|
||||
//! # The `Reflect` Subtraits
|
||||
//!
|
||||
//! Since [`Reflect`] is meant to cover any and every type, this crate also comes with a few
|
||||
//! more traits to accompany `Reflect` and provide more specific interactions.
|
||||
//! We refer to these traits as the _reflection subtraits_ since they all have `Reflect` as a supertrait.
|
||||
//! The current list of reflection subtraits include:
|
||||
//! * [`Tuple`]
|
||||
//! * [`Array`]
|
||||
//! * [`List`]
|
||||
//! * [`Map`]
|
||||
//! * [`Struct`]
|
||||
//! * [`TupleStruct`]
|
||||
//! * [`Enum`]
|
||||
//!
|
||||
//! As mentioned previously, the last three are automatically implemented by the [derive macro].
|
||||
//!
|
||||
//! Each of these traits come with their own methods specific to their respective category.
|
||||
//! For example, we can access our struct's fields by name using the [`Struct::field`] method.
|
||||
//!
|
||||
//! ```
|
||||
//! # use bevy_reflect::{Reflect, Struct};
|
||||
//! # #[derive(Reflect)]
|
||||
//! # struct MyStruct {
|
||||
//! # foo: i32
|
||||
//! # }
|
||||
//! let my_struct: Box<dyn Struct> = Box::new(MyStruct {
|
||||
//! foo: 123
|
||||
//! });
|
||||
//! let foo: &dyn Reflect = my_struct.field("foo").unwrap();
|
||||
//! assert_eq!(Some(&123), foo.downcast_ref::<i32>());
|
||||
//! ```
|
||||
//!
|
||||
//! Since most data is passed around as `dyn Reflect`,
|
||||
//! the `Reflect` trait has methods for going to and from these subtraits.
|
||||
//!
|
||||
//! [`Reflect::reflect_ref`], [`Reflect::reflect_mut`], and [`Reflect::reflect_owned`] all return
|
||||
//! an enum that respectively contains immutable, mutable, and owned access to the type as a subtrait object.
|
||||
//!
|
||||
//! For example, we can get out a `dyn Tuple` from our reflected tuple type using one of these methods.
|
||||
//!
|
||||
//! ```
|
||||
//! # use bevy_reflect::{Reflect, ReflectRef};
|
||||
//! let my_tuple: Box<dyn Reflect> = Box::new((1, 2, 3));
|
||||
//! let ReflectRef::Tuple(my_tuple) = my_tuple.reflect_ref() else { unreachable!() };
|
||||
//! assert_eq!(3, my_tuple.field_len());
|
||||
//! ```
|
||||
//!
|
||||
//! And to go back to a general-purpose `dyn Reflect`,
|
||||
//! we can just use the matching [`Reflect::as_reflect`], [`Reflect::as_reflect_mut`],
|
||||
//! or [`Reflect::into_reflect`] methods.
|
||||
//!
|
||||
//! ## Value Types
|
||||
//!
|
||||
//! Types that do not fall under one of the above subtraits,
|
||||
//! such as for primitives (e.g. `bool`, `usize`, etc.)
|
||||
//! and simple types (e.g. `String`, `Duration`),
|
||||
//! are referred to as _value_ types
|
||||
//! since methods like [`Reflect::reflect_ref`] return a [`ReflectRef::Value`] variant.
|
||||
//! While most other types contain their own `dyn Reflect` fields and data,
|
||||
//! these types generally cannot be broken down any further.
|
||||
//!
|
||||
//! # Dynamic Types
|
||||
//!
|
||||
//! Each subtrait comes with a corresponding _dynamic_ type.
|
||||
//!
|
||||
//! The available dynamic types are:
|
||||
//! * [`DynamicTuple`]
|
||||
//! * [`DynamicArray`]
|
||||
//! * [`DynamicList`]
|
||||
//! * [`DynamicMap`]
|
||||
//! * [`DynamicStruct`]
|
||||
//! * [`DynamicTupleStruct`]
|
||||
//! * [`DynamicEnum`]
|
||||
//!
|
||||
//! These dynamic types may contain any arbitrary reflected data.
|
||||
//!
|
||||
//! ```
|
||||
//! # use bevy_reflect::{DynamicStruct, Struct};
|
||||
//! let mut data = DynamicStruct::default();
|
||||
//! data.insert("foo", 123_i32);
|
||||
//! assert_eq!(Some(&123), data.field("foo").unwrap().downcast_ref::<i32>())
|
||||
//! ```
|
||||
//!
|
||||
//! They are most commonly used as "proxies" for other types,
|
||||
//! where they contain the same data as— and therefore, represent— a concrete type.
|
||||
//! The [`Reflect::clone_value`] method will return a dynamic type for all non-value types,
|
||||
//! allowing all types to essentially be "cloned".
|
||||
//! And since dynamic types themselves implement [`Reflect`],
|
||||
//! we may pass them around just like any other reflected type.
|
||||
//!
|
||||
//! ```
|
||||
//! # use bevy_reflect::{DynamicStruct, Reflect};
|
||||
//! # #[derive(Reflect)]
|
||||
//! # struct MyStruct {
|
||||
//! # foo: i32
|
||||
//! # }
|
||||
//! let original: Box<dyn Reflect> = Box::new(MyStruct {
|
||||
//! foo: 123
|
||||
//! });
|
||||
//!
|
||||
//! // `cloned` will be a `DynamicStruct` representing a `MyStruct`
|
||||
//! let cloned: Box<dyn Reflect> = original.clone_value();
|
||||
//! assert!(cloned.represents::<MyStruct>());
|
||||
//! assert!(cloned.is::<DynamicStruct>());
|
||||
//! ```
|
||||
//!
|
||||
//! ## Patching
|
||||
//!
|
||||
//! These dynamic types come in handy when needing to apply multiple changes to another type.
|
||||
//! This is known as "patching" and is done using the [`Reflect::apply`] method.
|
||||
//!
|
||||
//! ```
|
||||
//! # use bevy_reflect::{DynamicEnum, Reflect};
|
||||
//! let mut value = Some(123_i32);
|
||||
//! let patch = DynamicEnum::new(std::any::type_name::<Option<i32>>(), "None", ());
|
||||
//! value.apply(&patch);
|
||||
//! assert_eq!(None, value);
|
||||
//! ```
|
||||
//!
|
||||
//! ## `FromReflect`
|
||||
//!
|
||||
//! It's important to remember that dynamic types are _not_ the concrete type they may be representing.
|
||||
//! A common mistake is to treat them like such when trying to cast back to the original type
|
||||
//! or when trying to make use of a reflected trait which expects the actual type.
|
||||
//!
|
||||
//! ```should_panic
|
||||
//! # use bevy_reflect::{DynamicStruct, Reflect};
|
||||
//! # #[derive(Reflect)]
|
||||
//! # struct MyStruct {
|
||||
//! # foo: i32
|
||||
//! # }
|
||||
//! let original: Box<dyn Reflect> = Box::new(MyStruct {
|
||||
//! foo: 123
|
||||
//! });
|
||||
//!
|
||||
//! let cloned: Box<dyn Reflect> = original.clone_value();
|
||||
//! let value = cloned.take::<MyStruct>().unwrap(); // PANIC!
|
||||
//! ```
|
||||
//!
|
||||
//! To resolve this issue, we'll need to convert the dynamic type to the concrete one.
|
||||
//! This is where [`FromReflect`] comes in.
|
||||
//!
|
||||
//! `FromReflect` is a derivable trait that allows an instance of a type to be generated from a
|
||||
//! dynamic representation— even partial ones.
|
||||
//! And since the [`FromReflect::from_reflect`] method takes the data by reference,
|
||||
//! this can be used to effectively clone data (to an extent).
|
||||
//!
|
||||
//! This trait can be derived on any type whose fields and sub-elements also implement `FromReflect`.
|
||||
//!
|
||||
//! ```
|
||||
//! # use bevy_reflect::{Reflect, FromReflect};
|
||||
//! #[derive(Reflect, FromReflect)]
|
||||
//! struct MyStruct {
|
||||
//! foo: i32
|
||||
//! }
|
||||
//! let original: Box<dyn Reflect> = Box::new(MyStruct {
|
||||
//! foo: 123
|
||||
//! });
|
||||
//!
|
||||
//! let cloned: Box<dyn Reflect> = original.clone_value();
|
||||
//! let value = <MyStruct as FromReflect>::from_reflect(&*cloned).unwrap(); // OK!
|
||||
//! ```
|
||||
//!
|
||||
//! With the derive macro, fields can be ignored or given default values for when a field is missing
|
||||
//! in the passed value.
|
||||
//! See the [derive macro documentation](derive@crate::FromReflect) for details.
|
||||
//!
|
||||
//! All primitives and simple types implement `FromReflect` by relying on their [`Default`] implementation.
|
||||
//!
|
||||
//! # Type Registration
|
||||
//!
|
||||
//! This crate also comes with a [`TypeRegistry`] that can be used to store and retrieve additional type metadata at runtime,
|
||||
//! such as helper types and trait implementations.
|
||||
//!
|
||||
//! The [derive macro] for [`Reflect`] also generates an implementation of the [`GetTypeRegistration`] trait,
|
||||
//! which is used by the registry to generate a [`TypeRegistration`] struct for that type.
|
||||
//! We can then register additional [type data] we want associated with that type.
|
||||
//!
|
||||
//! For example, we can register [`ReflectDefault`] on our type so that its `Default` implementation
|
||||
//! may be used dynamically.
|
||||
//!
|
||||
//! ```
|
||||
//! # use bevy_reflect::{Reflect, TypeRegistry, prelude::ReflectDefault};
|
||||
//! #[derive(Reflect, Default)]
|
||||
//! struct MyStruct {
|
||||
//! foo: i32
|
||||
//! }
|
||||
//! let mut registry = TypeRegistry::empty();
|
||||
//! registry.register::<MyStruct>();
|
||||
//! registry.register_type_data::<MyStruct, ReflectDefault>();
|
||||
//!
|
||||
//! let registration = registry.get(std::any::TypeId::of::<MyStruct>()).unwrap();
|
||||
//! let reflect_default = registration.data::<ReflectDefault>().unwrap();
|
||||
//!
|
||||
//! let new_value: Box<dyn Reflect> = reflect_default.default();
|
||||
//! assert!(new_value.is::<MyStruct>());
|
||||
//! ```
|
||||
//!
|
||||
//! Because this operation is so common, the derive macro actually has a shorthand for it.
|
||||
//! By using the `#[reflect(Trait)]` attribute, the derive macro will automatically register a matching,
|
||||
//! in-scope `ReflectTrait` type within the `GetTypeRegistration` implementation.
|
||||
//!
|
||||
//! ```
|
||||
//! use bevy_reflect::prelude::{Reflect, ReflectDefault};
|
||||
//!
|
||||
//! #[derive(Reflect, Default)]
|
||||
//! #[reflect(Default)]
|
||||
//! struct MyStruct {
|
||||
//! foo: i32
|
||||
//! }
|
||||
//! ```
|
||||
//!
|
||||
//! ## Reflecting Traits
|
||||
//!
|
||||
//! Type data doesn't have to be tied to a trait, but it's often extremely useful to create trait type data.
|
||||
//! These allow traits to be used directly on a `dyn Reflect` while utilizing the underlying type's implementation.
|
||||
//!
|
||||
//! For any [object-safe] trait, we can easily generate a corresponding `ReflectTrait` type for our trait
|
||||
//! using the [`#[reflect_trait]`](reflect_trait) macro.
|
||||
//!
|
||||
//! ```
|
||||
//! # use bevy_reflect::{Reflect, reflect_trait, TypeRegistry};
|
||||
//! #[reflect_trait] // Generates a `ReflectMyTrait` type
|
||||
//! pub trait MyTrait {}
|
||||
//! impl<T: Reflect> MyTrait for T {}
|
||||
//!
|
||||
//! let mut registry = TypeRegistry::new();
|
||||
//! registry.register_type_data::<i32, ReflectMyTrait>();
|
||||
//! ```
|
||||
//!
|
||||
//! The generated type data can be used to convert a valid `dyn Reflect` into a `dyn MyTrait`.
|
||||
//! See the [trait reflection example](https://github.com/bevyengine/bevy/blob/latest/examples/reflection/trait_reflection.rs)
|
||||
//! for more information and usage details.
|
||||
//!
|
||||
//! # Serialization
|
||||
//!
|
||||
//! By using reflection, we are also able to get serialization capabilities for free.
|
||||
//! In fact, using [`bevy_reflect`] can result in faster compile times and reduced code generation over
|
||||
//! directly deriving the [`serde`] traits.
|
||||
//!
|
||||
//! The way it works is by moving the serialization logic into common serializers and deserializers:
|
||||
//! * [`ReflectSerializer`]
|
||||
//! * [`TypedReflectSerializer`]
|
||||
//! * [`UntypedReflectDeserializer`]
|
||||
//! * [`TypedReflectDeserializer`]
|
||||
//!
|
||||
//! All of these structs require a reference to the [registry] so that [type information] can be retrieved,
|
||||
//! as well as registered type data, such as [`ReflectSerialize`] and [`ReflectDeserialize`].
|
||||
//!
|
||||
//! The general entry point are the "untyped" versions of these structs.
|
||||
//! These will automatically extract the type information and pass them into their respective "typed" version.
|
||||
//!
|
||||
//! The output of the `ReflectSerializer` will be a map, where the key is the [type name]
|
||||
//! and the value is the serialized data.
|
||||
//! The `TypedReflectSerializer` will simply output the serialized data.
|
||||
//!
|
||||
//! The `UntypedReflectDeserializer` can be used to deserialize this map and return a `Box<dyn Reflect>`,
|
||||
//! where the underlying type will be a dynamic type representing some concrete type (except for value types).
|
||||
//!
|
||||
//! Again, it's important to remember that dynamic types may need to be converted to their concrete counterparts
|
||||
//! in order to be used in certain cases.
|
||||
//! This can be achieved using [`FromReflect`].
|
||||
//!
|
||||
//! ```
|
||||
//! # use serde::de::DeserializeSeed;
|
||||
//! # use bevy_reflect::{
|
||||
//! # serde::{ReflectSerializer, UntypedReflectDeserializer},
|
||||
//! # Reflect, FromReflect, TypeRegistry
|
||||
//! # };
|
||||
//! #[derive(Reflect, FromReflect, PartialEq, Debug)]
|
||||
//! struct MyStruct {
|
||||
//! foo: i32
|
||||
//! }
|
||||
//!
|
||||
//! let original_value = MyStruct {
|
||||
//! foo: 123
|
||||
//! };
|
||||
//!
|
||||
//! // Register
|
||||
//! let mut registry = TypeRegistry::new();
|
||||
//! registry.register::<MyStruct>();
|
||||
//!
|
||||
//! // Serialize
|
||||
//! let reflect_serializer = ReflectSerializer::new(&original_value, ®istry);
|
||||
//! let serialized_value: String = ron::to_string(&reflect_serializer).unwrap();
|
||||
//!
|
||||
//! // Deserialize
|
||||
//! let reflect_deserializer = UntypedReflectDeserializer::new(®istry);
|
||||
//! let deserialized_value: Box<dyn Reflect> = reflect_deserializer.deserialize(
|
||||
//! &mut ron::Deserializer::from_str(&serialized_value).unwrap()
|
||||
//! ).unwrap();
|
||||
//!
|
||||
//! // Convert
|
||||
//! let converted_value = <MyStruct as FromReflect>::from_reflect(&*deserialized_value).unwrap();
|
||||
//!
|
||||
//! assert_eq!(original_value, converted_value);
|
||||
//! ```
|
||||
//!
|
||||
//! # Limitations
|
||||
//!
|
||||
//! While this crate offers a lot in terms of adding reflection to Rust,
|
||||
//! it does come with some limitations that don't make it as featureful as reflection
|
||||
//! in other programming languages.
|
||||
//!
|
||||
//! ## Non-Static Lifetimes
|
||||
//!
|
||||
//! One of the most obvious limitations is the `'static` requirement.
|
||||
//! Rust requires fields to define a lifetime for referenced data,
|
||||
//! but [`Reflect`] requires all types to have a `'static` lifetime.
|
||||
//! This makes it impossible to reflect any type with non-static borrowed data.
|
||||
//!
|
||||
//! ## Function Reflection
|
||||
//!
|
||||
//! Another limitation is the inability to fully reflect functions and methods.
|
||||
//! Most languages offer some way of calling methods dynamically,
|
||||
//! but Rust makes this very difficult to do.
|
||||
//! For non-generic methods, this can be done by registering custom [type data] that
|
||||
//! contains function pointers.
|
||||
//! For generic methods, the same can be done but will typically require manual monomorphization
|
||||
//! (i.e. manually specifying the types the generic method can take).
|
||||
//!
|
||||
//! ## Manual Registration
|
||||
//!
|
||||
//! Since Rust doesn't provide built-in support for running initialization code before `main`,
|
||||
//! there is no way for `bevy_reflect` to automatically register types into the [type registry].
|
||||
//! This means types must manually be registered, including their desired monomorphized
|
||||
//! representations if generic.
|
||||
//!
|
||||
//! # Features
|
||||
//!
|
||||
//! ## `bevy`
|
||||
//!
|
||||
//! | Default | Dependencies |
|
||||
//! | :-----: | :---------------------------------------: |
|
||||
//! | ❌ | [`bevy_math`], [`glam`], [`smallvec`] |
|
||||
//!
|
||||
//! This feature makes it so that the appropriate reflection traits are implemented on all the types
|
||||
//! necessary for the [Bevy] game engine.
|
||||
//! enables the optional dependencies: [`bevy_math`], [`glam`], and [`smallvec`].
|
||||
//! These dependencies are used by the [Bevy] game engine and must define their reflection implementations
|
||||
//! within this crate due to Rust's [orphan rule].
|
||||
//!
|
||||
//! ## `documentation`
|
||||
//!
|
||||
//! | Default | Dependencies |
|
||||
//! | :-----: | :-------------------------------------------: |
|
||||
//! | ❌ | [`bevy_reflect_derive/documentation`] |
|
||||
//!
|
||||
//! This feature enables capturing doc comments as strings for items that [derive `Reflect`].
|
||||
//! Documentation information can then be accessed at runtime on the [`TypeInfo`] of that item.
|
||||
//!
|
||||
//! This can be useful for generating documentation for scripting language interop or
|
||||
//! for displaying tooltips in an editor.
|
||||
//!
|
||||
//! [Reflection]: https://en.wikipedia.org/wiki/Reflective_programming
|
||||
//! [Bevy]: https://bevyengine.org/
|
||||
//! [limitations]: #limitations
|
||||
//! [`bevy_reflect`]: crate
|
||||
//! [runtime cost]: https://doc.rust-lang.org/book/ch17-02-trait-objects.html#trait-objects-perform-dynamic-dispatch
|
||||
//! [derive macro]: derive@crate::Reflect
|
||||
//! [`'static` lifetime]: https://doc.rust-lang.org/rust-by-example/scope/lifetime/static_lifetime.html#trait-bound
|
||||
//! [derive macro documentation]: derive@crate::Reflect
|
||||
//! [type data]: TypeData
|
||||
//! [`ReflectDefault`]: std_traits::ReflectDefault
|
||||
//! [object-safe]: https://doc.rust-lang.org/reference/items/traits.html#object-safety
|
||||
//! [`serde`]: ::serde
|
||||
//! [`ReflectSerializer`]: serde::ReflectSerializer
|
||||
//! [`TypedReflectSerializer`]: serde::TypedReflectSerializer
|
||||
//! [`UntypedReflectDeserializer`]: serde::UntypedReflectDeserializer
|
||||
//! [`TypedReflectDeserializer`]: serde::TypedReflectDeserializer
|
||||
//! [registry]: TypeRegistry
|
||||
//! [type information]: TypeInfo
|
||||
//! [type name]: Reflect::type_name
|
||||
//! [type registry]: TypeRegistry
|
||||
//! [`bevy_math`]: https://docs.rs/bevy_math/latest/bevy_math/
|
||||
//! [`glam`]: https://docs.rs/glam/latest/glam/
|
||||
//! [`smallvec`]: https://docs.rs/smallvec/latest/smallvec/
|
||||
//! [orphan rule]: https://doc.rust-lang.org/book/ch10-02-traits.html#implementing-a-trait-on-a-type:~:text=But%20we%20can%E2%80%99t,implementation%20to%20use.
|
||||
//! [`bevy_reflect_derive/documentation`]: bevy_reflect_derive
|
||||
//! [derive `Reflect`]: derive@crate::Reflect
|
||||
|
||||
mod array;
|
||||
mod fields;
|
||||
|
|
|
@ -7,19 +7,44 @@ use crate::{
|
|||
DynamicInfo, FromReflect, Reflect, ReflectMut, ReflectOwned, ReflectRef, TypeInfo, Typed,
|
||||
};
|
||||
|
||||
/// An ordered, mutable list of [Reflect] items. This corresponds to types like [`std::vec::Vec`].
|
||||
/// A trait used to power [list-like] operations via [reflection].
|
||||
///
|
||||
/// Unlike the [`Array`](crate::Array) trait, implementors of this type are not expected to
|
||||
/// This corresponds to types, like [`Vec`], which contain an ordered sequence
|
||||
/// of elements that implement [`Reflect`].
|
||||
///
|
||||
/// Unlike the [`Array`](crate::Array) trait, implementors of this trait are not expected to
|
||||
/// maintain a constant length.
|
||||
/// Methods like [insertion](List::insert) and [removal](List::remove) explicitly allow for their
|
||||
/// internal size to change.
|
||||
///
|
||||
/// This trait expects index 0 to contain the _front_ element.
|
||||
/// The _back_ element must refer to the element with the largest index.
|
||||
/// These two rules above should be upheld by manual implementors.
|
||||
///
|
||||
/// [`push`](List::push) and [`pop`](List::pop) have default implementations,
|
||||
/// however it may be faster to implement them manually.
|
||||
/// however it will generally be more performant to implement them manually
|
||||
/// as the default implementation uses a very naive approach to find the correct position.
|
||||
///
|
||||
/// This trait expects its elements to be ordered linearly from front to back.
|
||||
/// The _front_ element starts at index 0 with the _back_ element ending at the largest index.
|
||||
/// This contract above should be upheld by any manual implementors.
|
||||
///
|
||||
/// Due to the [type-erasing] nature of the reflection API as a whole,
|
||||
/// this trait does not make any guarantees that the implementor's elements
|
||||
/// are homogenous (i.e. all the same type).
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// use bevy_reflect::{Reflect, List};
|
||||
///
|
||||
/// let foo: &mut dyn List = &mut vec![123_u32, 456_u32, 789_u32];
|
||||
/// assert_eq!(foo.len(), 3);
|
||||
///
|
||||
/// let last_field: Box<dyn Reflect> = foo.pop().unwrap();
|
||||
/// assert_eq!(last_field.downcast_ref::<u32>(), Some(&789));
|
||||
/// ```
|
||||
///
|
||||
/// [list-like]: https://doc.rust-lang.org/book/ch08-01-vectors.html
|
||||
/// [reflection]: crate
|
||||
/// [`Vec`]: std::vec::Vec
|
||||
/// [type-erasing]: https://doc.rust-lang.org/book/ch17-02-trait-objects.html
|
||||
pub trait List: Reflect {
|
||||
/// Returns a reference to the element at `index`, or `None` if out of bounds.
|
||||
fn get(&self, index: usize) -> Option<&dyn Reflect>;
|
||||
|
|
|
@ -7,16 +7,38 @@ use bevy_utils::{Entry, HashMap};
|
|||
use crate::utility::NonGenericTypeInfoCell;
|
||||
use crate::{DynamicInfo, Reflect, ReflectMut, ReflectOwned, ReflectRef, TypeInfo, Typed};
|
||||
|
||||
/// An ordered mapping between [`Reflect`] values.
|
||||
/// A trait used to power [map-like] operations via [reflection].
|
||||
///
|
||||
/// Because the values are reflected, the underlying types of keys and values
|
||||
/// may differ between entries.
|
||||
/// Maps contain zero or more entries of a key and its associated value,
|
||||
/// and correspond to types like [`HashMap`].
|
||||
/// The order of these entries is not guaranteed by this trait.
|
||||
///
|
||||
///`ReflectValue` `Keys` are assumed to return a non-`None` hash. The ordering
|
||||
/// of `Map` entries is not guaranteed to be stable across runs or between
|
||||
/// instances.
|
||||
/// # Hashing
|
||||
///
|
||||
/// This trait corresponds to types like [`std::collections::HashMap`].
|
||||
/// All keys are expected to return a valid hash value from [`Reflect::reflect_hash`].
|
||||
/// If using the [`#[derive(Reflect)]`](derive@crate::Reflect) macro, this can be done by adding `#[reflect(Hash)]`
|
||||
/// to the entire struct or enum.
|
||||
/// This is true even for manual implementors who do not use the hashed value,
|
||||
/// as it is still relied on by [`DynamicMap`].
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// use bevy_reflect::{Reflect, Map};
|
||||
/// use bevy_utils::HashMap;
|
||||
///
|
||||
///
|
||||
/// let foo: &mut dyn Map = &mut HashMap::<u32, bool>::new();
|
||||
/// foo.insert_boxed(Box::new(123_u32), Box::new(true));
|
||||
/// assert_eq!(foo.len(), 1);
|
||||
///
|
||||
/// let field: &dyn Reflect = foo.get(&123_u32).unwrap();
|
||||
/// assert_eq!(field.downcast_ref::<bool>(), Some(&true));
|
||||
/// ```
|
||||
///
|
||||
/// [map-like]: https://doc.rust-lang.org/book/ch08-03-hash-maps.html
|
||||
/// [reflection]: crate
|
||||
/// [`HashMap`]: bevy_utils::HashMap
|
||||
pub trait Map: Reflect {
|
||||
/// Returns a reference to the value associated with the given key.
|
||||
///
|
||||
|
|
|
@ -61,13 +61,17 @@ pub enum ReflectOwned {
|
|||
Value(Box<dyn Reflect>),
|
||||
}
|
||||
|
||||
/// A reflected Rust type.
|
||||
/// The core trait of [`bevy_reflect`], used for accessing and modifying data dynamically.
|
||||
///
|
||||
/// Methods for working with particular kinds of Rust type are available using the [`Array`], [`List`],
|
||||
/// [`Map`], [`Tuple`], [`TupleStruct`], [`Struct`], and [`Enum`] subtraits.
|
||||
/// It's recommended to use the [derive macro] rather than manually implementing this trait.
|
||||
/// Doing so will automatically implement many other useful traits for reflection,
|
||||
/// including one of the appropriate subtraits: [`Struct`], [`TupleStruct`] or [`Enum`].
|
||||
///
|
||||
/// When using `#[derive(Reflect)]` on a struct, tuple struct or enum, the suitable subtrait for that
|
||||
/// type (`Struct`, `TupleStruct` or `Enum`) is derived automatically.
|
||||
/// See the [crate-level documentation] to see how this trait and its subtraits can be used.
|
||||
///
|
||||
/// [`bevy_reflect`]: crate
|
||||
/// [derive macro]: bevy_reflect_derive::Reflect
|
||||
/// [crate-level documentation]: crate
|
||||
pub trait Reflect: Any + Send + Sync {
|
||||
/// Returns the [type name][std::any::type_name] of the underlying type.
|
||||
fn type_name(&self) -> &str;
|
||||
|
|
|
@ -10,13 +10,14 @@ use std::{
|
|||
slice::Iter,
|
||||
};
|
||||
|
||||
/// A reflected Rust regular struct type.
|
||||
/// A trait used to power [struct-like] operations via [reflection].
|
||||
///
|
||||
/// Implementors of this trait allow their fields to be addressed by name as
|
||||
/// well as by index.
|
||||
/// This trait uses the [`Reflect`] trait to allow implementors to have their fields
|
||||
/// be dynamically addressed by both name and index.
|
||||
///
|
||||
/// This trait is automatically implemented for `struct` types with named fields
|
||||
/// when using `#[derive(Reflect)]`.
|
||||
/// When using [`#[derive(Reflect)]`](derive@crate::Reflect) on a standard struct,
|
||||
/// this trait will be automatically implemented.
|
||||
/// This goes for [unit structs] as well.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
|
@ -25,19 +26,22 @@ use std::{
|
|||
///
|
||||
/// #[derive(Reflect)]
|
||||
/// struct Foo {
|
||||
/// bar: String,
|
||||
/// bar: u32,
|
||||
/// }
|
||||
///
|
||||
/// # fn main() {
|
||||
/// let foo = Foo { bar: "Hello, world!".to_string() };
|
||||
/// let foo = Foo { bar: 123 };
|
||||
///
|
||||
/// assert_eq!(foo.field_len(), 1);
|
||||
/// assert_eq!(foo.name_at(0), Some("bar"));
|
||||
///
|
||||
/// let bar = foo.field("bar").unwrap();
|
||||
/// assert_eq!(bar.downcast_ref::<String>(), Some(&"Hello, world!".to_string()));
|
||||
/// # }
|
||||
/// let field: &dyn Reflect = foo.field("bar").unwrap();
|
||||
/// assert_eq!(field.downcast_ref::<u32>(), Some(&123));
|
||||
/// ```
|
||||
///
|
||||
/// [struct-like]: https://doc.rust-lang.org/book/ch05-01-defining-structs.html
|
||||
/// [reflection]: crate
|
||||
|
||||
/// [unit structs]: https://doc.rust-lang.org/book/ch05-01-defining-structs.html#unit-like-structs-without-any-fields
|
||||
pub trait Struct: Reflect {
|
||||
/// Returns a reference to the value of the field named `name` as a `&dyn
|
||||
/// Reflect`.
|
||||
|
@ -68,7 +72,7 @@ pub trait Struct: Reflect {
|
|||
fn clone_dynamic(&self) -> DynamicStruct;
|
||||
}
|
||||
|
||||
/// A container for compile-time struct info.
|
||||
/// A container for compile-time named struct info.
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct StructInfo {
|
||||
name: &'static str,
|
||||
|
|
|
@ -7,7 +7,10 @@ use std::any::{Any, TypeId};
|
|||
use std::fmt::{Debug, Formatter};
|
||||
use std::slice::Iter;
|
||||
|
||||
/// A reflected Rust tuple.
|
||||
/// A trait used to power [tuple-like] operations via [reflection].
|
||||
///
|
||||
/// This trait uses the [`Reflect`] trait to allow implementors to have their fields
|
||||
/// be dynamically addressed by index.
|
||||
///
|
||||
/// This trait is automatically implemented for arbitrary tuples of up to 12
|
||||
/// elements, provided that each element implements [`Reflect`].
|
||||
|
@ -15,16 +18,17 @@ use std::slice::Iter;
|
|||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// use bevy_reflect::Tuple;
|
||||
/// use bevy_reflect::{Reflect, Tuple};
|
||||
///
|
||||
/// # fn main() {
|
||||
/// let foo = ("blue".to_string(), 42_i32);
|
||||
/// let foo = (123_u32, true);
|
||||
/// assert_eq!(foo.field_len(), 2);
|
||||
///
|
||||
/// let first = foo.field(0).unwrap();
|
||||
/// assert_eq!(first.downcast_ref::<String>(), Some(&"blue".to_string()));
|
||||
/// # }
|
||||
/// let field: &dyn Reflect = foo.field(0).unwrap();
|
||||
/// assert_eq!(field.downcast_ref::<u32>(), Some(&123));
|
||||
/// ```
|
||||
///
|
||||
/// [tuple-like]: https://doc.rust-lang.org/book/ch03-02-data-types.html#the-tuple-type
|
||||
/// [reflection]: crate
|
||||
pub trait Tuple: Reflect {
|
||||
/// Returns a reference to the value of the field with index `index` as a
|
||||
/// `&dyn Reflect`.
|
||||
|
|
|
@ -6,29 +6,32 @@ use std::any::{Any, TypeId};
|
|||
use std::fmt::{Debug, Formatter};
|
||||
use std::slice::Iter;
|
||||
|
||||
/// A reflected Rust tuple struct.
|
||||
/// A trait used to power [tuple struct-like] operations via [reflection].
|
||||
///
|
||||
/// Implementors of this trait allow their tuple fields to be addressed by
|
||||
/// index.
|
||||
/// This trait uses the [`Reflect`] trait to allow implementors to have their fields
|
||||
/// be dynamically addressed by index.
|
||||
///
|
||||
/// This trait is automatically implemented for tuple struct types when using
|
||||
/// `#[derive(Reflect)]`.
|
||||
/// When using [`#[derive(Reflect)]`](derive@crate::Reflect) on a tuple struct,
|
||||
/// this trait will be automatically implemented.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// use bevy_reflect::{Reflect, TupleStruct};
|
||||
///
|
||||
/// #[derive(Reflect)]
|
||||
/// struct Foo(String);
|
||||
/// struct Foo(u32);
|
||||
///
|
||||
/// # fn main() {
|
||||
/// let foo = Foo("Hello, world!".to_string());
|
||||
/// let foo = Foo(123);
|
||||
///
|
||||
/// assert_eq!(foo.field_len(), 1);
|
||||
///
|
||||
/// let first = foo.field(0).unwrap();
|
||||
/// assert_eq!(first.downcast_ref::<String>(), Some(&"Hello, world!".to_string()));
|
||||
/// # }
|
||||
/// let field: &dyn Reflect = foo.field(0).unwrap();
|
||||
/// assert_eq!(field.downcast_ref::<u32>(), Some(&123));
|
||||
/// ```
|
||||
///
|
||||
/// [tuple struct-like]: https://doc.rust-lang.org/book/ch05-01-defining-structs.html#using-tuple-structs-without-named-fields-to-create-different-types
|
||||
/// [reflection]: crate
|
||||
pub trait TupleStruct: Reflect {
|
||||
/// Returns a reference to the value of the field with index `index` as a
|
||||
/// `&dyn Reflect`.
|
||||
|
|
|
@ -5,7 +5,7 @@ use std::any::{Any, TypeId};
|
|||
|
||||
/// A static accessor to compile-time type information.
|
||||
///
|
||||
/// This trait is automatically implemented by the `#[derive(Reflect)]` macro
|
||||
/// This trait is automatically implemented by the [`#[derive(Reflect)]`](derive@crate::Reflect) macro
|
||||
/// and allows type information to be processed without an instance of that type.
|
||||
///
|
||||
/// # Implementing
|
||||
|
|
|
@ -6,7 +6,18 @@ use parking_lot::{RwLock, RwLockReadGuard, RwLockWriteGuard};
|
|||
use serde::Deserialize;
|
||||
use std::{any::TypeId, fmt::Debug, sync::Arc};
|
||||
|
||||
/// A registry of reflected types.
|
||||
/// A registry of [reflected] types.
|
||||
///
|
||||
/// This struct is used as the central store for type information.
|
||||
/// [Registering] a type will generate a new [`TypeRegistration`] entry in this store
|
||||
/// using a type's [`GetTypeRegistration`] implementation
|
||||
/// (which is automatically implemented when using [`#[derive(Reflect)]`](derive@crate::Reflect)).
|
||||
///
|
||||
/// See the [crate-level documentation] for more information.
|
||||
///
|
||||
/// [reflected]: crate
|
||||
/// [Registering]: TypeRegistry::register
|
||||
/// [crate-level documentation]: crate
|
||||
pub struct TypeRegistry {
|
||||
registrations: HashMap<TypeId, TypeRegistration>,
|
||||
short_name_to_id: HashMap<String, TypeId>,
|
||||
|
@ -28,9 +39,15 @@ impl Debug for TypeRegistryArc {
|
|||
}
|
||||
}
|
||||
|
||||
/// A trait which allows a type to generate its [`TypeRegistration`].
|
||||
/// A trait which allows a type to generate its [`TypeRegistration`]
|
||||
/// for registration into the [`TypeRegistry`].
|
||||
///
|
||||
/// This trait is automatically implemented for types which derive [`Reflect`].
|
||||
/// This trait is automatically implemented for items using [`#[derive(Reflect)]`](derive@crate::Reflect).
|
||||
/// The macro also allows [`TypeData`] to be more easily registered.
|
||||
///
|
||||
/// See the [crate-level documentation] for more information on type registration.
|
||||
///
|
||||
/// [crate-level documentation]: crate
|
||||
pub trait GetTypeRegistration {
|
||||
fn get_type_registration() -> TypeRegistration;
|
||||
}
|
||||
|
@ -257,19 +274,32 @@ impl TypeRegistryArc {
|
|||
}
|
||||
}
|
||||
|
||||
/// A record of data about a type.
|
||||
/// Runtime storage for type metadata, registered into the [`TypeRegistry`].
|
||||
///
|
||||
/// This contains the [`TypeInfo`] of the type, as well as its [short name].
|
||||
/// An instance of `TypeRegistration` can be created using the [`TypeRegistration::of`] method,
|
||||
/// but is more often automatically generated using [`#[derive(Reflect)]`](derive@crate::Reflect) which itself generates
|
||||
/// an implementation of the [`GetTypeRegistration`] trait.
|
||||
///
|
||||
/// For each trait specified by the [`#[reflect(_)]`][0] attribute of
|
||||
/// [`#[derive(Reflect)]`][1] on the registered type, this record also contains
|
||||
/// a [`TypeData`] which can be used to downcast [`Reflect`] trait objects of
|
||||
/// this type to trait objects of the relevant trait.
|
||||
/// Along with the type's [`TypeInfo`] and [short name],
|
||||
/// this struct also contains a type's registered [`TypeData`].
|
||||
///
|
||||
/// See the [crate-level documentation] for more information on type registration.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// # use bevy_reflect::{TypeRegistration, std_traits::ReflectDefault, FromType};
|
||||
/// let mut registration = TypeRegistration::of::<Option<String>>();
|
||||
///
|
||||
/// assert_eq!("core::option::Option<alloc::string::String>", registration.type_name());
|
||||
/// assert_eq!("Option<String>", registration.short_name());
|
||||
///
|
||||
/// registration.insert::<ReflectDefault>(FromType::<Option<String>>::from_type());
|
||||
/// assert!(registration.data::<ReflectDefault>().is_some())
|
||||
/// ```
|
||||
///
|
||||
/// [short name]: bevy_utils::get_short_name
|
||||
/// [`TypeInfo`]: crate::TypeInfo
|
||||
/// [0]: crate::Reflect
|
||||
/// [1]: crate::Reflect
|
||||
/// [crate-level documentation]: crate
|
||||
pub struct TypeRegistration {
|
||||
short_name: String,
|
||||
data: HashMap<TypeId, Box<dyn TypeData>>,
|
||||
|
@ -365,9 +395,18 @@ impl Clone for TypeRegistration {
|
|||
}
|
||||
}
|
||||
}
|
||||
/// A trait for types generated by the [`#[reflect_trait]`][0] attribute macro.
|
||||
|
||||
/// A trait used to type-erase type metadata.
|
||||
///
|
||||
/// [0]: crate::reflect_trait
|
||||
/// Type data can be registered to the [`TypeRegistry`] and stored on a type's [`TypeRegistration`].
|
||||
///
|
||||
/// While type data is often generated using the [`#[reflect_trait]`](crate::reflect_trait) macro,
|
||||
/// almost any type that implements [`Clone`] can be considered "type data".
|
||||
/// This is because it has a blanket implementation over all `T` where `T: Clone + Send + Sync + 'static`.
|
||||
///
|
||||
/// See the [crate-level documentation] for more information on type data and type registration.
|
||||
///
|
||||
/// [crate-level documentation]: crate
|
||||
pub trait TypeData: Downcast + Send + Sync {
|
||||
fn clone_type_data(&self) -> Box<dyn TypeData>;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue