reflection_types/reflection_types.rs
1//! This example illustrates how reflection works for simple data structures, like
2//! structs, tuples and vectors.
3
4use bevy::{
5 platform::collections::HashMap,
6 prelude::*,
7 reflect::{DynamicList, PartialReflect, ReflectRef},
8};
9use serde::{Deserialize, Serialize};
10
11fn main() {
12 App::new()
13 .add_plugins(DefaultPlugins)
14 .add_systems(Startup, setup)
15 .run();
16}
17
18/// Deriving reflect on a struct will implement the `Reflect` and `Struct` traits
19#[derive(Reflect)]
20pub struct A {
21 x: usize,
22 y: Vec<u32>,
23 z: HashMap<String, f32>,
24}
25
26/// Deriving reflect on a unit struct will implement the `Reflect` and `Struct` traits
27#[derive(Reflect)]
28pub struct B;
29
30/// Deriving reflect on a tuple struct will implement the `Reflect` and `TupleStruct` traits
31#[derive(Reflect)]
32pub struct C(usize);
33
34/// Deriving reflect on an enum will implement the `Reflect` and `Enum` traits
35#[derive(Reflect)]
36enum D {
37 A,
38 B(usize),
39 C { value: f32 },
40}
41
42/// Reflect has "built in" support for some common traits like `PartialEq`, `Hash`, and `Clone`.
43///
44/// These are exposed via methods like `PartialReflect::reflect_hash()`,
45/// `PartialReflect::reflect_partial_eq()`, and `PartialReflect::reflect_clone()`.
46/// You can force these implementations to use the actual trait
47/// implementations (instead of their defaults) like this:
48#[derive(Reflect, Hash, PartialEq, Clone)]
49#[reflect(Hash, PartialEq, Clone)]
50pub struct E {
51 x: usize,
52}
53
54/// By default, deriving with Reflect assumes the type is either a "struct" or an "enum".
55///
56/// You can tell reflect to treat your type instead as an "opaque type" by using the `#[reflect(opaque)]`.
57/// It is generally a good idea to implement (and reflect) the `PartialEq` and `Clone` (optionally also `Serialize` and `Deserialize`)
58/// traits on opaque types to ensure that these values behave as expected when nested in other reflected types.
59#[derive(Reflect, Copy, Clone, PartialEq, Eq, Serialize, Deserialize)]
60#[reflect(opaque)]
61#[reflect(PartialEq, Clone, Serialize, Deserialize)]
62enum F {
63 X,
64 Y,
65}
66
67fn setup() {
68 let mut z = <HashMap<_, _>>::default();
69 z.insert("Hello".to_string(), 1.0);
70 let value: Box<dyn Reflect> = Box::new(A {
71 x: 1,
72 y: vec![1, 2],
73 z,
74 });
75
76 // There are a number of different "reflect traits", which each expose different operations on
77 // the underlying type
78 match value.reflect_ref() {
79 // `Struct` is a trait automatically implemented for structs that derive Reflect. This trait
80 // allows you to interact with fields via their string names or indices
81 ReflectRef::Struct(value) => {
82 info!(
83 "This is a 'struct' type with an 'x' value of {}",
84 value.get_field::<usize>("x").unwrap()
85 );
86 }
87 // `TupleStruct` is a trait automatically implemented for tuple structs that derive Reflect.
88 // This trait allows you to interact with fields via their indices
89 ReflectRef::TupleStruct(_) => {}
90 // `Tuple` is a special trait that can be manually implemented (instead of deriving
91 // Reflect). This exposes "tuple" operations on your type, allowing you to interact
92 // with fields via their indices. Tuple is automatically implemented for tuples of
93 // arity 12 or less.
94 ReflectRef::Tuple(_) => {}
95 // `Enum` is a trait automatically implemented for enums that derive Reflect. This trait allows you
96 // to interact with the current variant and its fields (if it has any)
97 ReflectRef::Enum(_) => {}
98 // `List` is a special trait that can be manually implemented (instead of deriving Reflect).
99 // This exposes "list" operations on your type, such as insertion. `List` is automatically
100 // implemented for relevant core types like Vec<T>.
101 ReflectRef::List(_) => {}
102 // `Array` is a special trait that can be manually implemented (instead of deriving Reflect).
103 // This exposes "array" operations on your type, such as indexing. `Array`
104 // is automatically implemented for relevant core types like [T; N].
105 ReflectRef::Array(_) => {}
106 // `Map` is a special trait that can be manually implemented (instead of deriving Reflect).
107 // This exposes "map" operations on your type, such as getting / inserting by key.
108 // Map is automatically implemented for relevant core types like HashMap<K, V>
109 ReflectRef::Map(_) => {}
110 // `Set` is a special trait that can be manually implemented (instead of deriving Reflect).
111 // This exposes "set" operations on your type, such as getting / inserting by value.
112 // Set is automatically implemented for relevant core types like HashSet<T>
113 ReflectRef::Set(_) => {}
114 // `Function` is a special trait that can be manually implemented (instead of deriving Reflect).
115 // This exposes "function" operations on your type, such as calling it with arguments.
116 // This trait is automatically implemented for types like DynamicFunction.
117 // This variant only exists if the `reflect_functions` feature is enabled.
118 #[cfg(feature = "reflect_functions")]
119 ReflectRef::Function(_) => {}
120 // `Opaque` types do not implement any of the other traits above. They are simply a Reflect
121 // implementation. Opaque is implemented for opaque types like String and Instant,
122 // but also include primitive types like i32, usize, and f32 (despite not technically being opaque).
123 ReflectRef::Opaque(_) => {}
124 #[expect(
125 clippy::allow_attributes,
126 reason = "`unreachable_patterns` is not always linted"
127 )]
128 #[allow(
129 unreachable_patterns,
130 reason = "This example cannot always detect when `bevy_reflect/functions` is enabled."
131 )]
132 _ => {}
133 }
134
135 let mut dynamic_list = DynamicList::default();
136 dynamic_list.push(3u32);
137 dynamic_list.push(4u32);
138 dynamic_list.push(5u32);
139
140 let mut value: A = value.take::<A>().unwrap();
141 value.y.apply(&dynamic_list);
142 assert_eq!(value.y, vec![3u32, 4u32, 5u32]);
143}