use serde::Serializer; use crate::{PartialReflect, TypeRegistry}; /// Allows overriding the default serialization behavior of /// [`ReflectSerializer`] and [`TypedReflectSerializer`] for specific values. /// /// When serializing a reflected value, you may want to override the default /// behavior and use your own logic for serialization. This logic may also be /// context-dependent, and only apply for a single use of your /// [`ReflectSerializer`]. To achieve this, you can create a processor and pass /// it into your serializer. /// /// Whenever the serializer attempts to serialize a value, it will first call /// [`try_serialize`] on your processor, which may take ownership of the /// serializer and write into the serializer (successfully or not), or return /// ownership of the serializer back, and continue with the default logic. /// /// The deserialization equivalent of this is [`ReflectDeserializerProcessor`]. /// /// # Compared to [`SerializeWithRegistry`] /// /// [`SerializeWithRegistry`] allows you to define how your type will be /// serialized by a [`TypedReflectSerializer`], given the extra context of the /// [`TypeRegistry`]. If your type can be serialized entirely using that, then /// you should prefer implementing that trait instead of using a processor. /// /// However, you may need more context-dependent data which is only present in /// the scope where you create the [`TypedReflectSerializer`]. For example, if /// you need to use a reference to a value while serializing, then there is no /// way to do this with [`SerializeWithRegistry`] as you can't pass that /// reference into anywhere. This is where a processor is useful, as the /// processor can capture local variables. /// /// A [`ReflectSerializerProcessor`] always takes priority over a /// [`SerializeWithRegistry`] implementation, so this is also useful for /// overriding serialization behavior if you need to do something custom. /// /// # Examples /// /// Serializing a reflected value when saving an asset to disk, and replacing /// asset handles with the handle path (if it has one): /// /// ``` /// # use core::any::Any; /// # use serde::Serialize; /// # use bevy_reflect::{PartialReflect, Reflect, TypeData, TypeRegistry}; /// # use bevy_reflect::serde::{ReflectSerializer, ReflectSerializerProcessor}; /// # /// # #[derive(Debug, Clone, Reflect)] /// # struct Handle(T); /// # #[derive(Debug, Clone, Reflect)] /// # struct Mesh; /// # /// # struct ReflectHandle; /// # impl TypeData for ReflectHandle { /// # fn clone_type_data(&self) -> Box { /// # unimplemented!() /// # } /// # } /// # impl ReflectHandle { /// # fn downcast_handle_untyped(&self, handle: &(dyn Any + 'static)) -> Option { /// # unimplemented!() /// # } /// # } /// # /// # #[derive(Debug, Clone)] /// # struct UntypedHandle; /// # impl UntypedHandle { /// # fn path(&self) -> Option<&str> { /// # unimplemented!() /// # } /// # } /// # type AssetError = Box; /// # /// #[derive(Debug, Clone, Reflect)] /// struct MyAsset { /// name: String, /// mesh: Handle, /// } /// /// struct HandleProcessor; /// /// impl ReflectSerializerProcessor for HandleProcessor { /// fn try_serialize( /// &self, /// value: &dyn PartialReflect, /// registry: &TypeRegistry, /// serializer: S, /// ) -> Result, S::Error> /// where /// S: serde::Serializer, /// { /// let Some(value) = value.try_as_reflect() else { /// // we don't have any info on this type; do the default serialization logic /// return Ok(Err(serializer)); /// }; /// let type_id = value.reflect_type_info().type_id(); /// let Some(reflect_handle) = registry.get_type_data::(type_id) else { /// // this isn't a `Handle` /// return Ok(Err(serializer)); /// }; /// /// let untyped_handle = reflect_handle /// .downcast_handle_untyped(value.as_any()) /// .unwrap(); /// if let Some(path) = untyped_handle.path() { /// Ok(Ok(serializer.serialize_str(path)?)) /// } else { /// Ok(Ok(serializer.serialize_unit()?)) /// } /// } /// } /// /// fn save(type_registry: &TypeRegistry, asset: &MyAsset) -> Result, AssetError> { /// let mut asset_bytes = Vec::new(); /// /// let processor = HandleProcessor; /// let serializer = ReflectSerializer::with_processor(asset, type_registry, &processor); /// let mut ron_serializer = ron::Serializer::new(&mut asset_bytes, None)?; /// /// serializer.serialize(&mut ron_serializer)?; /// Ok(asset_bytes) /// } /// ``` /// /// [`ReflectSerializer`]: crate::serde::ReflectSerializer /// [`TypedReflectSerializer`]: crate::serde::TypedReflectSerializer /// [`try_serialize`]: Self::try_serialize /// [`SerializeWithRegistry`]: crate::serde::SerializeWithRegistry /// [`ReflectDeserializerProcessor`]: crate::serde::ReflectDeserializerProcessor pub trait ReflectSerializerProcessor { /// Attempts to serialize the value which a [`TypedReflectSerializer`] is /// currently looking at. /// /// If you want to override the default serialization, return /// `Ok(Ok(value))` with an `Ok` output from the serializer. /// /// If you don't want to override the serialization, return ownership of /// the serializer back via `Ok(Err(serializer))`. /// /// You can use the type registry to read info about the type you're /// serializing, or just try to downcast the value directly: /// /// ``` /// # use bevy_reflect::{TypeRegistration, TypeRegistry, PartialReflect}; /// # use bevy_reflect::serde::ReflectSerializerProcessor; /// # use core::any::TypeId; /// struct I32AsStringProcessor; /// /// impl ReflectSerializerProcessor for I32AsStringProcessor { /// fn try_serialize( /// &self, /// value: &dyn PartialReflect, /// registry: &TypeRegistry, /// serializer: S, /// ) -> Result, S::Error> /// where /// S: serde::Serializer /// { /// if let Some(value) = value.try_downcast_ref::() { /// let value_as_string = format!("{value:?}"); /// Ok(Ok(serializer.serialize_str(&value_as_string)?)) /// } else { /// // Not an `i32`, just do the default serialization /// Ok(Err(serializer)) /// } /// } /// } /// ``` /// /// [`TypedReflectSerializer`]: crate::serde::TypedReflectSerializer /// [`Reflect`]: crate::Reflect fn try_serialize( &self, value: &dyn PartialReflect, registry: &TypeRegistry, serializer: S, ) -> Result, S::Error> where S: Serializer; } impl ReflectSerializerProcessor for () { fn try_serialize( &self, _value: &dyn PartialReflect, _registry: &TypeRegistry, serializer: S, ) -> Result, S::Error> where S: Serializer, { Ok(Err(serializer)) } }