Skip to main content

bevy_reflect/serde/
mod.rs

1//! Serde integration for reflected types.
2
3mod de;
4mod ser;
5mod type_data;
6
7pub use de::*;
8pub use ser::*;
9pub use type_data::*;
10
11#[cfg(test)]
12mod tests {
13    use super::*;
14    use crate::{
15        structs::{DynamicStruct, Struct},
16        tuple_struct::DynamicTupleStruct,
17        type_registry::TypeRegistry,
18        FromReflect, PartialReflect, Reflect,
19    };
20    use serde::de::DeserializeSeed;
21
22    #[test]
23    fn test_serialization_struct() {
24        #[derive(Debug, Reflect, PartialEq)]
25        #[reflect(PartialEq)]
26        struct TestStruct {
27            a: i32,
28            #[reflect(ignore)]
29            b: i32,
30            #[reflect(skip_serializing)]
31            c: i32,
32            #[reflect(skip_serializing)]
33            #[reflect(default = "custom_default")]
34            d: i32,
35            e: i32,
36        }
37
38        fn custom_default() -> i32 {
39            -1
40        }
41
42        let mut registry = TypeRegistry::default();
43        registry.register::<TestStruct>();
44
45        let test_struct = TestStruct {
46            a: 3,
47            b: 4,
48            c: 5,
49            d: 6,
50            e: 7,
51        };
52
53        let serializer = ReflectSerializer::new(&test_struct, &registry);
54        let serialized =
55            ron::ser::to_string_pretty(&serializer, ron::ser::PrettyConfig::default()).unwrap();
56
57        let mut deserializer = ron::de::Deserializer::from_str(&serialized).unwrap();
58        let reflect_deserializer = ReflectDeserializer::new(&registry);
59        let deserialized = reflect_deserializer.deserialize(&mut deserializer).unwrap();
60
61        let mut expected = DynamicStruct::default();
62        expected.insert("a", 3);
63        // Ignored: expected.insert("b", 0);
64        expected.insert("c", 0);
65        expected.insert("d", -1);
66        expected.insert("e", 7);
67
68        assert!(
69            expected
70                .reflect_partial_eq(deserialized.as_partial_reflect())
71                .unwrap(),
72            "Deserialization failed: expected {expected:?} found {deserialized:?}"
73        );
74
75        let expected = TestStruct {
76            a: 3,
77            b: 0,
78            c: 0,
79            d: -1,
80            e: 7,
81        };
82        let received =
83            <TestStruct as FromReflect>::from_reflect(deserialized.as_partial_reflect()).unwrap();
84
85        assert_eq!(
86            expected, received,
87            "FromReflect failed: expected {expected:?} found {received:?}"
88        );
89    }
90
91    #[test]
92    fn test_serialization_tuple_struct() {
93        #[derive(Debug, Reflect, PartialEq)]
94        #[reflect(PartialEq)]
95        struct TestStruct(
96            i32,
97            #[reflect(ignore)] i32,
98            #[reflect(skip_serializing)] i32,
99            #[reflect(skip_serializing)]
100            #[reflect(default = "custom_default")]
101            i32,
102            i32,
103        );
104
105        fn custom_default() -> i32 {
106            -1
107        }
108
109        let mut registry = TypeRegistry::default();
110        registry.register::<TestStruct>();
111
112        let test_struct = TestStruct(3, 4, 5, 6, 7);
113
114        let serializer = ReflectSerializer::new(&test_struct, &registry);
115        let serialized =
116            ron::ser::to_string_pretty(&serializer, ron::ser::PrettyConfig::default()).unwrap();
117
118        let mut deserializer = ron::de::Deserializer::from_str(&serialized).unwrap();
119        let reflect_deserializer = ReflectDeserializer::new(&registry);
120        let deserialized = reflect_deserializer.deserialize(&mut deserializer).unwrap();
121
122        let mut expected = DynamicTupleStruct::default();
123        expected.insert(3);
124        // Ignored: expected.insert(0);
125        expected.insert(0);
126        expected.insert(-1);
127        expected.insert(7);
128
129        assert!(
130            expected
131                .reflect_partial_eq(deserialized.as_partial_reflect())
132                .unwrap(),
133            "Deserialization failed: expected {expected:?} found {deserialized:?}"
134        );
135
136        let expected = TestStruct(3, 0, 0, -1, 7);
137        let received =
138            <TestStruct as FromReflect>::from_reflect(deserialized.as_partial_reflect()).unwrap();
139
140        assert_eq!(
141            expected, received,
142            "FromReflect failed: expected {expected:?} found {received:?}"
143        );
144    }
145
146    #[test]
147    #[should_panic(
148        expected = "cannot serialize dynamic value without represented type: `bevy_reflect::DynamicStruct`"
149    )]
150    fn should_not_serialize_unproxied_dynamic() {
151        let registry = TypeRegistry::default();
152
153        let mut value = DynamicStruct::default();
154        value.insert("foo", 123_u32);
155
156        let serializer = ReflectSerializer::new(&value, &registry);
157        ron::ser::to_string(&serializer).unwrap();
158    }
159
160    #[test]
161    fn should_roundtrip_proxied_dynamic() {
162        #[derive(Reflect)]
163        struct TestStruct {
164            a: i32,
165            b: i32,
166        }
167
168        let mut registry = TypeRegistry::default();
169        registry.register::<TestStruct>();
170
171        let value: DynamicStruct = TestStruct { a: 123, b: 456 }.to_dynamic_struct();
172
173        let serializer = ReflectSerializer::new(&value, &registry);
174
175        let expected = r#"{"bevy_reflect::serde::tests::TestStruct":(a:123,b:456)}"#;
176        let result = ron::ser::to_string(&serializer).unwrap();
177        assert_eq!(expected, result);
178
179        let mut deserializer = ron::de::Deserializer::from_str(&result).unwrap();
180        let reflect_deserializer = ReflectDeserializer::new(&registry);
181
182        let expected = value.to_dynamic();
183        let result = reflect_deserializer.deserialize(&mut deserializer).unwrap();
184
185        assert!(expected
186            .reflect_partial_eq(result.as_partial_reflect())
187            .unwrap());
188    }
189
190    mod type_data {
191        use super::*;
192        use crate::from_reflect::FromReflect;
193        use crate::serde::{DeserializeWithRegistry, ReflectDeserializeWithRegistry};
194        use crate::serde::{ReflectSerializeWithRegistry, SerializeWithRegistry};
195        use crate::{ReflectFromReflect, TypePath};
196        use alloc::{format, string::String, vec, vec::Vec};
197        use bevy_platform::sync::Arc;
198        use bevy_reflect_derive::reflect_trait;
199        use core::any::TypeId;
200        use core::fmt::{Debug, Formatter};
201        use serde::de::{SeqAccess, Visitor};
202        use serde::ser::SerializeSeq;
203        use serde::{Deserializer, Serialize, Serializer};
204
205        #[reflect_trait]
206        trait Enemy: Reflect + Debug {
207            #[expect(dead_code, reason = "this method is purely for testing purposes")]
208            fn hp(&self) -> u8;
209        }
210
211        // This is needed to support Arc<dyn Enemy>
212        impl TypePath for dyn Enemy {
213            fn type_path() -> &'static str {
214                "dyn bevy_reflect::serde::tests::type_data::Enemy"
215            }
216
217            fn short_type_path() -> &'static str {
218                "dyn Enemy"
219            }
220        }
221
222        #[derive(Reflect, Debug)]
223        #[reflect(Enemy)]
224        struct Skeleton(u8);
225
226        impl Enemy for Skeleton {
227            fn hp(&self) -> u8 {
228                self.0
229            }
230        }
231
232        #[derive(Reflect, Debug)]
233        #[reflect(Enemy)]
234        struct Zombie {
235            health: u8,
236            walk_speed: f32,
237        }
238
239        impl Enemy for Zombie {
240            fn hp(&self) -> u8 {
241                self.health
242            }
243        }
244
245        #[derive(Reflect, Debug)]
246        struct Level {
247            name: String,
248            enemies: EnemyList,
249        }
250
251        #[derive(Reflect, Debug)]
252        #[reflect(SerializeWithRegistry, DeserializeWithRegistry)]
253        // Note that we have to use `Arc` instead of `Box` here due to the
254        // former being the only one between the two to implement `Reflect`.
255        struct EnemyList(Vec<Arc<dyn Enemy>>);
256
257        impl SerializeWithRegistry for EnemyList {
258            fn serialize<S>(
259                &self,
260                serializer: S,
261                registry: &TypeRegistry,
262            ) -> Result<S::Ok, S::Error>
263            where
264                S: Serializer,
265            {
266                let mut state = serializer.serialize_seq(Some(self.0.len()))?;
267                for enemy in &self.0 {
268                    state.serialize_element(&ReflectSerializer::new(
269                        (**enemy).as_partial_reflect(),
270                        registry,
271                    ))?;
272                }
273                state.end()
274            }
275        }
276
277        impl<'de> DeserializeWithRegistry<'de> for EnemyList {
278            fn deserialize<D>(deserializer: D, registry: &TypeRegistry) -> Result<Self, D::Error>
279            where
280                D: Deserializer<'de>,
281            {
282                struct EnemyListVisitor<'a> {
283                    registry: &'a TypeRegistry,
284                }
285
286                impl<'a, 'de> Visitor<'de> for EnemyListVisitor<'a> {
287                    type Value = Vec<Arc<dyn Enemy>>;
288
289                    fn expecting(&self, formatter: &mut Formatter) -> core::fmt::Result {
290                        write!(formatter, "a list of enemies")
291                    }
292
293                    fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
294                    where
295                        A: SeqAccess<'de>,
296                    {
297                        let mut enemies = Vec::new();
298                        while let Some(enemy) =
299                            seq.next_element_seed(ReflectDeserializer::new(self.registry))?
300                        {
301                            let registration = self
302                                .registry
303                                .get_with_type_path(
304                                    enemy.get_represented_type_info().unwrap().type_path(),
305                                )
306                                .unwrap();
307
308                            // 1. Convert any possible dynamic values to concrete ones
309                            let enemy = registration
310                                .data::<ReflectFromReflect>()
311                                .unwrap()
312                                .from_reflect(&*enemy)
313                                .unwrap();
314
315                            // 2. Convert the concrete value to a boxed trait object
316                            let enemy = registration
317                                .data::<ReflectEnemy>()
318                                .unwrap()
319                                .get_boxed(enemy)
320                                .unwrap();
321
322                            enemies.push(enemy.into());
323                        }
324
325                        Ok(enemies)
326                    }
327                }
328
329                deserializer
330                    .deserialize_seq(EnemyListVisitor { registry })
331                    .map(EnemyList)
332            }
333        }
334
335        fn create_registry() -> TypeRegistry {
336            let mut registry = TypeRegistry::default();
337            registry.register::<Level>();
338            registry.register::<EnemyList>();
339            registry.register::<Skeleton>();
340            registry.register::<Zombie>();
341            registry
342        }
343
344        fn create_arc_dyn_enemy<T: Enemy>(enemy: T) -> Arc<dyn Enemy> {
345            let arc = Arc::new(enemy);
346
347            #[cfg(not(target_has_atomic = "ptr"))]
348            #[expect(
349                unsafe_code,
350                reason = "unsized coercion is an unstable feature for non-std types"
351            )]
352            // SAFETY:
353            // - Coercion from `T` to `dyn Enemy` is valid as `T: Enemy + 'static`
354            // - `Arc::from_raw` receives a valid pointer from a previous call to `Arc::into_raw`
355            let arc = unsafe { Arc::from_raw(Arc::into_raw(arc) as *const dyn Enemy) };
356
357            arc
358        }
359
360        #[test]
361        fn should_serialize_with_serialize_with_registry() {
362            let registry = create_registry();
363
364            let level = Level {
365                name: String::from("Level 1"),
366                enemies: EnemyList(vec![
367                    create_arc_dyn_enemy(Skeleton(10)),
368                    create_arc_dyn_enemy(Zombie {
369                        health: 20,
370                        walk_speed: 0.5,
371                    }),
372                ]),
373            };
374
375            let serializer = ReflectSerializer::new(&level, &registry);
376            let serialized = ron::ser::to_string(&serializer).unwrap();
377
378            let expected = r#"{"bevy_reflect::serde::tests::type_data::Level":(name:"Level 1",enemies:[{"bevy_reflect::serde::tests::type_data::Skeleton":(10)},{"bevy_reflect::serde::tests::type_data::Zombie":(health:20,walk_speed:0.5)}])}"#;
379
380            assert_eq!(expected, serialized);
381        }
382
383        #[test]
384        fn should_deserialize_with_deserialize_with_registry() {
385            let registry = create_registry();
386
387            let input = r#"{"bevy_reflect::serde::tests::type_data::Level":(name:"Level 1",enemies:[{"bevy_reflect::serde::tests::type_data::Skeleton":(10)},{"bevy_reflect::serde::tests::type_data::Zombie":(health:20,walk_speed:0.5)}])}"#;
388
389            let mut deserializer = ron::de::Deserializer::from_str(input).unwrap();
390            let reflect_deserializer = ReflectDeserializer::new(&registry);
391            let value = reflect_deserializer.deserialize(&mut deserializer).unwrap();
392
393            let output = Level::from_reflect(&*value).unwrap();
394
395            let expected = Level {
396                name: String::from("Level 1"),
397                enemies: EnemyList(vec![
398                    create_arc_dyn_enemy(Skeleton(10)),
399                    create_arc_dyn_enemy(Zombie {
400                        health: 20,
401                        walk_speed: 0.5,
402                    }),
403                ]),
404            };
405
406            // Poor man's comparison since we can't derive PartialEq for Arc<dyn Enemy>
407            assert_eq!(format!("{expected:?}"), format!("{output:?}",));
408
409            let unexpected = Level {
410                name: String::from("Level 1"),
411                enemies: EnemyList(vec![
412                    create_arc_dyn_enemy(Skeleton(20)),
413                    create_arc_dyn_enemy(Zombie {
414                        health: 20,
415                        walk_speed: 5.0,
416                    }),
417                ]),
418            };
419
420            // Poor man's comparison since we can't derive PartialEq for Arc<dyn Enemy>
421            assert_ne!(format!("{unexpected:?}"), format!("{output:?}"));
422        }
423
424        #[test]
425        fn should_serialize_single_tuple_struct_as_newtype() {
426            #[derive(Reflect, Serialize, PartialEq, Debug)]
427            struct TupleStruct(u32);
428
429            #[derive(Reflect, Serialize, PartialEq, Debug)]
430            struct TupleStructWithSkip(
431                u32,
432                #[reflect(skip_serializing)]
433                #[serde(skip)]
434                u32,
435            );
436
437            #[derive(Reflect, Serialize, PartialEq, Debug)]
438            enum Enum {
439                TupleStruct(usize),
440                NestedTupleStruct(TupleStruct),
441                NestedTupleStructWithSkip(TupleStructWithSkip),
442            }
443
444            let mut registry = TypeRegistry::default();
445            registry.register::<TupleStruct>();
446            registry.register::<TupleStructWithSkip>();
447            registry.register::<Enum>();
448
449            let tuple_struct = TupleStruct(1);
450            let tuple_struct_with_skip = TupleStructWithSkip(2, 3);
451            let tuple_struct_enum = Enum::TupleStruct(4);
452            let nested_tuple_struct = Enum::NestedTupleStruct(TupleStruct(5));
453            let nested_tuple_struct_with_skip =
454                Enum::NestedTupleStructWithSkip(TupleStructWithSkip(6, 7));
455
456            fn assert_serialize<T: Reflect + FromReflect + Serialize + PartialEq + Debug>(
457                value: &T,
458                registry: &TypeRegistry,
459            ) {
460                let serializer = TypedReflectSerializer::new(value, registry);
461                let reflect_serialize = serde_json::to_string(&serializer).unwrap();
462                let serde_serialize = serde_json::to_string(value).unwrap();
463                assert_eq!(reflect_serialize, serde_serialize);
464
465                let registration = registry.get(TypeId::of::<T>()).unwrap();
466                let reflect_deserializer = TypedReflectDeserializer::new(registration, registry);
467
468                let mut deserializer = serde_json::Deserializer::from_str(&serde_serialize);
469                let reflect_value = reflect_deserializer.deserialize(&mut deserializer).unwrap();
470                let _ = T::from_reflect(&*reflect_value).unwrap();
471            }
472
473            assert_serialize(&tuple_struct, &registry);
474            assert_serialize(&tuple_struct_with_skip, &registry);
475            assert_serialize(&tuple_struct_enum, &registry);
476            assert_serialize(&nested_tuple_struct, &registry);
477            assert_serialize(&nested_tuple_struct_with_skip, &registry);
478        }
479    }
480}