@@ -14,7 +14,155 @@ use crate::{
1414} ;
1515use serde:: { ser:: SerializeMap , Serialize , Serializer } ;
1616
17+ /// Allows overriding the default serialization behaviour of
18+ /// [`ReflectSerializer`] and [`TypedReflectSerializer`] for specific values.
19+ ///
20+ /// When serializing a reflected value, you may want to override the default
21+ /// behaviour and use your own logic for serialization. This logic may also be
22+ /// context-dependent, and only apply for a single use of your
23+ /// [`ReflectSerializer`]. To achieve this, you can create a processor and pass
24+ /// it into your serializer.
25+ ///
26+ /// Whenever the serializer attempts to serialize a value, it will first call
27+ /// [`try_serialize`] on your processor, which may take ownership of the
28+ /// serializer and write into the serializer (successfully or not), or return
29+ /// ownership of the serializer back, and continue with the default logic.
30+ ///
31+ /// # Examples
32+ ///
33+ /// Serializing a reflected value when saving an asset to disk, and replacing
34+ /// asset handles with the handle path (if it has one):
35+ ///
36+ /// ```
37+ /// # use core::any::Any;
38+ /// # use serde::Serialize;
39+ /// # use bevy_reflect::{Reflect, TypeData, TypeRegistry};
40+ /// # use bevy_reflect::serde::{ReflectSerializer, ReflectSerializerProcessor};
41+ /// #
42+ /// # #[derive(Debug, Clone, Reflect)]
43+ /// # struct Handle<T>(T);
44+ /// # #[derive(Debug, Clone, Reflect)]
45+ /// # struct Mesh;
46+ /// #
47+ /// # struct ReflectHandle;
48+ /// # impl TypeData for ReflectHandle {
49+ /// # fn clone_type_data(&self) -> Box<dyn TypeData> {
50+ /// # unimplemented!()
51+ /// # }
52+ /// # }
53+ /// # impl ReflectHandle {
54+ /// # fn downcast_handle_untyped(&self, handle: &(dyn Any + 'static)) -> Option<UntypedHandle> {
55+ /// # unimplemented!()
56+ /// # }
57+ /// # }
58+ /// #
59+ /// # #[derive(Debug, Clone)]
60+ /// # struct UntypedHandle;
61+ /// # impl UntypedHandle {
62+ /// # fn path(&self) -> Option<&str> {
63+ /// # unimplemented!()
64+ /// # }
65+ /// # }
66+ /// # type AssetError = Box<dyn core::error::Error>;
67+ /// #
68+ /// #[derive(Debug, Clone, Reflect)]
69+ /// struct MyAsset {
70+ /// name: String,
71+ /// mesh: Handle<Mesh>,
72+ /// }
73+ ///
74+ /// struct HandleProcessor;
75+ ///
76+ /// impl ReflectSerializerProcessor for HandleProcessor {
77+ /// fn try_serialize<S>(
78+ /// &self,
79+ /// value: &dyn crate::PartialReflect,
80+ /// registry: &TypeRegistry,
81+ /// serializer: S,
82+ /// ) -> Result<Result<S::Ok, S>, S::Error>
83+ /// where
84+ /// S: serde::Serializer,
85+ /// {
86+ /// let Some(value) = value.try_as_reflect() else {
87+ /// // we don't have any info on this type; do the default logic
88+ /// return Ok(Err(serializer));
89+ /// };
90+ /// let type_id = value.reflect_type_info().type_id();
91+ /// let Some(reflect_handle) = registry.get_type_data::<ReflectHandle>(type_id) else {
92+ /// // this isn't a `Handle<T>`
93+ /// return Ok(Err(serializer));
94+ /// };
95+ ///
96+ /// let untyped_handle = reflect_handle
97+ /// .downcast_handle_untyped(value.as_any())
98+ /// .unwrap();
99+ /// if let Some(path) = untyped_handle.path() {
100+ /// serializer.serialize_str(path).map(Ok)
101+ /// } else {
102+ /// serializer.serialize_unit().map(Ok)
103+ /// }
104+ /// }
105+ /// }
106+ ///
107+ /// fn save(type_registry: &TypeRegistry, asset: &MyAsset) -> Result<Vec<u8>, AssetError> {
108+ /// let mut asset_bytes = Vec::new();
109+ ///
110+ /// let processor = HandleProcessor;
111+ /// let serializer = ReflectSerializer::with_processor(asset, type_registry, &processor);
112+ /// let ron_serializer = ron::Serializer::new(&mut asset_bytes, None);
113+ ///
114+ /// serializer.serialize(serializer)?;
115+ /// Ok(asset_bytes)
116+ /// }
117+ /// ```
118+ ///
119+ /// [`try_serialize`]: Self::try_serialize
17120pub trait ReflectSerializerProcessor {
121+ /// Attempts to serialize the value which a [`TypedReflectSerializer`] is
122+ /// currently looking at.
123+ ///
124+ /// If you want to override the default deserialization, return
125+ /// `Ok(Ok(value))` with an `Ok` output from the serializer.
126+ ///
127+ /// If you don't want to override the serialization, return ownership of
128+ /// the serializer back via `Ok(Err(serializer))`.
129+ ///
130+ /// To get useful info about the type of value you're serializing, you will
131+ /// likely want to convert it to a [`Reflect`] and read its type info from
132+ /// the given registry:
133+ ///
134+ /// ```
135+ /// # use bevy_reflect::{TypeRegistration, TypeRegistry, PartialReflect};
136+ /// # use bevy_reflect::serde::ReflectDeserializerProcessor;
137+ /// # use core::any::TypeId;
138+ /// struct I32AsStringProcessor;
139+ ///
140+ /// impl ReflectSerializerProcessor for I32AsStringProcessor {
141+ /// fn try_serialize<S>(
142+ /// &self,
143+ /// value: &dyn PartialReflect,
144+ /// registry: &TypeRegistry,
145+ /// serializer: S,
146+ /// ) -> Result<Result<S::Ok, S>, S::Error>
147+ /// where
148+ /// S: serde::Serializer
149+ /// {
150+ /// let Some(value) = value.try_as_reflect() else {
151+ /// // this value isn't `Reflect`, just do the default serialization
152+ /// return Ok(Err(serializer));
153+ /// };
154+ /// // actually read the type ID of this value
155+ /// let type_id = value.reflect_type_info().type_id();
156+ ///
157+ /// if type_id == TypeId::of::<i32>() {
158+ /// let value_as_string = format!("{value:?}");
159+ /// serializer.serialize_str(value_as_string).map(Ok)
160+ /// } else {
161+ /// Ok(Err(serializer))
162+ /// }
163+ /// }
164+ /// }
165+ /// ```
18166 fn try_serialize < S > (
19167 & self ,
20168 value : & dyn PartialReflect ,
@@ -51,6 +199,10 @@ impl ReflectSerializerProcessor for () {
51199/// where the key is the _full_ [type path] of the reflected type
52200/// and the value is the serialized data.
53201///
202+ /// If you want to override serialization for specific values, you can pass in
203+ /// a reference to a [`ReflectSerializerProcessor`] which will take priority
204+ /// over all other serialization methods - see [`with_processor`].
205+ ///
54206/// # Example
55207///
56208/// ```
@@ -75,13 +227,20 @@ impl ReflectSerializerProcessor for () {
75227///
76228/// [`ReflectDeserializer`]: crate::serde::ReflectDeserializer
77229/// [type path]: crate::TypePath::type_path
230+ /// [`with_processor`]: Self::with_processor
78231pub struct ReflectSerializer < ' a , P = ( ) > {
79232 value : & ' a dyn PartialReflect ,
80233 registry : & ' a TypeRegistry ,
81234 processor : Option < & ' a P > ,
82235}
83236
84237impl < ' a > ReflectSerializer < ' a , ( ) > {
238+ /// Creates a serializer with no processor.
239+ ///
240+ /// If you want to add custom logic for serializing certain values, use
241+ /// [`with_processor`].
242+ ///
243+ /// [`with_processor`]: Self::with_processor
85244 pub fn new ( value : & ' a dyn PartialReflect , registry : & ' a TypeRegistry ) -> Self {
86245 Self {
87246 value,
@@ -92,6 +251,12 @@ impl<'a> ReflectSerializer<'a, ()> {
92251}
93252
94253impl < ' a , P : ReflectSerializerProcessor > ReflectSerializer < ' a , P > {
254+ /// Creates a serializer with a processor.
255+ ///
256+ /// If you do not need any custom logic for handling certain values, use
257+ /// [`new`].
258+ ///
259+ /// [`new`]: Self::new
95260 pub fn with_processor (
96261 value : & ' a dyn PartialReflect ,
97262 registry : & ' a TypeRegistry ,
@@ -148,6 +313,10 @@ impl<P: ReflectSerializerProcessor> Serialize for ReflectSerializer<'_, P> {
148313///
149314/// Instead, it will output just the serialized data.
150315///
316+ /// If you want to override serialization for specific values, you can pass in
317+ /// a reference to a [`ReflectSerializerProcessor`] which will take priority
318+ /// over all other serialization methods - see [`with_processor`].
319+ ///
151320/// # Example
152321///
153322/// ```
@@ -172,13 +341,20 @@ impl<P: ReflectSerializerProcessor> Serialize for ReflectSerializer<'_, P> {
172341///
173342/// [`TypedReflectDeserializer`]: crate::serde::TypedReflectDeserializer
174343/// [type path]: crate::TypePath::type_path
344+ /// [`with_processor`]: Self::with_processor
175345pub struct TypedReflectSerializer < ' a , P = ( ) > {
176346 value : & ' a dyn PartialReflect ,
177347 registry : & ' a TypeRegistry ,
178348 processor : Option < & ' a P > ,
179349}
180350
181351impl < ' a > TypedReflectSerializer < ' a , ( ) > {
352+ /// Creates a serializer with no processor.
353+ ///
354+ /// If you want to add custom logic for serializing certain values, use
355+ /// [`with_processor`].
356+ ///
357+ /// [`with_processor`]: Self::with_processor
182358 pub fn new ( value : & ' a dyn PartialReflect , registry : & ' a TypeRegistry ) -> Self {
183359 #[ cfg( feature = "debug_stack" ) ]
184360 TYPE_INFO_STACK . set ( crate :: type_info_stack:: TypeInfoStack :: new ( ) ) ;
@@ -192,6 +368,12 @@ impl<'a> TypedReflectSerializer<'a, ()> {
192368}
193369
194370impl < ' a , P > TypedReflectSerializer < ' a , P > {
371+ /// Creates a serializer with a processor.
372+ ///
373+ /// If you do not need any custom logic for handling certain values, use
374+ /// [`new`].
375+ ///
376+ /// [`new`]: Self::new
195377 pub fn with_processor (
196378 value : & ' a dyn PartialReflect ,
197379 registry : & ' a TypeRegistry ,
0 commit comments