dynamic_types/
dynamic_types.rs

1//! This example demonstrates the use of dynamic types in Bevy's reflection system.
2
3use bevy::reflect::{
4    reflect_trait, serde::TypedReflectDeserializer, std_traits::ReflectDefault, DynamicArray,
5    DynamicEnum, DynamicList, DynamicMap, DynamicSet, DynamicStruct, DynamicTuple,
6    DynamicTupleStruct, DynamicVariant, FromReflect, PartialReflect, Reflect, ReflectFromReflect,
7    Set, TypeRegistry, Typed,
8};
9use serde::de::DeserializeSeed;
10use std::collections::{HashMap, HashSet};
11
12fn main() {
13    #[derive(Reflect, Default, PartialEq, Debug)]
14    #[reflect(Identifiable, Default)]
15    struct Player {
16        id: u32,
17    }
18
19    #[reflect_trait]
20    trait Identifiable {
21        fn id(&self) -> u32;
22    }
23
24    impl Identifiable for Player {
25        fn id(&self) -> u32 {
26            self.id
27        }
28    }
29
30    // Normally, when instantiating a type, you get back exactly that type.
31    // This is because the type is known at compile time.
32    // We call this the "concrete" or "canonical" type.
33    let player: Player = Player { id: 123 };
34
35    // When working with reflected types, however, we often "erase" this type information
36    // using the `Reflect` trait object.
37    // This trait object also gives us access to all the methods in the `PartialReflect` trait too.
38    // The underlying type is still the same (in this case, `Player`),
39    // but now we've hidden that information from the compiler.
40    let reflected: Box<dyn Reflect> = Box::new(player);
41
42    // Because it's the same type under the hood, we can still downcast it back to the original type.
43    assert!(reflected.downcast_ref::<Player>().is_some());
44
45    // We can attempt to clone our value using `PartialReflect::reflect_clone`.
46    // This will recursively call `PartialReflect::reflect_clone` on all fields of the type.
47    // Or, if we had registered `ReflectClone` using `#[reflect(Clone)]`, it would simply call `Clone::clone` directly.
48    let cloned: Box<dyn Reflect> = reflected.reflect_clone().unwrap();
49    assert_eq!(cloned.downcast_ref::<Player>(), Some(&Player { id: 123 }));
50
51    // Another way we can "clone" our data is by converting it to a dynamic type.
52    // Notice here we bind it as a `dyn PartialReflect` instead of `dyn Reflect`.
53    // This is because it returns a dynamic type that simply represents the original type.
54    // In this case, because `Player` is a struct, it will return a `DynamicStruct`.
55    let dynamic: Box<dyn PartialReflect> = reflected.to_dynamic();
56    assert!(dynamic.is_dynamic());
57
58    // And if we try to convert it back to a `dyn Reflect` trait object, we'll get `None`.
59    // Dynamic types cannot be directly cast to `dyn Reflect` trait objects.
60    assert!(dynamic.try_as_reflect().is_none());
61
62    // Generally dynamic types are used to represent (or "proxy") the original type,
63    // so that we can continue to access its fields and overall structure.
64    let dynamic_ref = dynamic.reflect_ref().as_struct().unwrap();
65    let id = dynamic_ref.field("id").unwrap().try_downcast_ref::<u32>();
66    assert_eq!(id, Some(&123));
67
68    // It also enables us to create a representation of a type without having compile-time
69    // access to the actual type. This is how the reflection deserializers work.
70    // They generally can't know how to construct a type ahead of time,
71    // so they instead build and return these dynamic representations.
72    let input = "(id: 123)";
73    let mut registry = TypeRegistry::default();
74    registry.register::<Player>();
75    let registration = registry.get(std::any::TypeId::of::<Player>()).unwrap();
76    let deserialized = TypedReflectDeserializer::new(registration, &registry)
77        .deserialize(&mut ron::Deserializer::from_str(input).unwrap())
78        .unwrap();
79
80    // Our deserialized output is a `DynamicStruct` that proxies/represents a `Player`.
81    assert!(deserialized.represents::<Player>());
82
83    // And while this does allow us to access the fields and structure of the type,
84    // there may be instances where we need the actual type.
85    // For example, if we want to convert our `dyn Reflect` into a `dyn Identifiable`,
86    // we can't use the `DynamicStruct` proxy.
87    let reflect_identifiable = registration
88        .data::<ReflectIdentifiable>()
89        .expect("`ReflectIdentifiable` should be registered");
90
91    // Trying to access the registry with our `deserialized` will give a compile error
92    // since it doesn't implement `Reflect`, only `PartialReflect`.
93    // Similarly, trying to force the operation will fail.
94    // This fails since the underlying type of `deserialized` is `DynamicStruct` and not `Player`.
95    assert!(deserialized
96        .try_as_reflect()
97        .and_then(|reflect_trait_obj| reflect_identifiable.get(reflect_trait_obj))
98        .is_none());
99
100    // So how can we go from a dynamic type to a concrete type?
101    // There are two ways:
102
103    // 1. Using `PartialReflect::apply`.
104    {
105        // If you know the type at compile time, you can construct a new value and apply the dynamic
106        // value to it.
107        let mut value = Player::default();
108        value.apply(deserialized.as_ref());
109        assert_eq!(value.id, 123);
110
111        // If you don't know the type at compile time, you need a dynamic way of constructing
112        // an instance of the type. One such way is to use the `ReflectDefault` type data.
113        let reflect_default = registration
114            .data::<ReflectDefault>()
115            .expect("`ReflectDefault` should be registered");
116
117        let mut value: Box<dyn Reflect> = reflect_default.default();
118        value.apply(deserialized.as_ref());
119
120        let identifiable: &dyn Identifiable = reflect_identifiable.get(value.as_reflect()).unwrap();
121        assert_eq!(identifiable.id(), 123);
122    }
123
124    // 2. Using `FromReflect`
125    {
126        // If you know the type at compile time, you can use the `FromReflect` trait to convert the
127        // dynamic value into the concrete type directly.
128        let value: Player = Player::from_reflect(deserialized.as_ref()).unwrap();
129        assert_eq!(value.id, 123);
130
131        // If you don't know the type at compile time, you can use the `ReflectFromReflect` type data
132        // to perform the conversion dynamically.
133        let reflect_from_reflect = registration
134            .data::<ReflectFromReflect>()
135            .expect("`ReflectFromReflect` should be registered");
136
137        let value: Box<dyn Reflect> = reflect_from_reflect
138            .from_reflect(deserialized.as_ref())
139            .unwrap();
140        let identifiable: &dyn Identifiable = reflect_identifiable.get(value.as_reflect()).unwrap();
141        assert_eq!(identifiable.id(), 123);
142    }
143
144    // Lastly, while dynamic types are commonly generated via reflection methods like
145    // `PartialReflect::to_dynamic` or via the reflection deserializers,
146    // you can also construct them manually.
147    let mut my_dynamic_list = DynamicList::from_iter([1u32, 2u32, 3u32]);
148
149    // This is useful when you just need to apply some subset of changes to a type.
150    let mut my_list: Vec<u32> = Vec::new();
151    my_list.apply(&my_dynamic_list);
152    assert_eq!(my_list, vec![1, 2, 3]);
153
154    // And if you want it to actually proxy a type, you can configure it to do that as well:
155    assert!(!my_dynamic_list
156        .as_partial_reflect()
157        .represents::<Vec<u32>>());
158    my_dynamic_list.set_represented_type(Some(<Vec<u32>>::type_info()));
159    assert!(my_dynamic_list
160        .as_partial_reflect()
161        .represents::<Vec<u32>>());
162
163    // ============================= REFERENCE ============================= //
164    // For reference, here are all the available dynamic types:
165
166    // 1. `DynamicTuple`
167    {
168        let mut dynamic_tuple = DynamicTuple::default();
169        dynamic_tuple.insert(1u32);
170        dynamic_tuple.insert(2u32);
171        dynamic_tuple.insert(3u32);
172
173        let mut my_tuple: (u32, u32, u32) = (0, 0, 0);
174        my_tuple.apply(&dynamic_tuple);
175        assert_eq!(my_tuple, (1, 2, 3));
176    }
177
178    // 2. `DynamicArray`
179    {
180        let dynamic_array = DynamicArray::from_iter([1u32, 2u32, 3u32]);
181
182        let mut my_array = [0u32; 3];
183        my_array.apply(&dynamic_array);
184        assert_eq!(my_array, [1, 2, 3]);
185    }
186
187    // 3. `DynamicList`
188    {
189        let dynamic_list = DynamicList::from_iter([1u32, 2u32, 3u32]);
190
191        let mut my_list: Vec<u32> = Vec::new();
192        my_list.apply(&dynamic_list);
193        assert_eq!(my_list, vec![1, 2, 3]);
194    }
195
196    // 4. `DynamicSet`
197    {
198        let mut dynamic_set = DynamicSet::from_iter(["x", "y", "z"]);
199        assert!(dynamic_set.contains(&"x"));
200
201        dynamic_set.remove(&"y");
202
203        let mut my_set: HashSet<&str> = HashSet::default();
204        my_set.apply(&dynamic_set);
205        assert_eq!(my_set, HashSet::from_iter(["x", "z"]));
206    }
207
208    // 5. `DynamicMap`
209    {
210        let dynamic_map = DynamicMap::from_iter([("x", 1u32), ("y", 2u32), ("z", 3u32)]);
211
212        let mut my_map: HashMap<&str, u32> = HashMap::default();
213        my_map.apply(&dynamic_map);
214        assert_eq!(my_map.get("x"), Some(&1));
215        assert_eq!(my_map.get("y"), Some(&2));
216        assert_eq!(my_map.get("z"), Some(&3));
217    }
218
219    // 6. `DynamicStruct`
220    {
221        #[derive(Reflect, Default, Debug, PartialEq)]
222        struct MyStruct {
223            x: u32,
224            y: u32,
225            z: u32,
226        }
227
228        let mut dynamic_struct = DynamicStruct::default();
229        dynamic_struct.insert("x", 1u32);
230        dynamic_struct.insert("y", 2u32);
231        dynamic_struct.insert("z", 3u32);
232
233        let mut my_struct = MyStruct::default();
234        my_struct.apply(&dynamic_struct);
235        assert_eq!(my_struct, MyStruct { x: 1, y: 2, z: 3 });
236    }
237
238    // 7. `DynamicTupleStruct`
239    {
240        #[derive(Reflect, Default, Debug, PartialEq)]
241        struct MyTupleStruct(u32, u32, u32);
242
243        let mut dynamic_tuple_struct = DynamicTupleStruct::default();
244        dynamic_tuple_struct.insert(1u32);
245        dynamic_tuple_struct.insert(2u32);
246        dynamic_tuple_struct.insert(3u32);
247
248        let mut my_tuple_struct = MyTupleStruct::default();
249        my_tuple_struct.apply(&dynamic_tuple_struct);
250        assert_eq!(my_tuple_struct, MyTupleStruct(1, 2, 3));
251    }
252
253    // 8. `DynamicEnum`
254    {
255        #[derive(Reflect, Default, Debug, PartialEq)]
256        enum MyEnum {
257            #[default]
258            Empty,
259            Xyz(u32, u32, u32),
260        }
261
262        let mut values = DynamicTuple::default();
263        values.insert(1u32);
264        values.insert(2u32);
265        values.insert(3u32);
266
267        let dynamic_variant = DynamicVariant::Tuple(values);
268        let dynamic_enum = DynamicEnum::new("Xyz", dynamic_variant);
269
270        let mut my_enum = MyEnum::default();
271        my_enum.apply(&dynamic_enum);
272        assert_eq!(my_enum, MyEnum::Xyz(1, 2, 3));
273    }
274}