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 }