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 fn serialize<S>(&self, serializer: S, registry: &TypeRegistry) -> Result<S::Ok, S::Error>
44 where
45 S: Serializer;
46}
47
48/// Type data used to serialize a [`Reflect`] type with a custom [`SerializeWithRegistry`] implementation.
49#[derive(Clone)]
50pub struct ReflectSerializeWithRegistry {
51 serialize: for<'a> fn(
52 value: &'a dyn Reflect,
53 registry: &'a TypeRegistry,
54 ) -> Box<dyn erased_serde::Serialize + 'a>,
55}
56
57impl ReflectSerializeWithRegistry {
58 /// Serialize a [`Reflect`] type with this type data's custom [`SerializeWithRegistry`] implementation.
59 pub fn serialize<S>(
60 &self,
61 value: &dyn Reflect,
62 serializer: S,
63 registry: &TypeRegistry,
64 ) -> Result<S::Ok, S::Error>
65 where
66 S: Serializer,
67 {
68 ((self.serialize)(value, registry)).serialize(serializer)
69 }
70}
71
72impl<T: Reflect + SerializeWithRegistry> FromType<T> for ReflectSerializeWithRegistry {
73 fn from_type() -> Self {
74 Self {
75 serialize: |value: &dyn Reflect, registry| {
76 let value = value.downcast_ref::<T>().unwrap_or_else(|| {
77 panic!(
78 "Expected value to be of type {} but received {}",
79 core::any::type_name::<T>(),
80 value.reflect_type_path()
81 )
82 });
83 Box::new(SerializableWithRegistry { value, registry })
84 },
85 }
86 }
87}
88
89struct SerializableWithRegistry<'a, T: SerializeWithRegistry> {
90 value: &'a T,
91 registry: &'a TypeRegistry,
92}
93
94impl<'a, T: SerializeWithRegistry> Serialize for SerializableWithRegistry<'a, T> {
95 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
96 where
97 S: Serializer,
98 {
99 self.value.serialize(serializer, self.registry)
100 }
101}