pub trait ReflectDeserializerProcessor {
// Required method
fn try_deserialize<'de, D>(
&mut self,
registration: &TypeRegistration,
registry: &TypeRegistry,
deserializer: D,
) -> Result<Result<Box<dyn PartialReflect>, D>, D::Error>
where D: Deserializer<'de>;
}
Expand description
Allows overriding the default deserialization behavior of
ReflectDeserializer
and TypedReflectDeserializer
for specific
TypeRegistration
s.
When deserializing a reflected value, you may want to override the default
behavior and use your own logic for deserialization. This logic may also
be context-dependent, and only apply for a single use of your
ReflectDeserializer
. To achieve this, you can create a processor and
pass it in to your deserializer.
Whenever the deserializer attempts to deserialize a value, it will first
call try_deserialize
on your processor, which may take ownership of the
deserializer and give back a Box<dyn PartialReflect>
, or return
ownership of the deserializer back, and continue with the default logic.
The serialization equivalent of this is ReflectSerializerProcessor
.
§Compared to DeserializeWithRegistry
DeserializeWithRegistry
allows you to define how your type will be
deserialized by a TypedReflectDeserializer
, given the extra context of
the TypeRegistry
. If your type can be deserialized entirely from that,
then you should prefer implementing that trait instead of using a processor.
However, you may need more context-dependent data which is only present in
the scope where you create the TypedReflectDeserializer
. For example, in
an asset loader, the &mut LoadContext
you get is only valid from within
the load
function. This is where a processor is useful, as the processor
can capture local variables.
A ReflectDeserializerProcessor
always takes priority over a
DeserializeWithRegistry
implementation, so this is also useful for
overriding deserialization behavior if you need to do something custom.
§Examples
Deserializing a reflected value in an asset loader, and replacing asset handles with a loaded equivalent:
#[derive(Debug, Clone, Reflect)]
struct MyAsset {
name: String,
mesh: Handle<Mesh>,
}
fn load(
asset_bytes: &[u8],
type_registry: &TypeRegistry,
load_context: &mut LoadContext,
) -> Result<MyAsset, AssetError> {
struct HandleProcessor<'a> {
load_context: &'a mut LoadContext,
}
impl ReflectDeserializerProcessor for HandleProcessor<'_> {
fn try_deserialize<'de, D>(
&mut self,
registration: &TypeRegistration,
_registry: &TypeRegistry,
deserializer: D,
) -> Result<Result<Box<dyn PartialReflect>, D>, D::Error>
where
D: Deserializer<'de>,
{
let Some(reflect_handle) = registration.data::<ReflectHandle>() else {
// we don't want to deserialize this - give the deserializer back
return Ok(Err(deserializer));
};
let asset_type_id = reflect_handle.asset_type_id();
let asset_path = deserializer.deserialize_str(AssetPathVisitor)?;
let handle: Handle<LoadedUntypedAsset> = self.load_context
.load()
.with_asset_type_id(asset_type_id)
.untyped()
.load_asset(asset_path);
Ok(Box::new(handle))
}
}
let mut ron_deserializer = ron::Deserializer::from_bytes(asset_bytes)?;
let mut processor = HandleProcessor { load_context };
let reflect_deserializer =
ReflectDeserializer::with_processor(type_registry, &mut processor);
let asset = reflect_deserializer.deserialize(&mut ron_deserializer)?;
}
Required Methods§
Sourcefn try_deserialize<'de, D>(
&mut self,
registration: &TypeRegistration,
registry: &TypeRegistry,
deserializer: D,
) -> Result<Result<Box<dyn PartialReflect>, D>, D::Error>where
D: Deserializer<'de>,
fn try_deserialize<'de, D>(
&mut self,
registration: &TypeRegistration,
registry: &TypeRegistry,
deserializer: D,
) -> Result<Result<Box<dyn PartialReflect>, D>, D::Error>where
D: Deserializer<'de>,
Attempts to deserialize the value which a TypedReflectDeserializer
is currently looking at, and knows the type of.
If you’ve read the registration
and want to override the default
deserialization, return Ok(Ok(value))
with the boxed reflected value
that you want to assign this value to. The type inside the box must
be the same one as the registration
is for, otherwise future
reflection operations (such as using FromReflect
to convert the
resulting Box<dyn PartialReflect>
into a concrete type) will fail.
If you don’t want to override the deserialization, return ownership of
the deserializer back via Ok(Err(deserializer))
.
Note that, if you do want to return a value, you must read from the deserializer passed to this function (you are free to ignore the result though). Otherwise, the deserializer will be in an inconsistent state, and future value parsing will fail.
§Examples
Correct way to return a constant value (not using any output from the deserializer):
use serde::de::IgnoredAny;
struct ConstantI32Processor;
impl ReflectDeserializerProcessor for ConstantI32Processor {
fn try_deserialize<'de, D>(
&mut self,
registration: &TypeRegistration,
_registry: &TypeRegistry,
deserializer: D,
) -> Result<Result<Box<dyn PartialReflect>, D>, D::Error>
where
D: serde::Deserializer<'de>
{
if registration.type_id() == TypeId::of::<i32>() {
_ = deserializer.deserialize_ignored_any(IgnoredAny);
Ok(Ok(Box::new(42_i32)))
} else {
Ok(Err(deserializer))
}
}
}
Dyn Compatibility§
This trait is not dyn compatible.
In older versions of Rust, dyn compatibility was called "object safety", so this trait is not object safe.