bevy_reflect: Fix dynamic type serialization (#10103)

# Objective

Fixes #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.
This commit is contained in:
Gino Valente 2023-10-16 16:31:16 -07:00 committed by GitHub
parent 71329fe0c2
commit 01b910a148
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 57 additions and 4 deletions

View file

@ -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,
@ -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();
@ -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());
}
}

View file

@ -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()

View file

@ -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()
}
}