This commit is contained in:
Nadav Nissim 2025-07-15 22:34:41 +02:00 committed by GitHub
commit 3077d7a6a9
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 165 additions and 11 deletions

View File

@ -391,16 +391,22 @@ impl<'de, P: ReflectDeserializerProcessor> DeserializeSeed<'de>
match self.registration.type_info() {
TypeInfo::Struct(struct_info) => {
let mut dynamic_struct = deserializer.deserialize_struct(
struct_info.type_path_table().ident().unwrap(),
struct_info.field_names(),
StructVisitor {
struct_info,
registration: self.registration,
registry: self.registry,
processor: self.processor,
},
)?;
let visitor = StructVisitor {
struct_info,
registration: self.registration,
registry: self.registry,
processor: self.processor,
};
let mut dynamic_struct = match struct_info.field_len() {
0 => deserializer.deserialize_unit(visitor)?,
_ => deserializer.deserialize_struct(
struct_info.type_path_table().ident().unwrap(),
struct_info.field_names(),
visitor,
)?,
};
dynamic_struct.set_represented_type(Some(self.registration.type_info()));
Ok(Box::new(dynamic_struct))
}
@ -529,3 +535,144 @@ impl<'de, P: ReflectDeserializerProcessor> DeserializeSeed<'de>
output
}
}
#[cfg(test)]
mod tests {
use super::*;
use serde::{Deserialize, Serialize};
use std::fmt::Debug;
use std::str::FromStr;
use crate as bevy_reflect;
use bevy_reflect::prelude::*;
#[derive(Reflect, Default, Debug, PartialEq, Serialize, Deserialize)]
struct UnitStruct;
#[derive(Reflect, Default, Debug, PartialEq, Serialize, Deserialize)]
struct SomeStruct {
field_1: f32,
field_2: i32,
field_3: String,
}
#[derive(Reflect, Default, Debug, PartialEq, Serialize, Deserialize)]
struct IgnoredStruct {
#[reflect(ignore)]
field_1: f32,
#[reflect(ignore)]
field_2: i32,
#[reflect(ignore)]
field_3: String,
}
fn check_equivalence<T>(
type_registry: &TypeRegistry,
json_raw: &str,
val: T,
) -> Result<(), serde_json::error::Error>
where
T: Serialize + for<'de> Deserialize<'de> + Debug + Reflect + FromReflect + PartialEq,
{
// Json raw to json value
let json_val = serde_json::Value::from_str(json_raw).unwrap();
// Json value to reflect
let registration = type_registry.get(std::any::TypeId::of::<T>()).unwrap();
let deserializer = TypedReflectDeserializer::new(registration, &type_registry);
let reflected = match deserializer.deserialize(json_val.clone()) {
Ok(v) => v,
Err(e) => return Err(e),
};
// Reflect to val
let extracted = T::from_reflect(reflected.as_ref()).unwrap();
if val != extracted {
return Err(serde_json::error::Error::custom(format!(
"val: {val:?} != extracted: {extracted:?}"
)));
}
// Val to json value
let serialized_val = serde_json::to_value(&val).unwrap();
if json_val != serialized_val {
return Err(serde_json::error::Error::custom(format!(
"json_val: {json_val:?} != serialized_val: {serialized_val:?}"
)));
}
Ok(())
}
#[test]
fn test_reflect_symmetry() {
let mut type_registry = TypeRegistry::default();
type_registry.register::<UnitStruct>();
type_registry.register::<SomeStruct>();
type_registry.register::<IgnoredStruct>();
let result = check_equivalence(&type_registry, "null", UnitStruct);
assert!(result.is_ok(), "Error: {:?}", result.unwrap_err());
let result = check_equivalence(
&type_registry,
r#"{"field_1":0.0,"field_2":0,"field_3":""}"#,
SomeStruct::default(),
);
assert!(result.is_ok(), "Error: {:?}", result.unwrap_err());
let result = check_equivalence(
&type_registry,
r#"{"field_1":1.0,"field_2":2,"field_3":"3"}"#,
SomeStruct {
field_1: 1.0,
field_2: 2,
field_3: "3".to_string(),
},
);
assert!(result.is_ok(), "Error: {:?}", result.unwrap_err());
let result = check_equivalence(
&type_registry,
r#"{"field_1":0.0,"field_2":0,"field_3":""}"#,
IgnoredStruct::default(),
);
assert!(result.is_ok(), "Error: {:?}", result.unwrap_err());
let result = check_equivalence(
&type_registry,
r#"{"field_1":1.0,"field_2":2,"field_3":"3"}"#,
IgnoredStruct {
field_1: 1.0,
field_2: 2,
field_3: "3".to_string(),
},
);
assert!(result.is_ok(), "Error: {:?}", result.unwrap_err());
}
#[test]
fn test_reflect_symmetry_fail() {
let mut type_registry = TypeRegistry::default();
type_registry.register::<UnitStruct>();
type_registry.register::<SomeStruct>();
type_registry.register::<IgnoredStruct>();
let result = check_equivalence(&type_registry, "[]", UnitStruct);
assert!(
result.is_err(),
"UnitStruct should fail to serialize to an array"
);
let result = check_equivalence(&type_registry, "null", SomeStruct::default());
assert!(result.is_err(), "Structs should serialize ino to an object");
let result = check_equivalence(&type_registry, "null", IgnoredStruct::default());
assert!(
result.is_err(),
"even structs with ignored fields should serialize ino to an object",
);
}
}

View File

@ -3,7 +3,7 @@ use crate::{
DynamicStruct, StructInfo, TypeRegistration, TypeRegistry,
};
use core::{fmt, fmt::Formatter};
use serde::de::{MapAccess, SeqAccess, Visitor};
use serde::de::{Error, MapAccess, SeqAccess, Visitor};
use super::ReflectDeserializerProcessor;
@ -49,4 +49,11 @@ impl<'de, P: ReflectDeserializerProcessor> Visitor<'de> for StructVisitor<'_, P>
self.processor,
)
}
fn visit_unit<E>(self) -> Result<Self::Value, E>
where
E: Error,
{
Ok(DynamicStruct::default())
}
}