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. While Rust doesn't yet provide much built-in tooling for reflection, this crate serves to help fill that role. And while 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 # 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`. In other words, 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 of 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`] 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 dynamics 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](bevy_reflect_derive::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 data, 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 they 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`] 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 representing some concrete type (except for value types). Again, it's important to remember that dynamics 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, &registry); let serialized_value: String = ron::to_string(&reflect_serializer).unwrap(); // Deserialize let reflect_deserializer = UntypedReflectDeserializer::new(&registry); 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); ``` [Reflection]: https://en.wikipedia.org/wiki/Reflective_programming [Bevy]: https://bevyengine.org/ [`bevy_reflect`]: crate [runtime cost]: https://doc.rust-lang.org/book/ch17-02-trait-objects.html#trait-objects-perform-dynamic-dispatch [derive macro]: bevy_reflect_derive::Reflect [derive macro documentation]: bevy_reflect_derive::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