Merge 012483675d
into d195116426
This commit is contained in:
commit
3077d7a6a9
@ -391,16 +391,22 @@ impl<'de, P: ReflectDeserializerProcessor> DeserializeSeed<'de>
|
|||||||
|
|
||||||
match self.registration.type_info() {
|
match self.registration.type_info() {
|
||||||
TypeInfo::Struct(struct_info) => {
|
TypeInfo::Struct(struct_info) => {
|
||||||
let mut dynamic_struct = deserializer.deserialize_struct(
|
let visitor = StructVisitor {
|
||||||
struct_info.type_path_table().ident().unwrap(),
|
struct_info,
|
||||||
struct_info.field_names(),
|
registration: self.registration,
|
||||||
StructVisitor {
|
registry: self.registry,
|
||||||
struct_info,
|
processor: self.processor,
|
||||||
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()));
|
dynamic_struct.set_represented_type(Some(self.registration.type_info()));
|
||||||
Ok(Box::new(dynamic_struct))
|
Ok(Box::new(dynamic_struct))
|
||||||
}
|
}
|
||||||
@ -529,3 +535,144 @@ impl<'de, P: ReflectDeserializerProcessor> DeserializeSeed<'de>
|
|||||||
output
|
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",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -3,7 +3,7 @@ use crate::{
|
|||||||
DynamicStruct, StructInfo, TypeRegistration, TypeRegistry,
|
DynamicStruct, StructInfo, TypeRegistration, TypeRegistry,
|
||||||
};
|
};
|
||||||
use core::{fmt, fmt::Formatter};
|
use core::{fmt, fmt::Formatter};
|
||||||
use serde::de::{MapAccess, SeqAccess, Visitor};
|
use serde::de::{Error, MapAccess, SeqAccess, Visitor};
|
||||||
|
|
||||||
use super::ReflectDeserializerProcessor;
|
use super::ReflectDeserializerProcessor;
|
||||||
|
|
||||||
@ -49,4 +49,11 @@ impl<'de, P: ReflectDeserializerProcessor> Visitor<'de> for StructVisitor<'_, P>
|
|||||||
self.processor,
|
self.processor,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn visit_unit<E>(self) -> Result<Self::Value, E>
|
||||||
|
where
|
||||||
|
E: Error,
|
||||||
|
{
|
||||||
|
Ok(DynamicStruct::default())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user