//! Illustrates how "reflection" works in Bevy.1//!2//! Reflection provides a way to dynamically interact with Rust types, such as accessing fields3//! by their string name. Reflection is a core part of Bevy and enables a number of interesting4//! features (like scenes).56use bevy::{7prelude::*,8reflect::{9serde::{ReflectDeserializer, ReflectSerializer},10DynamicStruct, PartialReflect,11},12};13use serde::de::DeserializeSeed;1415fn main() {16App::new()17.add_plugins(DefaultPlugins)18.add_systems(Startup, setup)19.run();20}2122/// Deriving `Reflect` implements the relevant reflection traits. In this case, it implements the23/// `Reflect` trait and the `Struct` trait `derive(Reflect)` assumes that all fields also implement24/// Reflect.25///26/// All fields in a reflected item will need to be `Reflect` as well. You can opt a field out of27/// reflection by using the `#[reflect(ignore)]` attribute.28/// If you choose to ignore a field, you need to let the automatically-derived `FromReflect` implementation29/// how to handle the field.30/// To do this, you can either define a `#[reflect(default = "...")]` attribute on the ignored field, or31/// opt-out of `FromReflect`'s auto-derive using the `#[reflect(from_reflect = false)]` attribute.32#[derive(Reflect)]33#[reflect(from_reflect = false)]34pub struct Foo {35a: usize,36nested: Bar,37#[reflect(ignore)]38_ignored: NonReflectedValue,39}4041/// This `Bar` type is used in the `nested` field of the `Foo` type. We must derive `Reflect` here42/// too (or ignore it)43#[derive(Reflect)]44pub struct Bar {45b: usize,46}4748#[derive(Default)]49struct NonReflectedValue {50_a: usize,51}5253fn setup(type_registry: Res<AppTypeRegistry>) {54let mut value = Foo {55a: 1,56_ignored: NonReflectedValue { _a: 10 },57nested: Bar { b: 8 },58};5960// You can set field values like this. The type must match exactly or this will fail.61*value.get_field_mut("a").unwrap() = 2usize;62assert_eq!(value.a, 2);63assert_eq!(*value.get_field::<usize>("a").unwrap(), 2);6465// You can also get the `&dyn PartialReflect` value of a field like this66let field = value.field("a").unwrap();6768// But values introspected via `PartialReflect` will not return `dyn Reflect` trait objects69// (even if the containing type does implement `Reflect`), so we need to convert them:70let fully_reflected_field = field.try_as_reflect().unwrap();7172// Now, you can downcast your `Reflect` value like this:73assert_eq!(*fully_reflected_field.downcast_ref::<usize>().unwrap(), 2);7475// For this specific case, we also support the shortcut `try_downcast_ref`:76assert_eq!(*field.try_downcast_ref::<usize>().unwrap(), 2);7778// `DynamicStruct` also implements the `Struct` and `Reflect` traits.79let mut patch = DynamicStruct::default();80patch.insert("a", 4usize);8182// You can "apply" Reflect implementations on top of other Reflect implementations.83// This will only set fields with the same name, and it will fail if the types don't match.84// You can use this to "patch" your types with new values.85value.apply(&patch);86assert_eq!(value.a, 4);8788let type_registry = type_registry.read();89// By default, all derived `Reflect` types can be Serialized using serde. No need to derive90// Serialize!91let serializer = ReflectSerializer::new(&value, &type_registry);92let ron_string =93ron::ser::to_string_pretty(&serializer, ron::ser::PrettyConfig::default()).unwrap();94info!("{}\n", ron_string);9596// Dynamic properties can be deserialized97let reflect_deserializer = ReflectDeserializer::new(&type_registry);98let mut deserializer = ron::de::Deserializer::from_str(&ron_string).unwrap();99let reflect_value = reflect_deserializer.deserialize(&mut deserializer).unwrap();100101// Deserializing returns a `Box<dyn PartialReflect>` value.102// Generally, deserializing a value will return the "dynamic" variant of a type.103// For example, deserializing a struct will return the DynamicStruct type.104// "Opaque types" will be deserialized as themselves.105assert_eq!(106reflect_value.reflect_type_path(),107DynamicStruct::type_path(),108);109110// Reflect has its own `partial_eq` implementation, named `reflect_partial_eq`. This behaves111// like normal `partial_eq`, but it treats "dynamic" and "non-dynamic" types the same. The112// `Foo` struct and deserialized `DynamicStruct` are considered equal for this reason:113assert!(reflect_value.reflect_partial_eq(&value).unwrap());114115// By "patching" `Foo` with the deserialized DynamicStruct, we can "Deserialize" Foo.116// This means we can serialize and deserialize with a single `Reflect` derive!117value.apply(&*reflect_value);118}119120121