Skip to content

Commit 3cc5728

Browse files
committed
serializer processor doc tests
1 parent 591edc4 commit 3cc5728

File tree

1 file changed

+182
-0
lines changed

1 file changed

+182
-0
lines changed

crates/bevy_reflect/src/serde/ser/serializer.rs

Lines changed: 182 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,155 @@ use crate::{
1414
};
1515
use 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
17120
pub 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
78231
pub struct ReflectSerializer<'a, P = ()> {
79232
value: &'a dyn PartialReflect,
80233
registry: &'a TypeRegistry,
81234
processor: Option<&'a P>,
82235
}
83236

84237
impl<'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

94253
impl<'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
175345
pub struct TypedReflectSerializer<'a, P = ()> {
176346
value: &'a dyn PartialReflect,
177347
registry: &'a TypeRegistry,
178348
processor: Option<&'a P>,
179349
}
180350

181351
impl<'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

194370
impl<'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

Comments
 (0)