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