bevy_reflect::serde

Trait ReflectDeserializerProcessor

Source
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 TypeRegistrations.

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§

Source

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.

Implementations on Foreign Types§

Source§

impl ReflectDeserializerProcessor for ()

Source§

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>,

Implementors§