//! 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},10structs::DynamicStruct,11PartialReflect,12},13};14use serde::de::DeserializeSeed;1516fn main() {17App::new()18.add_plugins(DefaultPlugins)19.add_systems(Startup, setup)20.run();21}2223/// Deriving `Reflect` implements the relevant reflection traits. In this case, it implements the24/// `Reflect` trait and the `Struct` trait `derive(Reflect)` assumes that all fields also implement25/// Reflect.26///27/// All fields in a reflected item will need to be `Reflect` as well. You can opt a field out of28/// reflection by using the `#[reflect(ignore)]` attribute.29/// If you choose to ignore a field, you need to let the automatically-derived `FromReflect` implementation30/// how to handle the field.31/// To do this, you can either define a `#[reflect(default = "...")]` attribute on the ignored field, or32/// opt-out of `FromReflect`'s auto-derive using the `#[reflect(from_reflect = false)]` attribute.33#[derive(Reflect)]34#[reflect(from_reflect = false)]35pub struct Foo {36a: usize,37nested: Bar,38#[reflect(ignore)]39_ignored: NonReflectedValue,40}4142/// This `Bar` type is used in the `nested` field of the `Foo` type. We must derive `Reflect` here43/// too (or ignore it)44#[derive(Reflect)]45pub struct Bar {46b: usize,47}4849#[derive(Default)]50struct NonReflectedValue {51_a: usize,52}5354fn setup(type_registry: Res<AppTypeRegistry>) {55let mut value = Foo {56a: 1,57_ignored: NonReflectedValue { _a: 10 },58nested: Bar { b: 8 },59};6061// You can set field values like this. The type must match exactly or this will fail.62*value.get_field_mut("a").unwrap() = 2usize;63assert_eq!(value.a, 2);64assert_eq!(*value.get_field::<usize>("a").unwrap(), 2);6566// You can also get the `&dyn PartialReflect` value of a field like this67let field = value.field("a").unwrap();6869// But values introspected via `PartialReflect` will not return `dyn Reflect` trait objects70// (even if the containing type does implement `Reflect`), so we need to convert them:71let fully_reflected_field = field.try_as_reflect().unwrap();7273// Now, you can downcast your `Reflect` value like this:74assert_eq!(*fully_reflected_field.downcast_ref::<usize>().unwrap(), 2);7576// For this specific case, we also support the shortcut `try_downcast_ref`:77assert_eq!(*field.try_downcast_ref::<usize>().unwrap(), 2);7879// `DynamicStruct` also implements the `Struct` and `Reflect` traits.80let mut patch = DynamicStruct::default();81patch.insert("a", 4usize);8283// You can "apply" Reflect implementations on top of other Reflect implementations.84// This will only set fields with the same name, and it will fail if the types don't match.85// You can use this to "patch" your types with new values.86value.apply(&patch);87assert_eq!(value.a, 4);8889let type_registry = type_registry.read();90// By default, all derived `Reflect` types can be Serialized using serde. No need to derive91// Serialize!92let serializer = ReflectSerializer::new(&value, &type_registry);93let ron_string =94ron::ser::to_string_pretty(&serializer, ron::ser::PrettyConfig::default()).unwrap();95info!("{}\n", ron_string);9697// Dynamic properties can be deserialized98let reflect_deserializer = ReflectDeserializer::new(&type_registry);99let mut deserializer = ron::de::Deserializer::from_str(&ron_string).unwrap();100let reflect_value = reflect_deserializer.deserialize(&mut deserializer).unwrap();101102// Deserializing returns a `Box<dyn PartialReflect>` value.103// Generally, deserializing a value will return the "dynamic" variant of a type.104// For example, deserializing a struct will return the DynamicStruct type.105// "Opaque types" will be deserialized as themselves.106assert_eq!(107reflect_value.reflect_type_path(),108DynamicStruct::type_path(),109);110111// Reflect has its own `partial_eq` implementation, named `reflect_partial_eq`. This behaves112// like normal `partial_eq`, but it treats "dynamic" and "non-dynamic" types the same. The113// `Foo` struct and deserialized `DynamicStruct` are considered equal for this reason:114assert!(reflect_value.reflect_partial_eq(&value).unwrap());115116// By "patching" `Foo` with the deserialized DynamicStruct, we can "Deserialize" Foo.117// This means we can serialize and deserialize with a single `Reflect` derive!118value.apply(&*reflect_value);119}120121122