diff --git a/crates/bevy_reflect/src/impls/std.rs b/crates/bevy_reflect/src/impls/std.rs index 734486715c..60704d602a 100644 --- a/crates/bevy_reflect/src/impls/std.rs +++ b/crates/bevy_reflect/src/impls/std.rs @@ -201,7 +201,7 @@ impl_reflect_opaque!(::core::num::NonZeroI8( )); impl_reflect_opaque!(::core::num::Wrapping()); impl_reflect_opaque!(::core::num::Saturating()); -impl_reflect_opaque!(::alloc::sync::Arc); +impl_reflect_opaque!(::alloc::sync::Arc); // `Serialize` and `Deserialize` only for platforms supported by serde: // https://github.com/serde-rs/serde/blob/3ffb86fc70efd3d329519e2dddfa306cc04f167c/serde/src/de/impls.rs#L1732 diff --git a/crates/bevy_reflect/src/serde/de/deserialize_with_registry.rs b/crates/bevy_reflect/src/serde/de/deserialize_with_registry.rs new file mode 100644 index 0000000000..ace4dc65b8 --- /dev/null +++ b/crates/bevy_reflect/src/serde/de/deserialize_with_registry.rs @@ -0,0 +1,83 @@ +use crate::serde::de::error_utils::make_custom_error; +use crate::{FromType, PartialReflect, TypeRegistry}; +use serde::Deserializer; + +/// Trait used to provide finer control when deserializing a reflected type with one of +/// the reflection deserializers. +/// +/// This trait is the reflection equivalent of `serde`'s [`Deserialize`] trait. +/// The main difference is that this trait provides access to the [`TypeRegistry`], +/// which means that we can use the registry and all its stored type information +/// to deserialize our type. +/// +/// This can be useful when writing a custom reflection deserializer where we may +/// want to handle parts of the deserialization process, but temporarily pass control +/// to the standard reflection deserializer for other parts. +/// +/// For the serialization equivalent of this trait, see [`SerializeWithRegistry`]. +/// +/// # Rationale +/// +/// Without this trait and its associated [type data], such a deserializer would have to +/// write out all of the deserialization logic itself, possibly including +/// unnecessary code duplication and trivial implementations. +/// +/// This is because a normal [`Deserialize`] implementation has no knowledge of the +/// [`TypeRegistry`] and therefore cannot create a reflection-based deserializer for +/// nested items. +/// +/// # Implementors +/// +/// In order for this to work with the reflection deserializers like [`TypedReflectDeserializer`] +/// and [`ReflectDeserializer`], implementors should be sure to register the +/// [`ReflectDeserializeWithRegistry`] type data. +/// This can be done [via the registry] or by adding `#[reflect(DeserializeWithRegistry)]` to +/// the type definition. +/// +/// [`Deserialize`]: ::serde::Deserialize +/// [`SerializeWithRegistry`]: crate::serde::SerializeWithRegistry +/// [type data]: ReflectDeserializeWithRegistry +/// [`TypedReflectDeserializer`]: crate::serde::TypedReflectDeserializer +/// [`ReflectDeserializer`]: crate::serde::ReflectDeserializer +/// [via the registry]: TypeRegistry::register_type_data +pub trait DeserializeWithRegistry<'de>: PartialReflect + Sized { + fn deserialize(deserializer: D, registry: &TypeRegistry) -> Result + where + D: Deserializer<'de>; +} + +/// Type data used to deserialize a [`PartialReflect`] type with a custom [`DeserializeWithRegistry`] implementation. +#[derive(Clone)] +pub struct ReflectDeserializeWithRegistry { + deserialize: fn( + deserializer: &mut dyn erased_serde::Deserializer, + registry: &TypeRegistry, + ) -> Result, erased_serde::Error>, +} + +impl ReflectDeserializeWithRegistry { + /// Deserialize a [`PartialReflect`] type with this type data's custom [`DeserializeWithRegistry`] implementation. + pub fn deserialize<'de, D>( + &self, + deserializer: D, + registry: &TypeRegistry, + ) -> Result, D::Error> + where + D: Deserializer<'de>, + { + let mut erased = ::erase(deserializer); + (self.deserialize)(&mut erased, registry).map_err(make_custom_error) + } +} + +impl DeserializeWithRegistry<'de>> FromType + for ReflectDeserializeWithRegistry +{ + fn from_type() -> Self { + Self { + deserialize: |deserializer, registry| { + Ok(Box::new(T::deserialize(deserializer, registry)?)) + }, + } + } +} diff --git a/crates/bevy_reflect/src/serde/de/deserializer.rs b/crates/bevy_reflect/src/serde/de/deserializer.rs index 6eddc2deed..1379fb3768 100644 --- a/crates/bevy_reflect/src/serde/de/deserializer.rs +++ b/crates/bevy_reflect/src/serde/de/deserializer.rs @@ -1,5 +1,6 @@ #[cfg(feature = "debug_stack")] use crate::serde::de::error_utils::TYPE_INFO_STACK; +use crate::serde::ReflectDeserializeWithRegistry; use crate::{ serde::{ de::{ @@ -9,7 +10,7 @@ use crate::{ }, TypeRegistrationDeserializer, }, - PartialReflect, ReflectDeserialize, TypeInfo, TypeRegistration, TypeRegistry, + PartialReflect, ReflectDeserialize, TypeInfo, TypePath, TypeRegistration, TypeRegistry, }; use core::{fmt, fmt::Formatter}; use serde::de::{DeserializeSeed, Error, IgnoredAny, MapAccess, Visitor}; @@ -231,6 +232,7 @@ pub struct TypedReflectDeserializer<'a> { } impl<'a> TypedReflectDeserializer<'a> { + /// Creates a new [`TypedReflectDeserializer`] for the given type registration. pub fn new(registration: &'a TypeRegistration, registry: &'a TypeRegistry) -> Self { #[cfg(feature = "debug_stack")] TYPE_INFO_STACK.set(crate::type_info_stack::TypeInfoStack::new()); @@ -241,6 +243,22 @@ impl<'a> TypedReflectDeserializer<'a> { } } + /// Creates a new [`TypedReflectDeserializer`] for the given type `T`. + /// + /// # Panics + /// + /// Panics if `T` is not registered in the given [`TypeRegistry`]. + pub fn of(registry: &'a TypeRegistry) -> Self { + let registration = registry + .get(core::any::TypeId::of::()) + .unwrap_or_else(|| panic!("no registration found for type `{}`", T::type_path())); + + Self { + registration, + registry, + } + } + /// An internal constructor for creating a deserializer without resetting the type info stack. pub(super) fn new_internal( registration: &'a TypeRegistration, @@ -269,6 +287,13 @@ impl<'a, 'de> DeserializeSeed<'de> for TypedReflectDeserializer<'a> { return Ok(value.into_partial_reflect()); } + if let Some(deserialize_reflect) = + self.registration.data::() + { + let value = deserialize_reflect.deserialize(deserializer, self.registry)?; + return Ok(value); + } + match self.registration.type_info() { TypeInfo::Struct(struct_info) => { let mut dynamic_struct = deserializer.deserialize_struct( diff --git a/crates/bevy_reflect/src/serde/de/mod.rs b/crates/bevy_reflect/src/serde/de/mod.rs index 482ce9fb63..318cb8d426 100644 --- a/crates/bevy_reflect/src/serde/de/mod.rs +++ b/crates/bevy_reflect/src/serde/de/mod.rs @@ -1,7 +1,9 @@ +pub use deserialize_with_registry::*; pub use deserializer::*; pub use registrations::*; mod arrays; +mod deserialize_with_registry; mod deserializer; mod enums; mod error_utils; diff --git a/crates/bevy_reflect/src/serde/mod.rs b/crates/bevy_reflect/src/serde/mod.rs index 5a307c7d18..b0f0d7e5c6 100644 --- a/crates/bevy_reflect/src/serde/mod.rs +++ b/crates/bevy_reflect/src/serde/mod.rs @@ -8,11 +8,10 @@ pub use type_data::*; #[cfg(test)] mod tests { + use super::*; use crate::{ - self as bevy_reflect, - serde::{ReflectDeserializer, ReflectSerializer}, - type_registry::TypeRegistry, - DynamicStruct, DynamicTupleStruct, FromReflect, PartialReflect, Reflect, Struct, + self as bevy_reflect, type_registry::TypeRegistry, DynamicStruct, DynamicTupleStruct, + FromReflect, PartialReflect, Reflect, Struct, }; use serde::de::DeserializeSeed; @@ -183,4 +182,221 @@ mod tests { .reflect_partial_eq(result.as_partial_reflect()) .unwrap()); } + + mod type_data { + use super::*; + use crate::from_reflect::FromReflect; + use crate::serde::{DeserializeWithRegistry, ReflectDeserializeWithRegistry}; + use crate::serde::{ReflectSerializeWithRegistry, SerializeWithRegistry}; + use crate::{ReflectFromReflect, TypePath}; + use alloc::sync::Arc; + use bevy_reflect_derive::reflect_trait; + use core::fmt::{Debug, Formatter}; + use serde::de::{SeqAccess, Visitor}; + use serde::ser::SerializeSeq; + use serde::{Deserializer, Serializer}; + + #[reflect_trait] + trait Enemy: Reflect + Debug { + #[allow(dead_code, reason = "this method is purely for testing purposes")] + fn hp(&self) -> u8; + } + + // This is needed to support Arc + impl TypePath for dyn Enemy { + fn type_path() -> &'static str { + "dyn bevy_reflect::serde::tests::type_data::Enemy" + } + + fn short_type_path() -> &'static str { + "dyn Enemy" + } + } + + #[derive(Reflect, Debug)] + #[reflect(Enemy)] + struct Skeleton(u8); + + impl Enemy for Skeleton { + fn hp(&self) -> u8 { + self.0 + } + } + + #[derive(Reflect, Debug)] + #[reflect(Enemy)] + struct Zombie { + health: u8, + walk_speed: f32, + } + + impl Enemy for Zombie { + fn hp(&self) -> u8 { + self.health + } + } + + #[derive(Reflect, Debug)] + struct Level { + name: String, + enemies: EnemyList, + } + + #[derive(Reflect, Debug)] + #[reflect(SerializeWithRegistry, DeserializeWithRegistry)] + // Note that we have to use `Arc` instead of `Box` here due to the + // former being the only one between the two to implement `Reflect`. + struct EnemyList(Vec>); + + impl SerializeWithRegistry for EnemyList { + fn serialize( + &self, + serializer: S, + registry: &TypeRegistry, + ) -> Result + where + S: Serializer, + { + let mut state = serializer.serialize_seq(Some(self.0.len()))?; + for enemy in &self.0 { + state.serialize_element(&ReflectSerializer::new( + (**enemy).as_partial_reflect(), + registry, + ))?; + } + state.end() + } + } + + impl<'de> DeserializeWithRegistry<'de> for EnemyList { + fn deserialize(deserializer: D, registry: &TypeRegistry) -> Result + where + D: Deserializer<'de>, + { + struct EnemyListVisitor<'a> { + registry: &'a TypeRegistry, + } + + impl<'a, 'de> Visitor<'de> for EnemyListVisitor<'a> { + type Value = Vec>; + + fn expecting(&self, formatter: &mut Formatter) -> core::fmt::Result { + write!(formatter, "a list of enemies") + } + + fn visit_seq(self, mut seq: A) -> Result + where + A: SeqAccess<'de>, + { + let mut enemies = Vec::new(); + while let Some(enemy) = + seq.next_element_seed(ReflectDeserializer::new(self.registry))? + { + let registration = self + .registry + .get_with_type_path( + enemy.get_represented_type_info().unwrap().type_path(), + ) + .unwrap(); + + // 1. Convert any possible dynamic values to concrete ones + let enemy = registration + .data::() + .unwrap() + .from_reflect(&*enemy) + .unwrap(); + + // 2. Convert the concrete value to a boxed trait object + let enemy = registration + .data::() + .unwrap() + .get_boxed(enemy) + .unwrap(); + + enemies.push(enemy.into()); + } + + Ok(enemies) + } + } + + deserializer + .deserialize_seq(EnemyListVisitor { registry }) + .map(EnemyList) + } + } + + fn create_registry() -> TypeRegistry { + let mut registry = TypeRegistry::default(); + registry.register::(); + registry.register::(); + registry.register::(); + registry.register::(); + registry + } + + #[test] + fn should_serialize_with_serialize_with_registry() { + let registry = create_registry(); + + let level = Level { + name: String::from("Level 1"), + enemies: EnemyList(vec![ + Arc::new(Skeleton(10)), + Arc::new(Zombie { + health: 20, + walk_speed: 0.5, + }), + ]), + }; + + let serializer = ReflectSerializer::new(&level, ®istry); + let serialized = ron::ser::to_string(&serializer).unwrap(); + + let expected = r#"{"bevy_reflect::serde::tests::type_data::Level":(name:"Level 1",enemies:[{"bevy_reflect::serde::tests::type_data::Skeleton":(10)},{"bevy_reflect::serde::tests::type_data::Zombie":(health:20,walk_speed:0.5)}])}"#; + + assert_eq!(expected, serialized); + } + + #[test] + fn should_deserialize_with_deserialize_with_registry() { + let registry = create_registry(); + + let input = r#"{"bevy_reflect::serde::tests::type_data::Level":(name:"Level 1",enemies:[{"bevy_reflect::serde::tests::type_data::Skeleton":(10)},{"bevy_reflect::serde::tests::type_data::Zombie":(health:20,walk_speed:0.5)}])}"#; + + let mut deserializer = ron::de::Deserializer::from_str(input).unwrap(); + let reflect_deserializer = ReflectDeserializer::new(®istry); + let value = reflect_deserializer.deserialize(&mut deserializer).unwrap(); + + let output = Level::from_reflect(&*value).unwrap(); + + let expected = Level { + name: String::from("Level 1"), + enemies: EnemyList(vec![ + Arc::new(Skeleton(10)), + Arc::new(Zombie { + health: 20, + walk_speed: 0.5, + }), + ]), + }; + + // Poor man's comparison since we can't derive PartialEq for Arc + assert_eq!(format!("{:?}", expected), format!("{:?}", output)); + + let unexpected = Level { + name: String::from("Level 1"), + enemies: EnemyList(vec![ + Arc::new(Skeleton(20)), + Arc::new(Zombie { + health: 20, + walk_speed: 5.0, + }), + ]), + }; + + // Poor man's comparison since we can't derive PartialEq for Arc + assert_ne!(format!("{:?}", unexpected), format!("{:?}", output)); + } + } } diff --git a/crates/bevy_reflect/src/serde/ser/custom_serialization.rs b/crates/bevy_reflect/src/serde/ser/custom_serialization.rs new file mode 100644 index 0000000000..18d2abed9c --- /dev/null +++ b/crates/bevy_reflect/src/serde/ser/custom_serialization.rs @@ -0,0 +1,62 @@ +use crate::serde::ser::error_utils::make_custom_error; +#[cfg(feature = "debug_stack")] +use crate::serde::ser::error_utils::TYPE_INFO_STACK; +use crate::serde::ReflectSerializeWithRegistry; +use crate::{PartialReflect, ReflectSerialize, TypeRegistry}; +use core::borrow::Borrow; +use serde::{Serialize, Serializer}; + +/// Attempts to serialize a [`PartialReflect`] value with custom [`ReflectSerialize`] +/// or [`ReflectSerializeWithRegistry`] type data. +/// +/// On success, returns the result of the serialization. +/// On failure, returns the original serializer and the error that occurred. +pub(super) fn try_custom_serialize( + value: &dyn PartialReflect, + type_registry: &TypeRegistry, + serializer: S, +) -> Result, (S, S::Error)> { + let Some(value) = value.try_as_reflect() else { + return Err(( + serializer, + make_custom_error(format_args!( + "type `{}` does not implement `Reflect`", + value.reflect_type_path() + )), + )); + }; + + let info = value.reflect_type_info(); + + let Some(registration) = type_registry.get(info.type_id()) else { + return Err(( + serializer, + make_custom_error(format_args!( + "type `{}` is not registered in the type registry", + info.type_path(), + )), + )); + }; + + if let Some(reflect_serialize) = registration.data::() { + #[cfg(feature = "debug_stack")] + TYPE_INFO_STACK.with_borrow_mut(crate::type_info_stack::TypeInfoStack::pop); + + Ok(reflect_serialize + .get_serializable(value) + .borrow() + .serialize(serializer)) + } else if let Some(reflect_serialize_with_registry) = + registration.data::() + { + #[cfg(feature = "debug_stack")] + TYPE_INFO_STACK.with_borrow_mut(crate::type_info_stack::TypeInfoStack::pop); + + Ok(reflect_serialize_with_registry.serialize(value, serializer, type_registry)) + } else { + Err((serializer, make_custom_error(format_args!( + "type `{}` did not register the `ReflectSerialize` or `ReflectSerializeWithRegistry` type data. For certain types, this may need to be registered manually using `register_type_data`", + info.type_path(), + )))) + } +} diff --git a/crates/bevy_reflect/src/serde/ser/mod.rs b/crates/bevy_reflect/src/serde/ser/mod.rs index 9ce71a839b..0a0d006b98 100644 --- a/crates/bevy_reflect/src/serde/ser/mod.rs +++ b/crates/bevy_reflect/src/serde/ser/mod.rs @@ -1,12 +1,15 @@ pub use serializable::*; +pub use serialize_with_registry::*; pub use serializer::*; mod arrays; +mod custom_serialization; mod enums; mod error_utils; mod lists; mod maps; mod serializable; +mod serialize_with_registry; mod serializer; mod sets; mod structs; @@ -459,7 +462,7 @@ mod tests { assert_eq!( error, ron::Error::Message( - "type `core::ops::RangeInclusive` did not register the `ReflectSerialize` type data. For certain types, this may need to be registered manually using `register_type_data` (stack: `core::ops::RangeInclusive`)".to_string() + "type `core::ops::RangeInclusive` did not register the `ReflectSerialize` or `ReflectSerializeWithRegistry` type data. For certain types, this may need to be registered manually using `register_type_data` (stack: `core::ops::RangeInclusive`)".to_string() ) ); #[cfg(not(feature = "debug_stack"))] diff --git a/crates/bevy_reflect/src/serde/ser/serializable.rs b/crates/bevy_reflect/src/serde/ser/serializable.rs index 3ca19a3912..b7420280a8 100644 --- a/crates/bevy_reflect/src/serde/ser/serializable.rs +++ b/crates/bevy_reflect/src/serde/ser/serializable.rs @@ -1,8 +1,4 @@ -use crate::{ - serde::ser::error_utils::make_custom_error, PartialReflect, ReflectSerialize, TypeRegistry, -}; use core::ops::Deref; -use serde::ser::Error; /// A type-erased serializable value. pub enum Serializable<'a> { @@ -10,47 +6,6 @@ pub enum Serializable<'a> { Borrowed(&'a dyn erased_serde::Serialize), } -impl<'a> Serializable<'a> { - /// Attempts to create a [`Serializable`] from a [`PartialReflect`] value. - /// - /// Returns an error if any of the following conditions are met: - /// - The underlying type of `value` does not implement [`Reflect`]. - /// - The underlying type of `value` does not represent any type (via [`PartialReflect::get_represented_type_info`]). - /// - The represented type of `value` is not registered in the `type_registry`. - /// - The represented type of `value` did not register the [`ReflectSerialize`] type data. - /// - /// [`Reflect`]: crate::Reflect - pub fn try_from_reflect_value( - value: &'a dyn PartialReflect, - type_registry: &TypeRegistry, - ) -> Result, E> { - let value = value.try_as_reflect().ok_or_else(|| { - make_custom_error(format_args!( - "type `{}` does not implement `Reflect`", - value.reflect_type_path() - )) - })?; - - let info = value.reflect_type_info(); - - let registration = type_registry.get(info.type_id()).ok_or_else(|| { - make_custom_error(format_args!( - "type `{}` is not registered in the type registry", - info.type_path(), - )) - })?; - - let reflect_serialize = registration.data::().ok_or_else(|| { - make_custom_error(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(value)) - } -} - impl<'a> Deref for Serializable<'a> { type Target = dyn erased_serde::Serialize + 'a; diff --git a/crates/bevy_reflect/src/serde/ser/serialize_with_registry.rs b/crates/bevy_reflect/src/serde/ser/serialize_with_registry.rs new file mode 100644 index 0000000000..5d6c82efcd --- /dev/null +++ b/crates/bevy_reflect/src/serde/ser/serialize_with_registry.rs @@ -0,0 +1,100 @@ +use crate::{FromType, Reflect, TypeRegistry}; +use serde::{Serialize, Serializer}; + +/// Trait used to provide finer control when serializing a reflected type with one of +/// the reflection serializers. +/// +/// This trait is the reflection equivalent of `serde`'s [`Serialize`] trait. +/// The main difference is that this trait provides access to the [`TypeRegistry`], +/// which means that we can use the registry and all its stored type information +/// to serialize our type. +/// +/// This can be useful when writing a custom reflection serializer where we may +/// want to handle parts of the serialization process, but temporarily pass control +/// to the standard reflection serializer for other parts. +/// +/// For the deserialization equivalent of this trait, see [`DeserializeWithRegistry`]. +/// +/// # Rationale +/// +/// Without this trait and its associated [type data], such a serializer would have to +/// write out all of the serialization logic itself, possibly including +/// unnecessary code duplication and trivial implementations. +/// +/// This is because a normal [`Serialize`] implementation has no knowledge of the +/// [`TypeRegistry`] and therefore cannot create a reflection-based serializer for +/// nested items. +/// +/// # Implementors +/// +/// In order for this to work with the reflection serializers like [`TypedReflectSerializer`] +/// and [`ReflectSerializer`], implementors should be sure to register the +/// [`ReflectSerializeWithRegistry`] type data. +/// This can be done [via the registry] or by adding `#[reflect(SerializeWithRegistry)]` to +/// the type definition. +/// +/// [`DeserializeWithRegistry`]: crate::serde::DeserializeWithRegistry +/// [type data]: ReflectSerializeWithRegistry +/// [`TypedReflectSerializer`]: crate::serde::TypedReflectSerializer +/// [`ReflectSerializer`]: crate::serde::ReflectSerializer +/// [via the registry]: TypeRegistry::register_type_data +pub trait SerializeWithRegistry { + fn serialize(&self, serializer: S, registry: &TypeRegistry) -> Result + where + S: Serializer; +} + +/// Type data used to serialize a [`Reflect`] type with a custom [`SerializeWithRegistry`] implementation. +#[derive(Clone)] +pub struct ReflectSerializeWithRegistry { + serialize: for<'a> fn( + value: &'a dyn Reflect, + registry: &'a TypeRegistry, + ) -> Box, +} + +impl ReflectSerializeWithRegistry { + /// Serialize a [`Reflect`] type with this type data's custom [`SerializeWithRegistry`] implementation. + pub fn serialize( + &self, + value: &dyn Reflect, + serializer: S, + registry: &TypeRegistry, + ) -> Result + where + S: Serializer, + { + ((self.serialize)(value, registry)).serialize(serializer) + } +} + +impl FromType for ReflectSerializeWithRegistry { + fn from_type() -> Self { + Self { + serialize: |value: &dyn Reflect, registry| { + let value = value.downcast_ref::().unwrap_or_else(|| { + panic!( + "Expected value to be of type {:?} but received {:?}", + core::any::type_name::(), + value.reflect_type_path() + ) + }); + Box::new(SerializableWithRegistry { value, registry }) + }, + } + } +} + +struct SerializableWithRegistry<'a, T: SerializeWithRegistry> { + value: &'a T, + registry: &'a TypeRegistry, +} + +impl<'a, T: SerializeWithRegistry> Serialize for SerializableWithRegistry<'a, T> { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + self.value.serialize(serializer, self.registry) + } +} diff --git a/crates/bevy_reflect/src/serde/ser/serializer.rs b/crates/bevy_reflect/src/serde/ser/serializer.rs index 55fad6d8e6..a803399829 100644 --- a/crates/bevy_reflect/src/serde/ser/serializer.rs +++ b/crates/bevy_reflect/src/serde/ser/serializer.rs @@ -1,14 +1,11 @@ #[cfg(feature = "debug_stack")] use crate::serde::ser::error_utils::TYPE_INFO_STACK; use crate::{ - serde::{ - ser::{ - arrays::ArraySerializer, enums::EnumSerializer, error_utils::make_custom_error, - lists::ListSerializer, maps::MapSerializer, sets::SetSerializer, - structs::StructSerializer, tuple_structs::TupleStructSerializer, - tuples::TupleSerializer, - }, - Serializable, + serde::ser::{ + arrays::ArraySerializer, custom_serialization::try_custom_serialize, enums::EnumSerializer, + error_utils::make_custom_error, lists::ListSerializer, maps::MapSerializer, + sets::SetSerializer, structs::StructSerializer, tuple_structs::TupleStructSerializer, + tuples::TupleSerializer, }, PartialReflect, ReflectRef, TypeRegistry, }; @@ -158,16 +155,12 @@ impl<'a> Serialize for TypedReflectSerializer<'a> { TYPE_INFO_STACK.with_borrow_mut(|stack| stack.push(info)); } } - // Handle both Value case and types that have a custom `Serialize` - let serializable = - Serializable::try_from_reflect_value::(self.value, self.registry); - if let Ok(serializable) = serializable { - #[cfg(feature = "debug_stack")] - TYPE_INFO_STACK.with_borrow_mut(crate::type_info_stack::TypeInfoStack::pop); - - return serializable.serialize(serializer); - } + let (serializer, error) = match try_custom_serialize(self.value, self.registry, serializer) + { + Ok(result) => return result, + Err(value) => value, + }; let output = match self.value.reflect_ref() { ReflectRef::Struct(value) => { @@ -196,7 +189,7 @@ impl<'a> Serialize for TypedReflectSerializer<'a> { } #[cfg(feature = "functions")] ReflectRef::Function(_) => Err(make_custom_error("functions cannot be serialized")), - ReflectRef::Opaque(_) => Err(serializable.err().unwrap()), + ReflectRef::Opaque(_) => Err(error), }; #[cfg(feature = "debug_stack")]