Skip to content

Commit 5b0edd5

Browse files
committed
Support Option types
1 parent c751b17 commit 5b0edd5

File tree

2 files changed

+225
-24
lines changed

2 files changed

+225
-24
lines changed

crates/bevy_reflect/src/serde/de.rs

Lines changed: 142 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -318,15 +318,23 @@ impl<'a, 'de> DeserializeSeed<'de> for TypedReflectDeserializer<'a> {
318318
Ok(Box::new(dynamic_tuple))
319319
}
320320
TypeInfo::Enum(enum_info) => {
321-
let mut dynamic_enum = deserializer.deserialize_enum(
322-
enum_info.name(),
323-
enum_info.variant_names(),
324-
EnumVisitor {
321+
let type_name = enum_info.type_name();
322+
let mut dynamic_enum = if type_name.starts_with("core::option::Option") {
323+
deserializer.deserialize_option(OptionVisitor {
325324
enum_info,
326325
registry: self.registry,
327-
},
328-
)?;
329-
dynamic_enum.set_name(enum_info.type_name().to_string());
326+
})?
327+
} else {
328+
deserializer.deserialize_enum(
329+
enum_info.name(),
330+
enum_info.variant_names(),
331+
EnumVisitor {
332+
enum_info,
333+
registry: self.registry,
334+
},
335+
)?
336+
};
337+
dynamic_enum.set_name(type_name.to_string());
330338
Ok(Box::new(dynamic_enum))
331339
}
332340
TypeInfo::Value(_) => {
@@ -588,16 +596,7 @@ impl<'a, 'de> Visitor<'de> for EnumVisitor<'a> {
588596
)?
589597
.into(),
590598
VariantInfo::Tuple(tuple_info) if tuple_info.field_len() == 1 => {
591-
let field = tuple_info.field_at(0).unwrap();
592-
let type_info =
593-
self.registry
594-
.get_type_info(field.type_id())
595-
.ok_or_else(|| {
596-
Error::custom(format_args!(
597-
"no registration found for type {}",
598-
field.type_name()
599-
))
600-
})?;
599+
let type_info = get_newtype_info(tuple_info, self.registry)?;
601600
let value = variant.newtype_variant_seed(TypedReflectDeserializer {
602601
type_info,
603602
registry: self.registry,
@@ -665,6 +664,54 @@ impl<'a, 'de> Visitor<'de> for TupleVariantVisitor<'a> {
665664
}
666665
}
667666

667+
struct OptionVisitor<'a> {
668+
enum_info: &'static EnumInfo,
669+
registry: &'a TypeRegistry,
670+
}
671+
672+
impl<'a, 'de> Visitor<'de> for OptionVisitor<'a> {
673+
type Value = DynamicEnum;
674+
675+
fn expecting(&self, formatter: &mut Formatter) -> fmt::Result {
676+
formatter.write_str("reflected option value of type ")?;
677+
formatter.write_str(self.enum_info.type_name())
678+
}
679+
680+
fn visit_some<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
681+
where
682+
D: serde::Deserializer<'de>,
683+
{
684+
let variant_info = self.enum_info.variant("Some").unwrap();
685+
match variant_info {
686+
VariantInfo::Tuple(tuple_info) if tuple_info.field_len() == 1 => {
687+
let type_info = get_newtype_info(tuple_info, self.registry)?;
688+
let de = TypedReflectDeserializer {
689+
type_info,
690+
registry: self.registry,
691+
};
692+
let mut value = DynamicTuple::default();
693+
value.insert_boxed(de.deserialize(deserializer)?);
694+
let mut option = DynamicEnum::default();
695+
option.set_variant("Some", value);
696+
Ok(option)
697+
}
698+
info => Err(Error::custom(format_args!(
699+
"invalid variant, expected `Some` but got `{}`",
700+
info.name()
701+
))),
702+
}
703+
}
704+
705+
fn visit_none<E>(self) -> Result<Self::Value, E>
706+
where
707+
E: Error,
708+
{
709+
let mut option = DynamicEnum::default();
710+
option.set_variant("None", ());
711+
Ok(option)
712+
}
713+
}
714+
668715
fn visit_struct<'de, T, V>(
669716
map: &mut V,
670717
info: &'static T,
@@ -732,6 +779,19 @@ where
732779
Ok(tuple)
733780
}
734781

782+
fn get_newtype_info<E: Error>(
783+
tuple_info: &'static TupleVariantInfo,
784+
registry: &TypeRegistry,
785+
) -> Result<&'static TypeInfo, E> {
786+
let field = tuple_info.field_at(0).unwrap();
787+
registry.get_type_info(field.type_id()).ok_or_else(|| {
788+
Error::custom(format_args!(
789+
"no registration found for type {}",
790+
field.type_name()
791+
))
792+
})
793+
}
794+
735795
fn get_type_info<E: de::Error>(
736796
type_id: TypeId,
737797
type_name: &str,
@@ -950,6 +1010,71 @@ mod tests {
9501010
assert_eq!(expected, output);
9511011
}
9521012

1013+
#[test]
1014+
fn should_deserialize_option() {
1015+
#[derive(Reflect, FromReflect, Debug, PartialEq)]
1016+
struct OptionTest {
1017+
none: Option<()>,
1018+
simple: Option<String>,
1019+
complex: Option<SomeStruct>,
1020+
}
1021+
1022+
let expected = OptionTest {
1023+
none: None,
1024+
simple: Some(String::from("Hello world!")),
1025+
complex: Some(SomeStruct { foo: 123 }),
1026+
};
1027+
1028+
let mut registry = get_registry();
1029+
registry.register::<OptionTest>();
1030+
registry.register::<Option<()>>();
1031+
1032+
// === Normal === //
1033+
let input = r#"{
1034+
"bevy_reflect::serde::de::tests::should_deserialize_option::OptionTest": (
1035+
none: None,
1036+
simple: Some("Hello world!"),
1037+
complex: Some((
1038+
foo: 123,
1039+
)),
1040+
),
1041+
}"#;
1042+
1043+
let reflect_deserializer = UntypedReflectDeserializer::new(&registry);
1044+
let mut ron_deserializer = ron::de::Deserializer::from_str(input).unwrap();
1045+
let dynamic_output = reflect_deserializer
1046+
.deserialize(&mut ron_deserializer)
1047+
.unwrap();
1048+
1049+
let output = <OptionTest as FromReflect>::from_reflect(dynamic_output.as_ref()).unwrap();
1050+
assert_eq!(expected, output, "failed to deserialize Options");
1051+
1052+
// === Implicit Some === //
1053+
let input = r#"
1054+
#![enable(implicit_some)]
1055+
{
1056+
"bevy_reflect::serde::de::tests::should_deserialize_option::OptionTest": (
1057+
none: None,
1058+
simple: "Hello world!",
1059+
complex: (
1060+
foo: 123,
1061+
),
1062+
),
1063+
}"#;
1064+
1065+
let reflect_deserializer = UntypedReflectDeserializer::new(&registry);
1066+
let mut ron_deserializer = ron::de::Deserializer::from_str(input).unwrap();
1067+
let dynamic_output = reflect_deserializer
1068+
.deserialize(&mut ron_deserializer)
1069+
.unwrap();
1070+
1071+
let output = <OptionTest as FromReflect>::from_reflect(dynamic_output.as_ref()).unwrap();
1072+
assert_eq!(
1073+
expected, output,
1074+
"failed to deserialize Options with implicit Some"
1075+
);
1076+
}
1077+
9531078
#[test]
9541079
fn enum_should_deserialize() {
9551080
#[derive(Reflect)]

crates/bevy_reflect/src/serde/ser.rs

Lines changed: 83 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -296,7 +296,15 @@ impl<'a> Serialize for EnumSerializer<'a> {
296296

297297
match variant_type {
298298
VariantType::Unit => {
299-
serializer.serialize_unit_variant(enum_name, variant_index, variant_name)
299+
if self
300+
.enum_value
301+
.type_name()
302+
.starts_with("core::option::Option")
303+
{
304+
serializer.serialize_none()
305+
} else {
306+
serializer.serialize_unit_variant(enum_name, variant_index, variant_name)
307+
}
300308
}
301309
VariantType::Struct => {
302310
let struct_info = match variant_info {
@@ -326,12 +334,20 @@ impl<'a> Serialize for EnumSerializer<'a> {
326334
}
327335
VariantType::Tuple if field_len == 1 => {
328336
let field = self.enum_value.field_at(0).unwrap();
329-
serializer.serialize_newtype_variant(
330-
enum_name,
331-
variant_index,
332-
variant_name,
333-
&TypedReflectSerializer::new(field, self.registry),
334-
)
337+
if self
338+
.enum_value
339+
.type_name()
340+
.starts_with("core::option::Option")
341+
{
342+
serializer.serialize_some(&TypedReflectSerializer::new(field, self.registry))
343+
} else {
344+
serializer.serialize_newtype_variant(
345+
enum_name,
346+
variant_index,
347+
variant_name,
348+
&TypedReflectSerializer::new(field, self.registry),
349+
)
350+
}
335351
}
336352
VariantType::Tuple => {
337353
let mut state = serializer.serialize_tuple_variant(
@@ -433,6 +449,7 @@ mod tests {
433449
use crate::serde::ReflectSerializer;
434450
use crate::{FromReflect, Reflect, ReflectSerialize, TypeRegistry};
435451
use bevy_utils::HashMap;
452+
use ron::extensions::Extensions;
436453
use ron::ser::PrettyConfig;
437454
use serde::Serialize;
438455
use std::f32::consts::PI;
@@ -577,6 +594,65 @@ mod tests {
577594
assert_eq!(expected, output);
578595
}
579596

597+
#[test]
598+
fn should_serialize_option() {
599+
#[derive(Reflect, FromReflect, Debug, PartialEq)]
600+
struct OptionTest {
601+
none: Option<()>,
602+
simple: Option<String>,
603+
complex: Option<SomeStruct>,
604+
}
605+
606+
let value = OptionTest {
607+
none: None,
608+
simple: Some(String::from("Hello world!")),
609+
complex: Some(SomeStruct { foo: 123 }),
610+
};
611+
612+
let registry = get_registry();
613+
let serializer = ReflectSerializer::new(&value, &registry);
614+
615+
// === Normal === //
616+
let config = PrettyConfig::default()
617+
.new_line(String::from("\n"))
618+
.decimal_floats(true)
619+
.indentor(String::from(" "));
620+
621+
let output = ron::ser::to_string_pretty(&serializer, config).unwrap();
622+
let expected = r#"{
623+
"bevy_reflect::serde::ser::tests::should_serialize_option::OptionTest": (
624+
none: None,
625+
simple: Some("Hello world!"),
626+
complex: Some((
627+
foo: 123,
628+
)),
629+
),
630+
}"#;
631+
632+
assert_eq!(expected, output);
633+
634+
// === Implicit Some === //
635+
let config = PrettyConfig::default()
636+
.new_line(String::from("\n"))
637+
.decimal_floats(true)
638+
.extensions(Extensions::IMPLICIT_SOME)
639+
.indentor(String::from(" "));
640+
641+
let output = ron::ser::to_string_pretty(&serializer, config).unwrap();
642+
let expected = r#"#![enable(implicit_some)]
643+
{
644+
"bevy_reflect::serde::ser::tests::should_serialize_option::OptionTest": (
645+
none: None,
646+
simple: "Hello world!",
647+
complex: (
648+
foo: 123,
649+
),
650+
),
651+
}"#;
652+
653+
assert_eq!(expected, output);
654+
}
655+
580656
#[test]
581657
fn enum_should_serialize() {
582658
#[derive(Reflect)]

0 commit comments

Comments
 (0)