Path: blob/main/crates/bevy_reflect/src/serde/ser/processor.rs
6600 views
use serde::Serializer;12use crate::{PartialReflect, TypeRegistry};34/// Allows overriding the default serialization behavior of5/// [`ReflectSerializer`] and [`TypedReflectSerializer`] for specific values.6///7/// When serializing a reflected value, you may want to override the default8/// behavior and use your own logic for serialization. This logic may also be9/// context-dependent, and only apply for a single use of your10/// [`ReflectSerializer`]. To achieve this, you can create a processor and pass11/// it into your serializer.12///13/// Whenever the serializer attempts to serialize a value, it will first call14/// [`try_serialize`] on your processor, which may take ownership of the15/// serializer and write into the serializer (successfully or not), or return16/// ownership of the serializer back, and continue with the default logic.17///18/// The deserialization equivalent of this is [`ReflectDeserializerProcessor`].19///20/// # Compared to [`SerializeWithRegistry`]21///22/// [`SerializeWithRegistry`] allows you to define how your type will be23/// serialized by a [`TypedReflectSerializer`], given the extra context of the24/// [`TypeRegistry`]. If your type can be serialized entirely using that, then25/// you should prefer implementing that trait instead of using a processor.26///27/// However, you may need more context-dependent data which is only present in28/// the scope where you create the [`TypedReflectSerializer`]. For example, if29/// you need to use a reference to a value while serializing, then there is no30/// way to do this with [`SerializeWithRegistry`] as you can't pass that31/// reference into anywhere. This is where a processor is useful, as the32/// processor can capture local variables.33///34/// A [`ReflectSerializerProcessor`] always takes priority over a35/// [`SerializeWithRegistry`] implementation, so this is also useful for36/// overriding serialization behavior if you need to do something custom.37///38/// # Examples39///40/// Serializing a reflected value when saving an asset to disk, and replacing41/// asset handles with the handle path (if it has one):42///43/// ```44/// # use core::any::Any;45/// # use serde::Serialize;46/// # use bevy_reflect::{PartialReflect, Reflect, TypeData, TypeRegistry};47/// # use bevy_reflect::serde::{ReflectSerializer, ReflectSerializerProcessor};48/// #49/// # #[derive(Debug, Clone, Reflect)]50/// # struct Handle<T>(T);51/// # #[derive(Debug, Clone, Reflect)]52/// # struct Mesh;53/// #54/// # struct ReflectHandle;55/// # impl TypeData for ReflectHandle {56/// # fn clone_type_data(&self) -> Box<dyn TypeData> {57/// # unimplemented!()58/// # }59/// # }60/// # impl ReflectHandle {61/// # fn downcast_handle_untyped(&self, handle: &(dyn Any + 'static)) -> Option<UntypedHandle> {62/// # unimplemented!()63/// # }64/// # }65/// #66/// # #[derive(Debug, Clone)]67/// # struct UntypedHandle;68/// # impl UntypedHandle {69/// # fn path(&self) -> Option<&str> {70/// # unimplemented!()71/// # }72/// # }73/// # type AssetError = Box<dyn core::error::Error>;74/// #75/// #[derive(Debug, Clone, Reflect)]76/// struct MyAsset {77/// name: String,78/// mesh: Handle<Mesh>,79/// }80///81/// struct HandleProcessor;82///83/// impl ReflectSerializerProcessor for HandleProcessor {84/// fn try_serialize<S>(85/// &self,86/// value: &dyn PartialReflect,87/// registry: &TypeRegistry,88/// serializer: S,89/// ) -> Result<Result<S::Ok, S>, S::Error>90/// where91/// S: serde::Serializer,92/// {93/// let Some(value) = value.try_as_reflect() else {94/// // we don't have any info on this type; do the default serialization logic95/// return Ok(Err(serializer));96/// };97/// let type_id = value.reflect_type_info().type_id();98/// let Some(reflect_handle) = registry.get_type_data::<ReflectHandle>(type_id) else {99/// // this isn't a `Handle<T>`100/// return Ok(Err(serializer));101/// };102///103/// let untyped_handle = reflect_handle104/// .downcast_handle_untyped(value.as_any())105/// .unwrap();106/// if let Some(path) = untyped_handle.path() {107/// Ok(Ok(serializer.serialize_str(path)?))108/// } else {109/// Ok(Ok(serializer.serialize_unit()?))110/// }111/// }112/// }113///114/// fn save(type_registry: &TypeRegistry, asset: &MyAsset) -> Result<String, AssetError> {115/// let mut asset_string = String::new();116///117/// let processor = HandleProcessor;118/// let serializer = ReflectSerializer::with_processor(asset, type_registry, &processor);119/// let mut ron_serializer = ron::Serializer::new(&mut asset_string, None)?;120///121/// serializer.serialize(&mut ron_serializer)?;122/// Ok(asset_string)123/// }124/// ```125///126/// [`ReflectSerializer`]: crate::serde::ReflectSerializer127/// [`TypedReflectSerializer`]: crate::serde::TypedReflectSerializer128/// [`try_serialize`]: Self::try_serialize129/// [`SerializeWithRegistry`]: crate::serde::SerializeWithRegistry130/// [`ReflectDeserializerProcessor`]: crate::serde::ReflectDeserializerProcessor131pub trait ReflectSerializerProcessor {132/// Attempts to serialize the value which a [`TypedReflectSerializer`] is133/// currently looking at.134///135/// If you want to override the default serialization, return136/// `Ok(Ok(value))` with an `Ok` output from the serializer.137///138/// If you don't want to override the serialization, return ownership of139/// the serializer back via `Ok(Err(serializer))`.140///141/// You can use the type registry to read info about the type you're142/// serializing, or just try to downcast the value directly:143///144/// ```145/// # use bevy_reflect::{TypeRegistration, TypeRegistry, PartialReflect};146/// # use bevy_reflect::serde::ReflectSerializerProcessor;147/// # use core::any::TypeId;148/// struct I32AsStringProcessor;149///150/// impl ReflectSerializerProcessor for I32AsStringProcessor {151/// fn try_serialize<S>(152/// &self,153/// value: &dyn PartialReflect,154/// registry: &TypeRegistry,155/// serializer: S,156/// ) -> Result<Result<S::Ok, S>, S::Error>157/// where158/// S: serde::Serializer159/// {160/// if let Some(value) = value.try_downcast_ref::<i32>() {161/// let value_as_string = format!("{value:?}");162/// Ok(Ok(serializer.serialize_str(&value_as_string)?))163/// } else {164/// // Not an `i32`, just do the default serialization165/// Ok(Err(serializer))166/// }167/// }168/// }169/// ```170///171/// [`TypedReflectSerializer`]: crate::serde::TypedReflectSerializer172/// [`Reflect`]: crate::Reflect173fn try_serialize<S>(174&self,175value: &dyn PartialReflect,176registry: &TypeRegistry,177serializer: S,178) -> Result<Result<S::Ok, S>, S::Error>179where180S: Serializer;181}182183impl ReflectSerializerProcessor for () {184fn try_serialize<S>(185&self,186_value: &dyn PartialReflect,187_registry: &TypeRegistry,188serializer: S,189) -> Result<Result<S::Ok, S>, S::Error>190where191S: Serializer,192{193Ok(Err(serializer))194}195}196197198