forked from bevyengine/bevy
-
Notifications
You must be signed in to change notification settings - Fork 0
/
properties.rs
102 lines (86 loc) · 3.54 KB
/
properties.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
use bevy::{
prelude::*,
property::{ron::deserialize_dynamic_properties, PropertyTypeRegistry},
scene::serialize_ron,
type_registry::TypeRegistry,
};
use serde::{Deserialize, Serialize};
/// This example illustrates how Properties work. Properties provide a way to dynamically interact with Rust struct fields using
/// their names. Properties are a core part of Bevy and enable a number of interesting scenarios (like scenes). If you are
/// familiar with "reflection" in other languages, Properties are very similar to that concept.
fn main() {
App::build()
.add_default_plugins()
// If you need to deserialize custom property types, register them like this:
.register_property::<Test>()
.register_property::<Nested>()
.register_property::<CustomProperty>()
.add_startup_system(setup.system())
.run();
}
#[derive(Properties, Default)]
pub struct Test {
a: usize,
custom: CustomProperty,
nested: Nested,
}
#[derive(Properties, Default)]
pub struct Nested {
b: usize,
}
#[derive(Serialize, Deserialize, Default, Clone, Property)]
pub struct CustomProperty {
a: usize,
}
fn setup(type_registry: Res<TypeRegistry>) {
let mut test = Test {
a: 1,
custom: CustomProperty { a: 10 },
nested: Nested { b: 8 },
};
// You can set a property value like this. The type must match exactly or this will fail.
test.set_prop_val::<usize>("a", 2);
assert_eq!(test.a, 2);
assert_eq!(*test.prop_val::<usize>("a").unwrap(), 2);
// You can also set properties dynamically. set_prop accepts any type that implements Property
let x: u32 = 3;
test.set_prop("a", &x);
assert_eq!(test.a, 3);
// DynamicProperties also implements the Properties trait.
let mut patch = DynamicProperties::map();
patch.set::<usize>("a", 4);
// You can "apply" Properties on top of other Properties. This will only set properties with the same name and type.
// You can use this to "patch" your properties with new values.
test.apply(&patch);
assert_eq!(test.a, 4);
// All properties can be serialized.
// If you #[derive(Properties)] your type doesn't even need to directly implement the Serde trait!
let registry = type_registry.property.read();
let ron_string = serialize_property(&test, ®istry);
println!("{}\n", ron_string);
// Dynamic properties can be deserialized
let dynamic_properties = deserialize_dynamic_properties(&ron_string, ®istry).unwrap();
let round_tripped = serialize_property(&dynamic_properties, ®istry);
println!("{}", round_tripped);
assert_eq!(ron_string, round_tripped);
// This means you can patch Properties with dynamic properties deserialized from a string
test.apply(&dynamic_properties);
// Properties can also be sequences.
// Sequences from std::collections (Vec, VecDeque) already implement the Properties trait
let mut seq = vec![1u32, 2u32];
let mut patch = DynamicProperties::seq();
patch.push(Box::new(3u32), None);
seq.apply(&patch);
assert_eq!(seq[0], 3);
let ron_string = serialize_property(&patch, ®istry);
println!("{}\n", ron_string);
let dynamic_properties = deserialize_dynamic_properties(&ron_string, ®istry).unwrap();
let round_tripped = serialize_property(&dynamic_properties, ®istry);
assert_eq!(ron_string, round_tripped);
}
fn serialize_property<T>(property: &T, registry: &PropertyTypeRegistry) -> String
where
T: Property,
{
serialize_ron(property.serializable(registry).borrow()).unwrap()
}