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