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