bevy_reflect/serde/ser/serialize_with_registry.rs
1use crate::{FromType, Reflect, TypeRegistry};
2use alloc::boxed::Box;
3use serde::{Serialize, Serializer};
4
5/// Trait used to provide finer control when serializing a reflected type with one of
6/// the reflection serializers.
7///
8/// This trait is the reflection equivalent of `serde`'s [`Serialize`] trait.
9/// The main difference is that this trait provides access to the [`TypeRegistry`],
10/// which means that we can use the registry and all its stored type information
11/// to serialize our type.
12///
13/// This can be useful when writing a custom reflection serializer where we may
14/// want to handle parts of the serialization process, but temporarily pass control
15/// to the standard reflection serializer for other parts.
16///
17/// For the deserialization equivalent of this trait, see [`DeserializeWithRegistry`].
18///
19/// # Rationale
20///
21/// Without this trait and its associated [type data], such a serializer would have to
22/// write out all of the serialization logic itself, possibly including
23/// unnecessary code duplication and trivial implementations.
24///
25/// This is because a normal [`Serialize`] implementation has no knowledge of the
26/// [`TypeRegistry`] and therefore cannot create a reflection-based serializer for
27/// nested items.
28///
29/// # Implementors
30///
31/// In order for this to work with the reflection serializers like [`TypedReflectSerializer`]
32/// and [`ReflectSerializer`], implementors should be sure to register the
33/// [`ReflectSerializeWithRegistry`] type data.
34/// This can be done [via the registry] or by adding `#[reflect(SerializeWithRegistry)]` to
35/// the type definition.
36///
37/// [`DeserializeWithRegistry`]: crate::serde::DeserializeWithRegistry
38/// [type data]: ReflectSerializeWithRegistry
39/// [`TypedReflectSerializer`]: crate::serde::TypedReflectSerializer
40/// [`ReflectSerializer`]: crate::serde::ReflectSerializer
41/// [via the registry]: TypeRegistry::register_type_data
42pub trait SerializeWithRegistry {
43 /// Serialize this value using the given [Serializer] and [`TypeRegistry`].
44 ///
45 /// [`Serializer`]: ::serde::Serializer
46 fn serialize<S>(&self, serializer: S, registry: &TypeRegistry) -> Result<S::Ok, S::Error>
47 where
48 S: Serializer;
49}
50
51/// Type data used to serialize a [`Reflect`] type with a custom [`SerializeWithRegistry`] implementation.
52#[derive(Clone)]
53pub struct ReflectSerializeWithRegistry {
54 serialize: for<'a> fn(
55 value: &'a dyn Reflect,
56 registry: &'a TypeRegistry,
57 ) -> Box<dyn erased_serde::Serialize + 'a>,
58}
59
60impl ReflectSerializeWithRegistry {
61 /// Serialize a [`Reflect`] type with this type data's custom [`SerializeWithRegistry`] implementation.
62 pub fn serialize<S>(
63 &self,
64 value: &dyn Reflect,
65 serializer: S,
66 registry: &TypeRegistry,
67 ) -> Result<S::Ok, S::Error>
68 where
69 S: Serializer,
70 {
71 ((self.serialize)(value, registry)).serialize(serializer)
72 }
73}
74
75impl<T: Reflect + SerializeWithRegistry> FromType<T> for ReflectSerializeWithRegistry {
76 fn from_type() -> Self {
77 Self {
78 serialize: |value: &dyn Reflect, registry| {
79 let value = value.downcast_ref::<T>().unwrap_or_else(|| {
80 panic!(
81 "Expected value to be of type {} but received {}",
82 core::any::type_name::<T>(),
83 value.reflect_type_path()
84 )
85 });
86 Box::new(SerializableWithRegistry { value, registry })
87 },
88 }
89 }
90}
91
92struct SerializableWithRegistry<'a, T: SerializeWithRegistry> {
93 value: &'a T,
94 registry: &'a TypeRegistry,
95}
96
97impl<'a, T: SerializeWithRegistry> Serialize for SerializableWithRegistry<'a, T> {
98 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
99 where
100 S: Serializer,
101 {
102 self.value.serialize(serializer, self.registry)
103 }
104}