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