bevy_reflect: Improve reflection serialization error messages (#13867)
# Objective The error messages that appear when a value cannot be serialized or deserialized via reflection could be slightly improved. When one of these operations fails, some users are confused about how to resolve the issue. I've spoken with a few who didn't know they could register `ReflectSerialize` themselves. We should try to clarify this to some degree in the error messages. ## Solution Add some more detail to the error messages. For example, replacing this: ``` Type 'core::ops::RangeInclusive<f32>' did not register ReflectSerialize ``` with this: ``` Type `core::ops::RangeInclusive<f32>` did not register the `ReflectSerialize` type data. For certain types, this may need to be registered manually using `register_type_data` ``` I also added a separate error message if the type was not registered in the type registry at all: ``` Type `core::ops::RangeInclusive<f32>` is not registered in the type registry ``` ## Testing You can test locally by running: ``` cargo test --package bevy_reflect ``` --- ## Changelog - Added error message for missing type registration when serializing reflect data - Changed error message for missing `ReflectSerialize` registration when serializing reflect data - Changed error message for missing `ReflectDeserialize` registration when deserializing reflect data
This commit is contained in:
parent
6273227e09
commit
53910e07ae
@ -620,7 +620,7 @@ impl<'a, 'de> DeserializeSeed<'de> for TypedReflectDeserializer<'a> {
|
||||
TypeInfo::Value(_) => {
|
||||
// This case should already be handled
|
||||
Err(Error::custom(format_args!(
|
||||
"the TypeRegistration for {type_path} doesn't have ReflectDeserialize",
|
||||
"Type `{type_path}` did not register the `ReflectDeserialize` type data. For certain types, this may need to be registered manually using `register_type_data`",
|
||||
)))
|
||||
}
|
||||
}
|
||||
@ -1174,6 +1174,7 @@ mod tests {
|
||||
use bincode::Options;
|
||||
use std::any::TypeId;
|
||||
use std::f32::consts::PI;
|
||||
use std::ops::RangeInclusive;
|
||||
|
||||
use serde::de::DeserializeSeed;
|
||||
use serde::Deserialize;
|
||||
@ -1632,4 +1633,18 @@ mod tests {
|
||||
let output = <MyStruct as FromReflect>::from_reflect(dynamic_output.as_ref()).unwrap();
|
||||
assert_eq!(expected, output);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn should_return_error_if_missing_type_data() {
|
||||
let mut registry = TypeRegistry::new();
|
||||
registry.register::<RangeInclusive<f32>>();
|
||||
|
||||
let input = r#"{"core::ops::RangeInclusive<f32>":(start:0.0,end:1.0)}"#;
|
||||
let mut deserializer = ron::de::Deserializer::from_str(input).unwrap();
|
||||
let reflect_deserializer = ReflectDeserializer::new(®istry);
|
||||
let error = reflect_deserializer
|
||||
.deserialize(&mut deserializer)
|
||||
.unwrap_err();
|
||||
assert_eq!(error, ron::Error::Message("Type `core::ops::RangeInclusive<f32>` did not register the `ReflectDeserialize` type data. For certain types, this may need to be registered manually using `register_type_data`".to_string()));
|
||||
}
|
||||
}
|
||||
|
||||
@ -39,14 +39,20 @@ fn get_serializable<'a, E: Error>(
|
||||
))
|
||||
})?;
|
||||
|
||||
let reflect_serialize = type_registry
|
||||
.get_type_data::<ReflectSerialize>(info.type_id())
|
||||
.ok_or_else(|| {
|
||||
let registration = type_registry.get(info.type_id()).ok_or_else(|| {
|
||||
Error::custom(format_args!(
|
||||
"Type '{}' did not register ReflectSerialize",
|
||||
"Type `{}` is not registered in the type registry",
|
||||
info.type_path(),
|
||||
))
|
||||
})?;
|
||||
|
||||
let reflect_serialize = registration.data::<ReflectSerialize>().ok_or_else(|| {
|
||||
Error::custom(format_args!(
|
||||
"Type `{}` did not register the `ReflectSerialize` type data. For certain types, this may need to be registered manually using `register_type_data`",
|
||||
info.type_path(),
|
||||
))
|
||||
})?;
|
||||
|
||||
Ok(reflect_serialize.get_serializable(reflect_value))
|
||||
}
|
||||
|
||||
@ -543,6 +549,7 @@ mod tests {
|
||||
use ron::ser::PrettyConfig;
|
||||
use serde::Serialize;
|
||||
use std::f32::consts::PI;
|
||||
use std::ops::RangeInclusive;
|
||||
|
||||
#[derive(Reflect, Debug, PartialEq)]
|
||||
struct MyStruct {
|
||||
@ -932,4 +939,36 @@ mod tests {
|
||||
|
||||
assert_eq!(expected, output);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn should_return_error_if_missing_registration() {
|
||||
let value = RangeInclusive::<f32>::new(0.0, 1.0);
|
||||
let registry = TypeRegistry::new();
|
||||
|
||||
let serializer = ReflectSerializer::new(&value, ®istry);
|
||||
let error = ron::ser::to_string(&serializer).unwrap_err();
|
||||
assert_eq!(
|
||||
error,
|
||||
ron::Error::Message(
|
||||
"Type `core::ops::RangeInclusive<f32>` is not registered in the type registry"
|
||||
.to_string()
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn should_return_error_if_missing_type_data() {
|
||||
let value = RangeInclusive::<f32>::new(0.0, 1.0);
|
||||
let mut registry = TypeRegistry::new();
|
||||
registry.register::<RangeInclusive<f32>>();
|
||||
|
||||
let serializer = ReflectSerializer::new(&value, ®istry);
|
||||
let error = ron::ser::to_string(&serializer).unwrap_err();
|
||||
assert_eq!(
|
||||
error,
|
||||
ron::Error::Message(
|
||||
"Type `core::ops::RangeInclusive<f32>` did not register the `ReflectSerialize` type data. For certain types, this may need to be registered manually using `register_type_data`".to_string()
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user