Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bevyengine
GitHub Repository: bevyengine/bevy
Path: blob/main/crates/bevy_reflect/src/serde/ser/processor.rs
6600 views
1
use serde::Serializer;
2
3
use crate::{PartialReflect, TypeRegistry};
4
5
/// Allows overriding the default serialization behavior of
6
/// [`ReflectSerializer`] and [`TypedReflectSerializer`] for specific values.
7
///
8
/// When serializing a reflected value, you may want to override the default
9
/// behavior and use your own logic for serialization. This logic may also be
10
/// context-dependent, and only apply for a single use of your
11
/// [`ReflectSerializer`]. To achieve this, you can create a processor and pass
12
/// it into your serializer.
13
///
14
/// Whenever the serializer attempts to serialize a value, it will first call
15
/// [`try_serialize`] on your processor, which may take ownership of the
16
/// serializer and write into the serializer (successfully or not), or return
17
/// ownership of the serializer back, and continue with the default logic.
18
///
19
/// The deserialization equivalent of this is [`ReflectDeserializerProcessor`].
20
///
21
/// # Compared to [`SerializeWithRegistry`]
22
///
23
/// [`SerializeWithRegistry`] allows you to define how your type will be
24
/// serialized by a [`TypedReflectSerializer`], given the extra context of the
25
/// [`TypeRegistry`]. If your type can be serialized entirely using that, then
26
/// you should prefer implementing that trait instead of using a processor.
27
///
28
/// However, you may need more context-dependent data which is only present in
29
/// the scope where you create the [`TypedReflectSerializer`]. For example, if
30
/// you need to use a reference to a value while serializing, then there is no
31
/// way to do this with [`SerializeWithRegistry`] as you can't pass that
32
/// reference into anywhere. This is where a processor is useful, as the
33
/// processor can capture local variables.
34
///
35
/// A [`ReflectSerializerProcessor`] always takes priority over a
36
/// [`SerializeWithRegistry`] implementation, so this is also useful for
37
/// overriding serialization behavior if you need to do something custom.
38
///
39
/// # Examples
40
///
41
/// Serializing a reflected value when saving an asset to disk, and replacing
42
/// asset handles with the handle path (if it has one):
43
///
44
/// ```
45
/// # use core::any::Any;
46
/// # use serde::Serialize;
47
/// # use bevy_reflect::{PartialReflect, Reflect, TypeData, TypeRegistry};
48
/// # use bevy_reflect::serde::{ReflectSerializer, ReflectSerializerProcessor};
49
/// #
50
/// # #[derive(Debug, Clone, Reflect)]
51
/// # struct Handle<T>(T);
52
/// # #[derive(Debug, Clone, Reflect)]
53
/// # struct Mesh;
54
/// #
55
/// # struct ReflectHandle;
56
/// # impl TypeData for ReflectHandle {
57
/// # fn clone_type_data(&self) -> Box<dyn TypeData> {
58
/// # unimplemented!()
59
/// # }
60
/// # }
61
/// # impl ReflectHandle {
62
/// # fn downcast_handle_untyped(&self, handle: &(dyn Any + 'static)) -> Option<UntypedHandle> {
63
/// # unimplemented!()
64
/// # }
65
/// # }
66
/// #
67
/// # #[derive(Debug, Clone)]
68
/// # struct UntypedHandle;
69
/// # impl UntypedHandle {
70
/// # fn path(&self) -> Option<&str> {
71
/// # unimplemented!()
72
/// # }
73
/// # }
74
/// # type AssetError = Box<dyn core::error::Error>;
75
/// #
76
/// #[derive(Debug, Clone, Reflect)]
77
/// struct MyAsset {
78
/// name: String,
79
/// mesh: Handle<Mesh>,
80
/// }
81
///
82
/// struct HandleProcessor;
83
///
84
/// impl ReflectSerializerProcessor for HandleProcessor {
85
/// fn try_serialize<S>(
86
/// &self,
87
/// value: &dyn PartialReflect,
88
/// registry: &TypeRegistry,
89
/// serializer: S,
90
/// ) -> Result<Result<S::Ok, S>, S::Error>
91
/// where
92
/// S: serde::Serializer,
93
/// {
94
/// let Some(value) = value.try_as_reflect() else {
95
/// // we don't have any info on this type; do the default serialization logic
96
/// return Ok(Err(serializer));
97
/// };
98
/// let type_id = value.reflect_type_info().type_id();
99
/// let Some(reflect_handle) = registry.get_type_data::<ReflectHandle>(type_id) else {
100
/// // this isn't a `Handle<T>`
101
/// return Ok(Err(serializer));
102
/// };
103
///
104
/// let untyped_handle = reflect_handle
105
/// .downcast_handle_untyped(value.as_any())
106
/// .unwrap();
107
/// if let Some(path) = untyped_handle.path() {
108
/// Ok(Ok(serializer.serialize_str(path)?))
109
/// } else {
110
/// Ok(Ok(serializer.serialize_unit()?))
111
/// }
112
/// }
113
/// }
114
///
115
/// fn save(type_registry: &TypeRegistry, asset: &MyAsset) -> Result<String, AssetError> {
116
/// let mut asset_string = String::new();
117
///
118
/// let processor = HandleProcessor;
119
/// let serializer = ReflectSerializer::with_processor(asset, type_registry, &processor);
120
/// let mut ron_serializer = ron::Serializer::new(&mut asset_string, None)?;
121
///
122
/// serializer.serialize(&mut ron_serializer)?;
123
/// Ok(asset_string)
124
/// }
125
/// ```
126
///
127
/// [`ReflectSerializer`]: crate::serde::ReflectSerializer
128
/// [`TypedReflectSerializer`]: crate::serde::TypedReflectSerializer
129
/// [`try_serialize`]: Self::try_serialize
130
/// [`SerializeWithRegistry`]: crate::serde::SerializeWithRegistry
131
/// [`ReflectDeserializerProcessor`]: crate::serde::ReflectDeserializerProcessor
132
pub trait ReflectSerializerProcessor {
133
/// Attempts to serialize the value which a [`TypedReflectSerializer`] is
134
/// currently looking at.
135
///
136
/// If you want to override the default serialization, return
137
/// `Ok(Ok(value))` with an `Ok` output from the serializer.
138
///
139
/// If you don't want to override the serialization, return ownership of
140
/// the serializer back via `Ok(Err(serializer))`.
141
///
142
/// You can use the type registry to read info about the type you're
143
/// serializing, or just try to downcast the value directly:
144
///
145
/// ```
146
/// # use bevy_reflect::{TypeRegistration, TypeRegistry, PartialReflect};
147
/// # use bevy_reflect::serde::ReflectSerializerProcessor;
148
/// # use core::any::TypeId;
149
/// struct I32AsStringProcessor;
150
///
151
/// impl ReflectSerializerProcessor for I32AsStringProcessor {
152
/// fn try_serialize<S>(
153
/// &self,
154
/// value: &dyn PartialReflect,
155
/// registry: &TypeRegistry,
156
/// serializer: S,
157
/// ) -> Result<Result<S::Ok, S>, S::Error>
158
/// where
159
/// S: serde::Serializer
160
/// {
161
/// if let Some(value) = value.try_downcast_ref::<i32>() {
162
/// let value_as_string = format!("{value:?}");
163
/// Ok(Ok(serializer.serialize_str(&value_as_string)?))
164
/// } else {
165
/// // Not an `i32`, just do the default serialization
166
/// Ok(Err(serializer))
167
/// }
168
/// }
169
/// }
170
/// ```
171
///
172
/// [`TypedReflectSerializer`]: crate::serde::TypedReflectSerializer
173
/// [`Reflect`]: crate::Reflect
174
fn try_serialize<S>(
175
&self,
176
value: &dyn PartialReflect,
177
registry: &TypeRegistry,
178
serializer: S,
179
) -> Result<Result<S::Ok, S>, S::Error>
180
where
181
S: Serializer;
182
}
183
184
impl ReflectSerializerProcessor for () {
185
fn try_serialize<S>(
186
&self,
187
_value: &dyn PartialReflect,
188
_registry: &TypeRegistry,
189
serializer: S,
190
) -> Result<Result<S::Ok, S>, S::Error>
191
where
192
S: Serializer,
193
{
194
Ok(Err(serializer))
195
}
196
}
197
198