docs/bevy/examples/reflection/reflection.rs 4.7 K · 120 lines · raw · history
| 1 | //! Illustrates how "reflection" works in Bevy. |
| 2 | //! |
| 3 | //! Reflection provides a way to dynamically interact with Rust types, such as accessing fields |
| 4 | //! by their string name. Reflection is a core part of Bevy and enables a number of interesting |
| 5 | //! features (like scenes). |
| 6 | |
| 7 | use bevy::{ |
| 8 | prelude::*, |
| 9 | reflect::{ |
| 10 | serde::{ReflectDeserializer, ReflectSerializer}, |
| 11 | structs::DynamicStruct, |
| 12 | PartialReflect, |
| 13 | }, |
| 14 | }; |
| 15 | use serde::de::DeserializeSeed; |
| 16 | |
| 17 | fn main() { |
| 18 | App::new() |
| 19 | .add_plugins(DefaultPlugins) |
| 20 | .add_systems(Startup, setup) |
| 21 | .run(); |
| 22 | } |
| 23 | |
| 24 | /// Deriving `Reflect` implements the relevant reflection traits. In this case, it implements the |
| 25 | /// `Reflect` trait and the `Struct` trait `derive(Reflect)` assumes that all fields also implement |
| 26 | /// Reflect. |
| 27 | /// |
| 28 | /// All fields in a reflected item will need to be `Reflect` as well. You can opt a field out of |
| 29 | /// reflection by using the `#[reflect(ignore)]` attribute. |
| 30 | /// If you choose to ignore a field, you need to let the automatically-derived `FromReflect` implementation |
| 31 | /// how to handle the field. |
| 32 | /// To do this, you can either define a `#[reflect(default = "...")]` attribute on the ignored field, or |
| 33 | /// opt-out of `FromReflect`'s auto-derive using the `#[reflect(from_reflect = false)]` attribute. |
| 34 | #[derive(Reflect)] |
| 35 | #[reflect(from_reflect = false)] |
| 36 | pub struct Foo { |
| 37 | a: usize, |
| 38 | nested: Bar, |
| 39 | #[reflect(ignore)] |
| 40 | _ignored: NonReflectedValue, |
| 41 | } |
| 42 | |
| 43 | /// This `Bar` type is used in the `nested` field of the `Foo` type. We must derive `Reflect` here |
| 44 | /// too (or ignore it) |
| 45 | #[derive(Reflect)] |
| 46 | pub struct Bar { |
| 47 | b: usize, |
| 48 | } |
| 49 | |
| 50 | #[derive(Default)] |
| 51 | struct NonReflectedValue { |
| 52 | _a: usize, |
| 53 | } |
| 54 | |
| 55 | fn setup(type_registry: Res<AppTypeRegistry>) { |
| 56 | let mut value = Foo { |
| 57 | a: 1, |
| 58 | _ignored: NonReflectedValue { _a: 10 }, |
| 59 | nested: Bar { b: 8 }, |
| 60 | }; |
| 61 | |
| 62 | // You can set field values like this. The type must match exactly or this will fail. |
| 63 | *value.get_field_mut("a").unwrap() = 2usize; |
| 64 | assert_eq!(value.a, 2); |
| 65 | assert_eq!(*value.get_field::<usize>("a").unwrap(), 2); |
| 66 | |
| 67 | // You can also get the `&dyn PartialReflect` value of a field like this |
| 68 | let field = value.field("a").unwrap(); |
| 69 | |
| 70 | // But values introspected via `PartialReflect` will not return `dyn Reflect` trait objects |
| 71 | // (even if the containing type does implement `Reflect`), so we need to convert them: |
| 72 | let fully_reflected_field = field.try_as_reflect().unwrap(); |
| 73 | |
| 74 | // Now, you can downcast your `Reflect` value like this: |
| 75 | assert_eq!(*fully_reflected_field.downcast_ref::<usize>().unwrap(), 2); |
| 76 | |
| 77 | // For this specific case, we also support the shortcut `try_downcast_ref`: |
| 78 | assert_eq!(*field.try_downcast_ref::<usize>().unwrap(), 2); |
| 79 | |
| 80 | // `DynamicStruct` also implements the `Struct` and `Reflect` traits. |
| 81 | let mut patch = DynamicStruct::default(); |
| 82 | patch.insert("a", 4usize); |
| 83 | |
| 84 | // You can "apply" Reflect implementations on top of other Reflect implementations. |
| 85 | // This will only set fields with the same name, and it will fail if the types don't match. |
| 86 | // You can use this to "patch" your types with new values. |
| 87 | value.apply(&patch); |
| 88 | assert_eq!(value.a, 4); |
| 89 | |
| 90 | let type_registry = type_registry.read(); |
| 91 | // By default, all derived `Reflect` types can be Serialized using serde. No need to derive |
| 92 | // Serialize! |
| 93 | let serializer = ReflectSerializer::new(&value, &type_registry); |
| 94 | let ron_string = |
| 95 | ron::ser::to_string_pretty(&serializer, ron::ser::PrettyConfig::default()).unwrap(); |
| 96 | info!("{}\n", ron_string); |
| 97 | |
| 98 | // Dynamic properties can be deserialized |
| 99 | let reflect_deserializer = ReflectDeserializer::new(&type_registry); |
| 100 | let mut deserializer = ron::de::Deserializer::from_str(&ron_string).unwrap(); |
| 101 | let reflect_value = reflect_deserializer.deserialize(&mut deserializer).unwrap(); |
| 102 | |
| 103 | // Deserializing returns a `Box<dyn PartialReflect>` value. |
| 104 | // Generally, deserializing a value will return the "dynamic" variant of a type. |
| 105 | // For example, deserializing a struct will return the DynamicStruct type. |
| 106 | // "Opaque types" will be deserialized as themselves. |
| 107 | assert_eq!( |
| 108 | reflect_value.reflect_type_path(), |
| 109 | DynamicStruct::type_path(), |
| 110 | ); |
| 111 | |
| 112 | // Reflect has its own `partial_eq` implementation, named `reflect_partial_eq`. This behaves |
| 113 | // like normal `partial_eq`, but it treats "dynamic" and "non-dynamic" types the same. The |
| 114 | // `Foo` struct and deserialized `DynamicStruct` are considered equal for this reason: |
| 115 | assert!(reflect_value.reflect_partial_eq(&value).unwrap()); |
| 116 | |
| 117 | // By "patching" `Foo` with the deserialized DynamicStruct, we can "Deserialize" Foo. |
| 118 | // This means we can serialize and deserialize with a single `Reflect` derive! |
| 119 | value.apply(&*reflect_value); |
| 120 | } |