@@ -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+ /// ``` 
18166fn  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 
85244pub  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 
95260pub  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 
182358pub  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 
195377pub  fn  with_processor ( 
196378        value :  & ' a  dyn  PartialReflect , 
197379        registry :  & ' a  TypeRegistry , 
0 commit comments