Skip to main content

dynamic_types/
dynamic_types.rs

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