bevy_reflect/serde/
mod.rs

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