Skip to content

Commit

Permalink
bevy_reflect: Fix dynamic type serialization (bevyengine#10103)
Browse files Browse the repository at this point in the history
# Objective

Fixes bevyengine#10086

## Solution

Instead of serializing via `DynamicTypePath::reflect_type_path`, now
uses the `TypePath` found on the `TypeInfo` returned by
`Reflect::get_represented_type_info`.

This issue was happening because the dynamic types implement `TypePath`
themselves and do not (and cannot) forward their proxy's `TypePath`
data. The solution was to access the proxy's type information in order
to get the correct `TypePath` data.

## Changed

- The `Debug` impl for `TypePathTable` now includes output for all
fields.
  • Loading branch information
MrGVSV authored and Ray Redondo committed Jan 9, 2024
1 parent 753a721 commit 85b98f9
Show file tree
Hide file tree
Showing 3 changed files with 57 additions and 4 deletions.
40 changes: 37 additions & 3 deletions crates/bevy_reflect/src/serde/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ pub use type_data::*;

#[cfg(test)]
mod tests {
use crate::{self as bevy_reflect, DynamicTupleStruct};
use crate::{self as bevy_reflect, DynamicTupleStruct, Struct};
use crate::{
serde::{ReflectSerializer, UntypedReflectDeserializer},
type_registry::TypeRegistry,
Expand Down Expand Up @@ -94,8 +94,10 @@ mod tests {
}

#[test]
#[should_panic(expected = "cannot get type info for bevy_reflect::DynamicStruct")]
fn unproxied_dynamic_should_not_serialize() {
#[should_panic(
expected = "cannot serialize dynamic value without represented type: bevy_reflect::DynamicStruct"
)]
fn should_not_serialize_unproxied_dynamic() {
let registry = TypeRegistry::default();

let mut value = DynamicStruct::default();
Expand All @@ -104,4 +106,36 @@ mod tests {
let serializer = ReflectSerializer::new(&value, &registry);
ron::ser::to_string(&serializer).unwrap();
}

#[test]
fn should_roundtrip_proxied_dynamic() {
#[derive(Reflect)]
struct TestStruct {
a: i32,
b: i32,
}

let mut registry = TypeRegistry::default();
registry.register::<TestStruct>();

let value: DynamicStruct = TestStruct { a: 123, b: 456 }.clone_dynamic();

let serializer = ReflectSerializer::new(&value, &registry);

let expected = r#"{"bevy_reflect::serde::tests::TestStruct":(a:123,b:456)}"#;
let result = ron::ser::to_string(&serializer).unwrap();
assert_eq!(expected, result);

let mut deserializer = ron::de::Deserializer::from_str(&result).unwrap();
let reflect_deserializer = UntypedReflectDeserializer::new(&registry);

let expected = value.clone_value();
let result = reflect_deserializer
.deserialize(&mut deserializer)
.unwrap()
.take::<DynamicStruct>()
.unwrap();

assert!(expected.reflect_partial_eq(&result).unwrap());
}
}
17 changes: 16 additions & 1 deletion crates/bevy_reflect/src/serde/ser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,22 @@ impl<'a> Serialize for ReflectSerializer<'a> {
{
let mut state = serializer.serialize_map(Some(1))?;
state.serialize_entry(
self.value.reflect_type_path(),
self.value
.get_represented_type_info()
.ok_or_else(|| {
if self.value.is_dynamic() {
Error::custom(format_args!(
"cannot serialize dynamic value without represented type: {}",
self.value.reflect_type_path()
))
} else {
Error::custom(format_args!(
"cannot get type info for {}",
self.value.reflect_type_path()
))
}
})?
.type_path(),
&TypedReflectSerializer::new(self.value, self.registry),
)?;
state.end()
Expand Down
4 changes: 4 additions & 0 deletions crates/bevy_reflect/src/type_path.rs
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,10 @@ impl fmt::Debug for TypePathTable {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("TypePathVtable")
.field("type_path", &self.type_path)
.field("short_type_path", &(self.short_type_path)())
.field("type_ident", &(self.type_ident)())
.field("crate_name", &(self.crate_name)())
.field("module_path", &(self.module_path)())
.finish()
}
}
Expand Down

0 comments on commit 85b98f9

Please sign in to comment.