From 25684f0f34417cf7b993eecd128ed07f0b744002 Mon Sep 17 00:00:00 2001 From: Gino Valente Date: Wed, 21 Sep 2022 22:32:54 -0700 Subject: [PATCH] Use FromReflect when deserializing --- crates/bevy_reflect/src/lib.rs | 5 +- crates/bevy_reflect/src/serde/de.rs | 277 +++++++++++++++++++-------- crates/bevy_reflect/src/serde/mod.rs | 34 ++-- examples/reflection/reflection.rs | 14 +- 4 files changed, 223 insertions(+), 107 deletions(-) diff --git a/crates/bevy_reflect/src/lib.rs b/crates/bevy_reflect/src/lib.rs index 0c114015452733..e6ee0c75296526 100644 --- a/crates/bevy_reflect/src/lib.rs +++ b/crates/bevy_reflect/src/lib.rs @@ -484,6 +484,7 @@ mod tests { struct Foo { a: u32, #[reflect(ignore)] + #[reflect(default)] _b: u32, c: Vec, d: HashMap, @@ -533,9 +534,9 @@ mod tests { let mut deserializer = Deserializer::from_str(&serialized).unwrap(); let reflect_deserializer = UntypedReflectDeserializer::new(®istry); let value = reflect_deserializer.deserialize(&mut deserializer).unwrap(); - let dynamic_struct = value.take::().unwrap(); + let output = value.take::().unwrap(); - assert!(foo.reflect_partial_eq(&dynamic_struct).unwrap()); + assert!(foo.reflect_partial_eq(&output).unwrap()); } #[test] diff --git a/crates/bevy_reflect/src/serde/de.rs b/crates/bevy_reflect/src/serde/de.rs index 6a5020b02c52da..317382679ab59b 100644 --- a/crates/bevy_reflect/src/serde/de.rs +++ b/crates/bevy_reflect/src/serde/de.rs @@ -2,9 +2,9 @@ use crate::serde::SerializationData; use crate::{ ArrayInfo, DynamicArray, DynamicEnum, DynamicList, DynamicMap, DynamicStruct, DynamicTuple, DynamicTupleStruct, DynamicVariant, EnumInfo, ListInfo, Map, MapInfo, NamedField, Reflect, - ReflectDeserialize, StructInfo, StructVariantInfo, Tuple, TupleInfo, TupleStruct, - TupleStructInfo, TupleVariantInfo, TypeInfo, TypeRegistration, TypeRegistry, UnnamedField, - VariantInfo, + ReflectDeserialize, ReflectFromReflect, StructInfo, StructVariantInfo, Tuple, TupleInfo, + TupleStruct, TupleStructInfo, TupleVariantInfo, TypeInfo, TypeRegistration, TypeRegistry, + UnnamedField, VariantInfo, }; use erased_serde::Deserializer; use serde::de::{ @@ -153,35 +153,74 @@ impl<'de> Deserialize<'de> for Ident { /// A general purpose deserializer for reflected types. /// -/// This will return a [`Box`] containing the deserialized data. -/// For non-value types, this `Box` will contain the dynamic equivalent. For example, a -/// deserialized struct will return a [`DynamicStruct`] and a `Vec` will return a -/// [`DynamicList`]. For value types, this `Box` will contain the actual value. -/// For example, an `f32` will contain the actual `f32` type. +/// This will always return a [`Box`] containing the deserialized data. +/// +/// If using [`UntypedReflectDeserializer::new`], then this will correspond to the +/// concrete type, made possible via [`FromReflect`]. /// -/// This means that converting to any concrete instance will require the use of -/// [`FromReflect`], or downcasting for value types. +/// If using [`UntypedReflectDeserializer::new_dynamic`], then this `Box` will contain +/// the dynamic equivalent. +/// For example, a deserialized struct will return a [`DynamicStruct`] and a `Vec` will return a +/// [`DynamicList`]. /// -/// Because the type isn't known ahead of time, the serialized data must take the form of -/// a map containing the following entries (in order): -/// 1. `type`: The _full_ [type name] -/// 2. `value`: The serialized value of the reflected type +/// For value types, this `Box` will always contain the actual concrete value. +/// For example, an `f32` will contain the actual `f32` type. /// /// If the type is already known and the [`TypeInfo`] for it can be retrieved, -/// [`TypedReflectDeserializer`] may be used instead to avoid requiring these entries. +/// [`TypedReflectDeserializer`] may be used instead. /// /// [`Box`]: crate::Reflect +/// [`FromReflect`]: crate::FromReflect /// [`DynamicStruct`]: crate::DynamicStruct /// [`DynamicList`]: crate::DynamicList -/// [`FromReflect`]: crate::FromReflect -/// [type name]: std::any::type_name pub struct UntypedReflectDeserializer<'a> { registry: &'a TypeRegistry, + auto_convert: bool, } impl<'a> UntypedReflectDeserializer<'a> { + /// Create a new untyped deserializer for reflected types. + /// + /// This will automatically handle the conversion of the deserialized data internally using [`FromReflect`]. + /// If this is undesired, such as for types that do not implement `FromReflect` or are meant to be fully + /// constructed at a later time, you can use the [`new_dynamic`](Self::new_dynamic) function instead. + /// + /// # Arguments + /// + /// * `registry`: The type registry + /// pub fn new(registry: &'a TypeRegistry) -> Self { - Self { registry } + Self { + registry, + auto_convert: true, + } + } + + /// Create a new typed deserializer for reflected types. + /// + /// Unlike the [`new`](Self::new) function, this does not automatically handle any conversion internally + /// using [`FromReflect`]. + /// + /// # Arguments + /// + /// * `registration`: The registration of the expected type to be deserialized + /// * `registry`: The type registry + /// + pub fn new_dynamic(registry: &'a TypeRegistry) -> Self { + Self { + registry, + auto_convert: false, + } + } + + /// Returns true if automatic conversions using [`FromReflect`](crate::FromReflect) are enabled. + pub fn auto_convert(&self) -> bool { + self.auto_convert + } + + /// Enable/disable automatic conversions using [`FromReflect`](crate::FromReflect). + pub fn set_auto_convert(&mut self, value: bool) { + self.auto_convert = value; } } @@ -194,12 +233,14 @@ impl<'a, 'de> DeserializeSeed<'de> for UntypedReflectDeserializer<'a> { { deserializer.deserialize_any(UntypedReflectDeserializerVisitor { registry: self.registry, + auto_convert: self.auto_convert, }) } } struct UntypedReflectDeserializerVisitor<'a> { registry: &'a TypeRegistry, + auto_convert: bool, } impl<'a, 'de> Visitor<'de> for UntypedReflectDeserializerVisitor<'a> { @@ -223,6 +264,7 @@ impl<'a, 'de> Visitor<'de> for UntypedReflectDeserializerVisitor<'a> { let value = map.next_value_seed(TypedReflectDeserializer { registration, registry: self.registry, + auto_convert: self.auto_convert, })?; Ok(value) } @@ -230,34 +272,79 @@ impl<'a, 'de> Visitor<'de> for UntypedReflectDeserializerVisitor<'a> { /// A deserializer for reflected types whose [`TypeInfo`] is known. /// -/// This will return a [`Box`] containing the deserialized data. -/// For non-value types, this `Box` will contain the dynamic equivalent. For example, a -/// deserialized struct will return a [`DynamicStruct`] and a `Vec` will return a -/// [`DynamicList`]. For value types, this `Box` will contain the actual value. -/// For example, an `f32` will contain the actual `f32` type. +/// This will always return a [`Box`] containing the deserialized data. +/// +/// If using [`TypedReflectDeserializer::new`], then this will correspond to the +/// concrete type, made possible via [`FromReflect`]. /// -/// This means that converting to any concrete instance will require the use of -/// [`FromReflect`], or downcasting for value types. +/// If using [`TypedReflectDeserializer::new_dynamic`], then this `Box` will contain +/// the dynamic equivalent. +/// For example, a deserialized struct will return a [`DynamicStruct`] and a `Vec` will return a +/// [`DynamicList`]. +/// +/// For value types, this `Box` will always contain the actual concrete value. +/// For example, an `f32` will contain the actual `f32` type. /// /// If the type is not known ahead of time, use [`UntypedReflectDeserializer`] instead. /// /// [`TypeInfo`]: crate::TypeInfo /// [`Box`]: crate::Reflect +/// [`FromReflect`]: crate::FromReflect /// [`DynamicStruct`]: crate::DynamicStruct /// [`DynamicList`]: crate::DynamicList -/// [`FromReflect`]: crate::FromReflect pub struct TypedReflectDeserializer<'a> { registration: &'a TypeRegistration, registry: &'a TypeRegistry, + auto_convert: bool, } impl<'a> TypedReflectDeserializer<'a> { + /// Create a new typed deserializer for reflected types. + /// + /// This will automatically handle the conversion of the deserialized data internally using [`FromReflect`]. + /// If this is undesired, such as for types that do not implement `FromReflect` or are meant to be fully + /// constructed at a later time, you can use the [`new_dynamic`](Self::new_dynamic) function instead. + /// + /// # Arguments + /// + /// * `registration`: The registration of the expected type to be deserialized + /// * `registry`: The type registry + /// pub fn new(registration: &'a TypeRegistration, registry: &'a TypeRegistry) -> Self { Self { registration, registry, + auto_convert: true, + } + } + + /// Create a new typed deserializer for reflected types. + /// + /// Unlike the [`new`](Self::new) function, this does not automatically handle any conversion internally + /// using [`FromReflect`]. + /// + /// # Arguments + /// + /// * `registration`: The registration of the expected type to be deserialized + /// * `registry`: The type registry + /// + fn new_dynamic(registration: &'a TypeRegistration, registry: &'a TypeRegistry) -> Self { + Self { + registration, + registry, + auto_convert: false, } } + + /// Returns true if automatic conversions using [`FromReflect`](crate::FromReflect) are enabled. + pub fn auto_convert(&self) -> bool { + self.auto_convert + } + + /// Enable/disable automatic conversions using [`FromReflect`](crate::FromReflect). + pub fn set_auto_convert(&mut self, value: bool) { + self.auto_convert = value; + } } impl<'a, 'de> DeserializeSeed<'de> for TypedReflectDeserializer<'a> { @@ -275,7 +362,7 @@ impl<'a, 'de> DeserializeSeed<'de> for TypedReflectDeserializer<'a> { return Ok(value); } - match self.registration.type_info() { + let output: Box = match self.registration.type_info() { TypeInfo::Struct(struct_info) => { let mut dynamic_struct = deserializer.deserialize_struct( struct_info.name(), @@ -287,7 +374,7 @@ impl<'a, 'de> DeserializeSeed<'de> for TypedReflectDeserializer<'a> { }, )?; dynamic_struct.set_name(struct_info.type_name().to_string()); - Ok(Box::new(dynamic_struct)) + Box::new(dynamic_struct) } TypeInfo::TupleStruct(tuple_struct_info) => { let mut dynamic_tuple_struct = deserializer.deserialize_tuple_struct( @@ -300,7 +387,7 @@ impl<'a, 'de> DeserializeSeed<'de> for TypedReflectDeserializer<'a> { }, )?; dynamic_tuple_struct.set_name(tuple_struct_info.type_name().to_string()); - Ok(Box::new(dynamic_tuple_struct)) + Box::new(dynamic_tuple_struct) } TypeInfo::List(list_info) => { let mut dynamic_list = deserializer.deserialize_seq(ListVisitor { @@ -308,7 +395,7 @@ impl<'a, 'de> DeserializeSeed<'de> for TypedReflectDeserializer<'a> { registry: self.registry, })?; dynamic_list.set_name(list_info.type_name().to_string()); - Ok(Box::new(dynamic_list)) + Box::new(dynamic_list) } TypeInfo::Array(array_info) => { let mut dynamic_array = deserializer.deserialize_tuple( @@ -319,7 +406,7 @@ impl<'a, 'de> DeserializeSeed<'de> for TypedReflectDeserializer<'a> { }, )?; dynamic_array.set_name(array_info.type_name().to_string()); - Ok(Box::new(dynamic_array)) + Box::new(dynamic_array) } TypeInfo::Map(map_info) => { let mut dynamic_map = deserializer.deserialize_map(MapVisitor { @@ -327,7 +414,7 @@ impl<'a, 'de> DeserializeSeed<'de> for TypedReflectDeserializer<'a> { registry: self.registry, })?; dynamic_map.set_name(map_info.type_name().to_string()); - Ok(Box::new(dynamic_map)) + Box::new(dynamic_map) } TypeInfo::Tuple(tuple_info) => { let mut dynamic_tuple = deserializer.deserialize_tuple( @@ -338,7 +425,7 @@ impl<'a, 'de> DeserializeSeed<'de> for TypedReflectDeserializer<'a> { }, )?; dynamic_tuple.set_name(tuple_info.type_name().to_string()); - Ok(Box::new(dynamic_tuple)) + Box::new(dynamic_tuple) } TypeInfo::Enum(enum_info) => { let type_name = enum_info.type_name(); @@ -359,23 +446,45 @@ impl<'a, 'de> DeserializeSeed<'de> for TypedReflectDeserializer<'a> { )? }; dynamic_enum.set_name(type_name.to_string()); - Ok(Box::new(dynamic_enum)) + Box::new(dynamic_enum) } TypeInfo::Value(_) => { // This case should already be handled - Err(de::Error::custom(format_args!( + return Err(Error::custom(format_args!( "the TypeRegistration for {} doesn't have ReflectDeserialize", type_name - ))) + ))); } TypeInfo::Dynamic(_) => { // We could potentially allow this but we'd have no idea what the actual types of the // fields are and would rely on the deserializer to determine them (e.g. `i32` vs `i64`) - Err(de::Error::custom(format_args!( + return Err(Error::custom(format_args!( "cannot deserialize arbitrary dynamic type {}", type_name - ))) + ))); } + }; + + // Note: This should really only happen at the "root" if `auto_convert` is enabled. + // Since `FromReflect` is naturally recursive, performing this at every level is redundant. + if self.auto_convert { + self.registration + .data::() + .ok_or_else(|| { + Error::custom(format!( + "missing `ReflectFromReflect` registration for `{}`", + type_name + )) + })? + .from_reflect(output.as_ref()) + .ok_or_else(|| { + Error::custom(format!( + "failed to convert `{}` using `FromReflect`", + type_name + )) + }) + } else { + Ok(output) } } } @@ -431,10 +540,10 @@ impl<'a, 'de> Visitor<'de> for TupleStructVisitor<'a> { get_registration(field.type_id(), field.type_name(), self.registry) }; - while let Some(value) = seq.next_element_seed(TypedReflectDeserializer { - registration: get_field_registration(index)?, - registry: self.registry, - })? { + while let Some(value) = seq.next_element_seed(TypedReflectDeserializer::new_dynamic( + get_field_registration(index)?, + self.registry, + ))? { tuple_struct.insert_boxed(value); index += 1; if index >= self.tuple_struct_info.field_len() { @@ -500,10 +609,10 @@ impl<'a, 'de> Visitor<'de> for ArrayVisitor<'a> { self.array_info.item_type_name(), self.registry, )?; - while let Some(value) = seq.next_element_seed(TypedReflectDeserializer { + while let Some(value) = seq.next_element_seed(TypedReflectDeserializer::new_dynamic( registration, - registry: self.registry, - })? { + self.registry, + ))? { vec.push(value); } @@ -540,10 +649,10 @@ impl<'a, 'de> Visitor<'de> for ListVisitor<'a> { self.list_info.item_type_name(), self.registry, )?; - while let Some(value) = seq.next_element_seed(TypedReflectDeserializer { + while let Some(value) = seq.next_element_seed(TypedReflectDeserializer::new_dynamic( registration, - registry: self.registry, - })? { + self.registry, + ))? { list.push_box(value); } Ok(list) @@ -577,14 +686,14 @@ impl<'a, 'de> Visitor<'de> for MapVisitor<'a> { self.map_info.value_type_name(), self.registry, )?; - while let Some(key) = map.next_key_seed(TypedReflectDeserializer { - registration: key_registration, - registry: self.registry, - })? { - let value = map.next_value_seed(TypedReflectDeserializer { - registration: value_registration, - registry: self.registry, - })?; + while let Some(key) = map.next_key_seed(TypedReflectDeserializer::new_dynamic( + key_registration, + self.registry, + ))? { + let value = map.next_value_seed(TypedReflectDeserializer::new_dynamic( + value_registration, + self.registry, + ))?; dynamic_map.insert_boxed(key, value); } @@ -634,10 +743,10 @@ impl<'a, 'de> Visitor<'de> for EnumVisitor<'a> { let field = tuple_info.field_at(0).unwrap(); let registration = get_registration(field.type_id(), field.type_name(), self.registry)?; - let value = variant.newtype_variant_seed(TypedReflectDeserializer { + let value = variant.newtype_variant_seed(TypedReflectDeserializer::new_dynamic( registration, - registry: self.registry, - })?; + self.registry, + ))?; let mut dynamic_tuple = DynamicTuple::default(); dynamic_tuple.insert_boxed(value); dynamic_tuple.into() @@ -721,10 +830,7 @@ impl<'a, 'de> Visitor<'de> for OptionVisitor<'a> { let field = tuple_info.field_at(0).unwrap(); let registration = get_registration(field.type_id(), field.type_name(), self.registry)?; - let de = TypedReflectDeserializer { - registration, - registry: self.registry, - }; + let de = TypedReflectDeserializer::new_dynamic(registration, self.registry); let mut value = DynamicTuple::default(); value.insert_boxed(de.deserialize(deserializer)?); let mut option = DynamicEnum::default(); @@ -768,10 +874,10 @@ where )) })?; let registration = get_registration(field.type_id(), field.type_name(), registry)?; - let value = map.next_value_seed(TypedReflectDeserializer { + let value = map.next_value_seed(TypedReflectDeserializer::new_dynamic( registration, registry, - })?; + ))?; dynamic_struct.insert_boxed(&key, value); } @@ -797,10 +903,10 @@ where get_registration(field.type_id(), field.type_name(), registry) }; - while let Some(value) = seq.next_element_seed(TypedReflectDeserializer { - registration: get_field_registration(index)?, + while let Some(value) = seq.next_element_seed(TypedReflectDeserializer::new_dynamic( + get_field_registration(index)?, registry, - })? { + ))? { tuple.insert_boxed(value); index += 1; if index >= info.get_field_len() { @@ -846,7 +952,7 @@ mod tests { use crate as bevy_reflect; use crate::serde::{TypedReflectDeserializer, UntypedReflectDeserializer}; - use crate::{DynamicEnum, FromReflect, Reflect, ReflectDeserialize, TypeRegistry}; + use crate::{DynamicEnum, Reflect, ReflectDeserialize, TypeRegistry}; #[derive(Reflect, Debug, PartialEq)] struct MyStruct { @@ -991,11 +1097,12 @@ mod tests { let registry = get_registry(); let reflect_deserializer = UntypedReflectDeserializer::new(®istry); let mut ron_deserializer = ron::de::Deserializer::from_str(input).unwrap(); - let dynamic_output = reflect_deserializer + let output = reflect_deserializer .deserialize(&mut ron_deserializer) + .unwrap() + .take::() .unwrap(); - let output = ::from_reflect(dynamic_output.as_ref()).unwrap(); assert_eq!(expected, output); } @@ -1008,10 +1115,9 @@ mod tests { let registry = get_registry(); let reflect_deserializer = UntypedReflectDeserializer::new(®istry); let mut ron_deserializer = ron::de::Deserializer::from_str(input).unwrap(); - let dynamic_output = reflect_deserializer + let output = reflect_deserializer .deserialize(&mut ron_deserializer) - .unwrap(); - let output = dynamic_output + .unwrap() .take::() .expect("underlying type should be f32"); assert_eq!(1.23, output); @@ -1035,11 +1141,12 @@ mod tests { let registration = registry.get(TypeId::of::()).unwrap(); let reflect_deserializer = TypedReflectDeserializer::new(registration, ®istry); let mut ron_deserializer = ron::de::Deserializer::from_str(input).unwrap(); - let dynamic_output = reflect_deserializer + let output = reflect_deserializer .deserialize(&mut ron_deserializer) + .unwrap() + .take::() .unwrap(); - let output = ::from_reflect(dynamic_output.as_ref()).unwrap(); assert_eq!(expected, output); } @@ -1075,11 +1182,12 @@ mod tests { let reflect_deserializer = UntypedReflectDeserializer::new(®istry); let mut ron_deserializer = ron::de::Deserializer::from_str(input).unwrap(); - let dynamic_output = reflect_deserializer + let output = reflect_deserializer .deserialize(&mut ron_deserializer) + .unwrap() + .take::() .unwrap(); - let output = ::from_reflect(dynamic_output.as_ref()).unwrap(); assert_eq!(expected, output, "failed to deserialize Options"); // === Implicit Some === // @@ -1097,11 +1205,12 @@ mod tests { let reflect_deserializer = UntypedReflectDeserializer::new(®istry); let mut ron_deserializer = ron::de::Deserializer::from_str(input).unwrap(); - let dynamic_output = reflect_deserializer + let output = reflect_deserializer .deserialize(&mut ron_deserializer) + .unwrap() + .take::() .unwrap(); - let output = ::from_reflect(dynamic_output.as_ref()).unwrap(); assert_eq!( expected, output, "failed to deserialize Options with implicit Some" @@ -1125,7 +1234,7 @@ mod tests { let input = r#"{ "bevy_reflect::serde::de::tests::enum_should_deserialize::MyEnum": Unit, }"#; - let reflect_deserializer = UntypedReflectDeserializer::new(®istry); + let reflect_deserializer = UntypedReflectDeserializer::new_dynamic(®istry); let mut deserializer = ron::de::Deserializer::from_str(input).unwrap(); let output = reflect_deserializer.deserialize(&mut deserializer).unwrap(); @@ -1136,7 +1245,7 @@ mod tests { let input = r#"{ "bevy_reflect::serde::de::tests::enum_should_deserialize::MyEnum": NewType(123), }"#; - let reflect_deserializer = UntypedReflectDeserializer::new(®istry); + let reflect_deserializer = UntypedReflectDeserializer::new_dynamic(®istry); let mut deserializer = ron::de::Deserializer::from_str(input).unwrap(); let output = reflect_deserializer.deserialize(&mut deserializer).unwrap(); @@ -1147,7 +1256,7 @@ mod tests { let input = r#"{ "bevy_reflect::serde::de::tests::enum_should_deserialize::MyEnum": Tuple(1.23, 3.21), }"#; - let reflect_deserializer = UntypedReflectDeserializer::new(®istry); + let reflect_deserializer = UntypedReflectDeserializer::new_dynamic(®istry); let mut deserializer = ron::de::Deserializer::from_str(input).unwrap(); let output = reflect_deserializer.deserialize(&mut deserializer).unwrap(); @@ -1160,7 +1269,7 @@ mod tests { value: "I <3 Enums", ), }"#; - let reflect_deserializer = UntypedReflectDeserializer::new(®istry); + let reflect_deserializer = UntypedReflectDeserializer::new_dynamic(®istry); let mut deserializer = ron::de::Deserializer::from_str(input).unwrap(); let output = reflect_deserializer.deserialize(&mut deserializer).unwrap(); diff --git a/crates/bevy_reflect/src/serde/mod.rs b/crates/bevy_reflect/src/serde/mod.rs index 3355ed38d0b115..eb2d4a878f7914 100644 --- a/crates/bevy_reflect/src/serde/mod.rs +++ b/crates/bevy_reflect/src/serde/mod.rs @@ -8,11 +8,11 @@ pub use type_data::*; #[cfg(test)] mod tests { - use crate::{self as bevy_reflect, DynamicTupleStruct}; use crate::{ + self as bevy_reflect, serde::{ReflectSerializer, UntypedReflectDeserializer}, type_registry::TypeRegistry, - DynamicStruct, Reflect, + DynamicTupleStruct, Reflect, }; use serde::de::DeserializeSeed; @@ -23,8 +23,10 @@ mod tests { struct TestStruct { a: i32, #[reflect(ignore)] + #[reflect(default)] b: i32, #[reflect(skip_serializing)] + #[reflect(default)] c: i32, d: i32, } @@ -43,19 +45,19 @@ mod tests { let serialized = ron::ser::to_string_pretty(&serializer, ron::ser::PrettyConfig::default()).unwrap(); - let mut expected = DynamicStruct::default(); - expected.insert("a", 3); - expected.insert("d", 6); - let mut deserializer = ron::de::Deserializer::from_str(&serialized).unwrap(); let reflect_deserializer = UntypedReflectDeserializer::new(®istry); let value = reflect_deserializer.deserialize(&mut deserializer).unwrap(); - let deserialized = value.take::().unwrap(); + let deserialized = value.take::().unwrap(); - assert!( - expected.reflect_partial_eq(&deserialized).unwrap(), - "Expected {expected:?} found {deserialized:?}" - ); + let expected = TestStruct { + a: 3, + b: 0, // <- ignored + c: 0, // <- serialization skipped + d: 6, + }; + + assert_eq!(expected, deserialized); } #[test] @@ -78,15 +80,15 @@ mod tests { let serialized = ron::ser::to_string_pretty(&serializer, ron::ser::PrettyConfig::default()).unwrap(); - let mut expected = DynamicTupleStruct::default(); - expected.insert(3); - expected.insert(6); - let mut deserializer = ron::de::Deserializer::from_str(&serialized).unwrap(); - let reflect_deserializer = UntypedReflectDeserializer::new(®istry); + let reflect_deserializer = UntypedReflectDeserializer::new_dynamic(®istry); let value = reflect_deserializer.deserialize(&mut deserializer).unwrap(); let deserialized = value.take::().unwrap(); + let mut expected = DynamicTupleStruct::default(); + expected.insert(3); + expected.insert(6); + assert!( expected.reflect_partial_eq(&deserialized).unwrap(), "Expected {expected:?} found {deserialized:?}" diff --git a/examples/reflection/reflection.rs b/examples/reflection/reflection.rs index 31f95e8d758a54..8cdb1e89b700d5 100644 --- a/examples/reflection/reflection.rs +++ b/examples/reflection/reflection.rs @@ -33,11 +33,11 @@ fn main() { /// To do this, you can either define a `#[reflect(default = "...")]` attribute on the ignored field, or /// opt-out of `FromReflect`'s auto-derive using the `#[from_reflect(auto_derive = false)]` attribute. #[derive(Reflect)] -#[from_reflect(auto_derive = false)] pub struct Foo { a: usize, nested: Bar, #[reflect(ignore)] + #[reflect(default)] _ignored: NonReflectedValue, } @@ -48,6 +48,7 @@ pub struct Bar { b: usize, } +#[derive(Default)] pub struct NonReflectedValue { _a: usize, } @@ -93,10 +94,13 @@ fn setup(type_registry: Res) { let mut deserializer = ron::de::Deserializer::from_str(&ron_string).unwrap(); let reflect_value = reflect_deserializer.deserialize(&mut deserializer).unwrap(); - // Deserializing returns a Box value. Generally, deserializing a value will return - // the "dynamic" variant of a type. For example, deserializing a struct will return the - // DynamicStruct type. "Value types" will be deserialized as themselves. - let _deserialized_struct = reflect_value.downcast_ref::(); + // Deserializing returns a `Box` value. Generally, deserializing a value will + // attempt to return the "real" type by utilizing `FromReflect`. + // If you can't use `FromReflect`, then you can try using `UntypedReflectDeserializer::new_dynamic`, + // which will return the "dynamic" variant of a type. + // For example, deserializing a struct will return the `DynamicStruct` type. + // In either case, "value types" will always be deserialized as themselves. + let _deserialized_struct = reflect_value.downcast_ref::(); // Reflect has its own `partial_eq` implementation, named `reflect_partial_eq`. This behaves // like normal `partial_eq`, but it treats "dynamic" and "non-dynamic" types the same. The