From 57931ce42f87ad460e36083f9b00a17fe508d9ba Mon Sep 17 00:00:00 2001 From: aecsocket <43144841+aecsocket@users.noreply.github.com> Date: Mon, 11 Nov 2024 18:46:23 +0000 Subject: [PATCH] bevy_reflect: Add `ReflectDeserializerProcessor` (#15482) **NOTE: Also see https://github.com/bevyengine/bevy/pull/15548 for the serializer equivalent** # Objective The current `ReflectDeserializer` and `TypedReflectDeserializer` use the `TypeRegistration` and/or `ReflectDeserialize` of a given type in order to determine how to deserialize a value of that type. However, there is currently no way to statefully override deserialization of a given type when using these two deserializers - that is, to have some local data in the same scope as the `ReflectDeserializer`, and make use of that data when deserializing. The motivating use case for this came up when working on [`bevy_animation_graph`](https://github.com/aecsocket/bevy_animation_graph/tree/feat/dynamic-nodes), when loading an animation graph asset. The `AnimationGraph` stores `Vec>`s which we have to load in. Those `Box`s may store `Handle`s to e.g. `Handle`. I want to trigger a `load_context.load()` for that handle when it's loaded. ```rs #[derive(Reflect)] struct Animation { clips: Vec>, } ``` ```rs ( clips: [ "animation_clips/walk.animclip.ron", "animation_clips/run.animclip.ron", "animation_clips/jump.animclip.ron", ], ) ```` Currently, if this were deserialized from an asset loader, this would be deserialized as a vec of `Handle::default()`s, which isn't useful since we also need to `load_context.load()` those handles for them to be used. With this processor field, a processor can detect when `Handle`s are being loaded, then actually load them in. ## Solution ```rs trait ReflectDeserializerProcessor { fn try_deserialize<'de, D>( &mut self, registration: &TypeRegistration, deserializer: D, ) -> Result, D>, D::Error> where D: serde::Deserializer<'de>; } ``` ```diff - pub struct ReflectDeserializer<'a> { + pub struct ReflectDeserializer<'a, P = ()> { // also for ReflectTypedDeserializer registry: &'a TypeRegistry, + processor: Option<&'a mut P>, } ``` ```rs impl<'a, P: ReflectDeserializerProcessor> ReflectDeserializer<'a, P> { // also for ReflectTypedDeserializer pub fn with_processor(registry: &'a TypeRegistry, processor: &'a mut P) -> Self { Self { registry, processor: Some(processor), } } } ``` This does not touch the existing `fn new`s. This `processor` field is also added to all internal visitor structs. When `TypedReflectDeserializer` runs, it will first try to deserialize a value of this type by passing the `TypeRegistration` and deserializer to the processor, and fallback to the default logic. This processor runs the earliest, and takes priority over all other deserialization logic. ## Testing Added unit tests to `bevy_reflect::serde::de`. Also using almost exactly the same implementation in [my fork of `bevy_animation_graph`](https://github.com/aecsocket/bevy_animation_graph/tree/feat/dynamic-nodes). ## Migration Guide (Since I added `P = ()`, I don't think this is actually a breaking change anymore, but I'll leave this in) `bevy_reflect`'s `ReflectDeserializer` and `TypedReflectDeserializer` now take a `ReflectDeserializerProcessor` as the type parameter `P`, which allows you to customize deserialization for specific types when they are found. However, the rest of the API surface (`new`) remains the same.
Original implementation Add `ReflectDeserializerProcessor`: ```rs struct ReflectDeserializerProcessor { pub can_deserialize: Box bool + 'p>, pub deserialize: Box< dyn FnMut( &TypeRegistration, &mut dyn erased_serde::Deserializer, ) -> Result, erased_serde::Error> + 'p, } ``` Along with `ReflectDeserializer::new_with_processor` and `TypedReflectDeserializer::new_with_processor`. This does not touch the public API of the existing `new` fns. This is stored as an `Option<&mut ReflectDeserializerProcessor>` on the deserializer and any of the private `-Visitor` structs, and when we attempt to deserialize a value, we first pass it through this processor. Also added a very comprehensive doc test to `ReflectDeserializerProcessor`, which is actually a scaled down version of the code for the `bevy_animation_graph` loader. This should give users a good motivating example for when and why to use this feature. ### Why `Box`? When I originally implemented this, I added a type parameter to `ReflectDeserializer` to determine the processor used, with `()` being "no processor". However when using this, I kept running into rustc errors where it failed to validate certain type bounds and led to overflows. I then switched to a dynamic dispatch approach. The dynamic dispatch should not be that expensive, nor should it be a performance regression, since it's only used if there is `Some` processor. (Note: I have not benchmarked this, I am just speculating.) Also, it means that we don't infect the rest of the code with an extra type parameter, which is nicer to maintain. ### Why the `'p` on `ReflectDeserializerProcessor<'p>`? Without a lifetime here, the `Box`es would automatically become `Box`. This makes them practically useless, since any local data you would want to pass in must then be `'static`. In the motivating example, you couldn't pass in that `&mut LoadContext` to the function. This means that the `'p` infects the rest of the Visitor types, but this is acceptable IMO. This PR also elides the lifetimes in the `impl<'de> Visitor<'de> for -Visitor` blocks where possible. ### Future possibilities I think it's technically possible to turn the processor into a trait, and make the deserializers generic over that trait. This would also open the door to an API like: ```rs type Seed; fn seed_deserialize(&mut self, r: &TypeRegistration) -> Option; fn deserialize(&mut self, r: &TypeRegistration, d: &mut dyn erased_serde::Deserializer, s: Self::Seed) -> ...; ``` A similar processor system should also be added to the serialization side, but that's for another PR. Ideally, both PRs will be in the same release, since one isn't very useful without the other. ## Testing Added unit tests to `bevy_reflect::serde::de`. Also using almost exactly the same implementation in [my fork of `bevy_animation_graph`](https://github.com/aecsocket/bevy_animation_graph/tree/feat/dynamic-nodes). ## Migration Guide `bevy_reflect`'s `ReflectDeserializer` and `TypedReflectDeserializer` now take a second lifetime parameter `'p` for storing the `ReflectDeserializerProcessor` field lifetimes. However, the rest of the API surface (`new`) remains the same, so if you are not storing these deserializers or referring to them with lifetimes, you should not have to make any changes.
--- crates/bevy_reflect/src/serde/de/arrays.rs | 23 +- .../bevy_reflect/src/serde/de/deserializer.rs | 198 +++++++++++--- crates/bevy_reflect/src/serde/de/enums.rs | 72 +++-- crates/bevy_reflect/src/serde/de/lists.rs | 23 +- crates/bevy_reflect/src/serde/de/maps.rs | 21 +- crates/bevy_reflect/src/serde/de/mod.rs | 249 +++++++++++++++++- crates/bevy_reflect/src/serde/de/options.rs | 26 +- crates/bevy_reflect/src/serde/de/processor.rs | 213 +++++++++++++++ crates/bevy_reflect/src/serde/de/sets.rs | 20 +- .../bevy_reflect/src/serde/de/struct_utils.rs | 12 +- crates/bevy_reflect/src/serde/de/structs.rs | 43 +-- .../src/serde/de/tuple_structs.rs | 30 +-- .../bevy_reflect/src/serde/de/tuple_utils.rs | 7 +- crates/bevy_reflect/src/serde/de/tuples.rs | 35 ++- 14 files changed, 775 insertions(+), 197 deletions(-) create mode 100644 crates/bevy_reflect/src/serde/de/processor.rs diff --git a/crates/bevy_reflect/src/serde/de/arrays.rs b/crates/bevy_reflect/src/serde/de/arrays.rs index 24d009716a..1e9dafae3c 100644 --- a/crates/bevy_reflect/src/serde/de/arrays.rs +++ b/crates/bevy_reflect/src/serde/de/arrays.rs @@ -5,31 +5,25 @@ use crate::{ use core::{fmt, fmt::Formatter}; use serde::de::{Error, SeqAccess, Visitor}; +use super::ReflectDeserializerProcessor; + /// A [`Visitor`] for deserializing [`Array`] values. /// /// [`Array`]: crate::Array -pub(super) struct ArrayVisitor<'a> { - array_info: &'static ArrayInfo, - registry: &'a TypeRegistry, +pub(super) struct ArrayVisitor<'a, P> { + pub array_info: &'static ArrayInfo, + pub registry: &'a TypeRegistry, + pub processor: Option<&'a mut P>, } -impl<'a> ArrayVisitor<'a> { - pub fn new(array_info: &'static ArrayInfo, registry: &'a TypeRegistry) -> Self { - Self { - array_info, - registry, - } - } -} - -impl<'a, 'de> Visitor<'de> for ArrayVisitor<'a> { +impl<'de, P: ReflectDeserializerProcessor> Visitor<'de> for ArrayVisitor<'_, P> { type Value = DynamicArray; fn expecting(&self, formatter: &mut Formatter) -> fmt::Result { formatter.write_str("reflected array value") } - fn visit_seq(self, mut seq: V) -> Result + fn visit_seq(mut self, mut seq: V) -> Result where V: SeqAccess<'de>, { @@ -38,6 +32,7 @@ impl<'a, 'de> Visitor<'de> for ArrayVisitor<'a> { while let Some(value) = seq.next_element_seed(TypedReflectDeserializer::new_internal( registration, self.registry, + self.processor.as_deref_mut(), ))? { vec.push(value); } diff --git a/crates/bevy_reflect/src/serde/de/deserializer.rs b/crates/bevy_reflect/src/serde/de/deserializer.rs index a1a97e3877..a177772ce2 100644 --- a/crates/bevy_reflect/src/serde/de/deserializer.rs +++ b/crates/bevy_reflect/src/serde/de/deserializer.rs @@ -15,6 +15,8 @@ use crate::{ use core::{fmt, fmt::Formatter}; use serde::de::{DeserializeSeed, Error, IgnoredAny, MapAccess, Visitor}; +use super::ReflectDeserializerProcessor; + /// A general purpose deserializer for reflected types. /// /// This is the deserializer counterpart to [`ReflectSerializer`]. @@ -42,6 +44,10 @@ use serde::de::{DeserializeSeed, Error, IgnoredAny, MapAccess, Visitor}; /// This means that if the actual type is needed, these dynamic representations will need to /// be converted to the concrete type using [`FromReflect`] or [`ReflectFromReflect`]. /// +/// If you want to override deserialization for a specific [`TypeRegistration`], +/// you can pass in a reference to a [`ReflectDeserializerProcessor`] which will +/// take priority over all other deserialization methods - see [`with_processor`]. +/// /// # Example /// /// ``` @@ -94,28 +100,57 @@ use serde::de::{DeserializeSeed, Error, IgnoredAny, MapAccess, Visitor}; /// [`Box`]: crate::DynamicList /// [`FromReflect`]: crate::FromReflect /// [`ReflectFromReflect`]: crate::ReflectFromReflect -pub struct ReflectDeserializer<'a> { +/// [`with_processor`]: Self::with_processor +pub struct ReflectDeserializer<'a, P: ReflectDeserializerProcessor = ()> { registry: &'a TypeRegistry, + processor: Option<&'a mut P>, } -impl<'a> ReflectDeserializer<'a> { +impl<'a> ReflectDeserializer<'a, ()> { + /// Creates a deserializer with no processor. + /// + /// If you want to add custom logic for deserializing certain types, use + /// [`with_processor`]. + /// + /// [`with_processor`]: Self::with_processor pub fn new(registry: &'a TypeRegistry) -> Self { - Self { registry } + Self { + registry, + processor: None, + } } } -impl<'a, 'de> DeserializeSeed<'de> for ReflectDeserializer<'a> { +impl<'a, P: ReflectDeserializerProcessor> ReflectDeserializer<'a, P> { + /// Creates a deserializer with a processor. + /// + /// If you do not need any custom logic for handling certain types, use + /// [`new`]. + /// + /// [`new`]: Self::new + pub fn with_processor(registry: &'a TypeRegistry, processor: &'a mut P) -> Self { + Self { + registry, + processor: Some(processor), + } + } +} + +impl<'de, P: ReflectDeserializerProcessor> DeserializeSeed<'de> for ReflectDeserializer<'_, P> { type Value = Box; fn deserialize(self, deserializer: D) -> Result where D: serde::Deserializer<'de>, { - struct UntypedReflectDeserializerVisitor<'a> { + struct UntypedReflectDeserializerVisitor<'a, P> { registry: &'a TypeRegistry, + processor: Option<&'a mut P>, } - impl<'a, 'de> Visitor<'de> for UntypedReflectDeserializerVisitor<'a> { + impl<'de, P: ReflectDeserializerProcessor> Visitor<'de> + for UntypedReflectDeserializerVisitor<'_, P> + { type Value = Box; fn expecting(&self, formatter: &mut Formatter) -> fmt::Result { @@ -131,10 +166,11 @@ impl<'a, 'de> DeserializeSeed<'de> for ReflectDeserializer<'a> { .next_key_seed(TypeRegistrationDeserializer::new(self.registry))? .ok_or_else(|| Error::invalid_length(0, &"a single entry"))?; - let value = map.next_value_seed(TypedReflectDeserializer { + let value = map.next_value_seed(TypedReflectDeserializer::new_internal( registration, - registry: self.registry, - })?; + self.registry, + self.processor, + ))?; if map.next_key::()?.is_some() { return Err(Error::invalid_length(2, &"a single entry")); @@ -146,6 +182,7 @@ impl<'a, 'de> DeserializeSeed<'de> for ReflectDeserializer<'a> { deserializer.deserialize_map(UntypedReflectDeserializerVisitor { registry: self.registry, + processor: self.processor, }) } } @@ -175,6 +212,10 @@ impl<'a, 'de> DeserializeSeed<'de> for ReflectDeserializer<'a> { /// This means that if the actual type is needed, these dynamic representations will need to /// be converted to the concrete type using [`FromReflect`] or [`ReflectFromReflect`]. /// +/// If you want to override deserialization for a specific [`TypeRegistration`], +/// you can pass in a reference to a [`ReflectDeserializerProcessor`] which will +/// take priority over all other deserialization methods - see [`with_processor`]. +/// /// # Example /// /// ``` @@ -226,13 +267,20 @@ impl<'a, 'de> DeserializeSeed<'de> for ReflectDeserializer<'a> { /// [`Box`]: crate::DynamicList /// [`FromReflect`]: crate::FromReflect /// [`ReflectFromReflect`]: crate::ReflectFromReflect -pub struct TypedReflectDeserializer<'a> { +/// [`with_processor`]: Self::with_processor +pub struct TypedReflectDeserializer<'a, P: ReflectDeserializerProcessor = ()> { registration: &'a TypeRegistration, registry: &'a TypeRegistry, + processor: Option<&'a mut P>, } -impl<'a> TypedReflectDeserializer<'a> { - /// Creates a new [`TypedReflectDeserializer`] for the given type registration. +impl<'a> TypedReflectDeserializer<'a, ()> { + /// Creates a typed deserializer with no processor. + /// + /// If you want to add custom logic for deserializing certain types, use + /// [`with_processor`]. + /// + /// [`with_processor`]: Self::with_processor pub fn new(registration: &'a TypeRegistration, registry: &'a TypeRegistry) -> Self { #[cfg(feature = "debug_stack")] TYPE_INFO_STACK.set(crate::type_info_stack::TypeInfoStack::new()); @@ -240,10 +288,12 @@ impl<'a> TypedReflectDeserializer<'a> { Self { registration, registry, + processor: None, } } - /// Creates a new [`TypedReflectDeserializer`] for the given type `T`. + /// Creates a new [`TypedReflectDeserializer`] for the given type `T` + /// without a processor. /// /// # Panics /// @@ -256,6 +306,30 @@ impl<'a> TypedReflectDeserializer<'a> { Self { registration, registry, + processor: None, + } + } +} + +impl<'a, P: ReflectDeserializerProcessor> TypedReflectDeserializer<'a, P> { + /// Creates a typed deserializer with a processor. + /// + /// If you do not need any custom logic for handling certain types, use + /// [`new`]. + /// + /// [`new`]: Self::new + pub fn with_processor( + registration: &'a TypeRegistration, + registry: &'a TypeRegistry, + processor: &'a mut P, + ) -> Self { + #[cfg(feature = "debug_stack")] + TYPE_INFO_STACK.set(crate::type_info_stack::TypeInfoStack::new()); + + Self { + registration, + registry, + processor: Some(processor), } } @@ -263,22 +337,42 @@ impl<'a> TypedReflectDeserializer<'a> { pub(super) fn new_internal( registration: &'a TypeRegistration, registry: &'a TypeRegistry, + processor: Option<&'a mut P>, ) -> Self { Self { registration, registry, + processor, } } } -impl<'a, 'de> DeserializeSeed<'de> for TypedReflectDeserializer<'a> { +impl<'de, P: ReflectDeserializerProcessor> DeserializeSeed<'de> + for TypedReflectDeserializer<'_, P> +{ type Value = Box; - fn deserialize(self, deserializer: D) -> Result + fn deserialize(mut self, deserializer: D) -> Result where D: serde::Deserializer<'de>, { let deserialize_internal = || -> Result { + // First, check if our processor wants to deserialize this type + // This takes priority over any other deserialization operations + let deserializer = if let Some(processor) = self.processor.as_deref_mut() { + match processor.try_deserialize(self.registration, self.registry, deserializer) { + Ok(Ok(value)) => { + return Ok(value); + } + Err(err) => { + return Err(make_custom_error(err)); + } + Ok(Err(deserializer)) => deserializer, + } + } else { + deserializer + }; + let type_path = self.registration.type_info().type_path(); // Handle both Value case and types that have a custom `ReflectDeserialize` @@ -299,7 +393,12 @@ impl<'a, 'de> DeserializeSeed<'de> for TypedReflectDeserializer<'a> { let mut dynamic_struct = deserializer.deserialize_struct( struct_info.type_path_table().ident().unwrap(), struct_info.field_names(), - StructVisitor::new(struct_info, self.registration, self.registry), + StructVisitor { + struct_info, + registration: self.registration, + registry: self.registry, + processor: self.processor, + }, )?; dynamic_struct.set_represented_type(Some(self.registration.type_info())); Ok(Box::new(dynamic_struct)) @@ -310,57 +409,76 @@ impl<'a, 'de> DeserializeSeed<'de> for TypedReflectDeserializer<'a> { { deserializer.deserialize_newtype_struct( tuple_struct_info.type_path_table().ident().unwrap(), - TupleStructVisitor::new( + TupleStructVisitor { tuple_struct_info, - self.registration, - self.registry, - ), + registration: self.registration, + registry: self.registry, + processor: self.processor, + }, )? } else { deserializer.deserialize_tuple_struct( tuple_struct_info.type_path_table().ident().unwrap(), tuple_struct_info.field_len(), - TupleStructVisitor::new( + TupleStructVisitor { tuple_struct_info, - self.registration, - self.registry, - ), + registration: self.registration, + registry: self.registry, + processor: self.processor, + }, )? }; - dynamic_tuple_struct.set_represented_type(Some(self.registration.type_info())); Ok(Box::new(dynamic_tuple_struct)) } TypeInfo::List(list_info) => { - let mut dynamic_list = - deserializer.deserialize_seq(ListVisitor::new(list_info, self.registry))?; + let mut dynamic_list = deserializer.deserialize_seq(ListVisitor { + list_info, + registry: self.registry, + processor: self.processor, + })?; dynamic_list.set_represented_type(Some(self.registration.type_info())); Ok(Box::new(dynamic_list)) } TypeInfo::Array(array_info) => { let mut dynamic_array = deserializer.deserialize_tuple( array_info.capacity(), - ArrayVisitor::new(array_info, self.registry), + ArrayVisitor { + array_info, + registry: self.registry, + processor: self.processor, + }, )?; dynamic_array.set_represented_type(Some(self.registration.type_info())); Ok(Box::new(dynamic_array)) } TypeInfo::Map(map_info) => { - let mut dynamic_map = - deserializer.deserialize_map(MapVisitor::new(map_info, self.registry))?; + let mut dynamic_map = deserializer.deserialize_map(MapVisitor { + map_info, + registry: self.registry, + processor: self.processor, + })?; dynamic_map.set_represented_type(Some(self.registration.type_info())); Ok(Box::new(dynamic_map)) } TypeInfo::Set(set_info) => { - let mut dynamic_set = - deserializer.deserialize_seq(SetVisitor::new(set_info, self.registry))?; + let mut dynamic_set = deserializer.deserialize_seq(SetVisitor { + set_info, + registry: self.registry, + processor: self.processor, + })?; dynamic_set.set_represented_type(Some(self.registration.type_info())); Ok(Box::new(dynamic_set)) } TypeInfo::Tuple(tuple_info) => { let mut dynamic_tuple = deserializer.deserialize_tuple( tuple_info.field_len(), - TupleVisitor::new(tuple_info, self.registration, self.registry), + TupleVisitor { + tuple_info, + registration: self.registration, + registry: self.registry, + processor: self.processor, + }, )?; dynamic_tuple.set_represented_type(Some(self.registration.type_info())); Ok(Box::new(dynamic_tuple)) @@ -370,13 +488,21 @@ impl<'a, 'de> DeserializeSeed<'de> for TypedReflectDeserializer<'a> { == Some("core::option") && enum_info.type_path_table().ident() == Some("Option") { - deserializer - .deserialize_option(OptionVisitor::new(enum_info, self.registry))? + deserializer.deserialize_option(OptionVisitor { + enum_info, + registry: self.registry, + processor: self.processor, + })? } else { deserializer.deserialize_enum( enum_info.type_path_table().ident().unwrap(), enum_info.variant_names(), - EnumVisitor::new(enum_info, self.registration, self.registry), + EnumVisitor { + enum_info, + registration: self.registration, + registry: self.registry, + processor: self.processor, + }, )? }; dynamic_enum.set_represented_type(Some(self.registration.type_info())); diff --git a/crates/bevy_reflect/src/serde/de/enums.rs b/crates/bevy_reflect/src/serde/de/enums.rs index ecdcc1435c..21cbf46f9e 100644 --- a/crates/bevy_reflect/src/serde/de/enums.rs +++ b/crates/bevy_reflect/src/serde/de/enums.rs @@ -15,30 +15,19 @@ use crate::{ use core::{fmt, fmt::Formatter}; use serde::de::{DeserializeSeed, EnumAccess, Error, MapAccess, SeqAccess, VariantAccess, Visitor}; +use super::ReflectDeserializerProcessor; + /// A [`Visitor`] for deserializing [`Enum`] values. /// /// [`Enum`]: crate::Enum -pub(super) struct EnumVisitor<'a> { - enum_info: &'static EnumInfo, - registration: &'a TypeRegistration, - registry: &'a TypeRegistry, +pub(super) struct EnumVisitor<'a, P> { + pub enum_info: &'static EnumInfo, + pub registration: &'a TypeRegistration, + pub registry: &'a TypeRegistry, + pub processor: Option<&'a mut P>, } -impl<'a> EnumVisitor<'a> { - pub fn new( - enum_info: &'static EnumInfo, - registration: &'a TypeRegistration, - registry: &'a TypeRegistry, - ) -> Self { - Self { - enum_info, - registration, - registry, - } - } -} - -impl<'a, 'de> Visitor<'de> for EnumVisitor<'a> { +impl<'de, P: ReflectDeserializerProcessor> Visitor<'de> for EnumVisitor<'_, P> { type Value = DynamicEnum; fn expecting(&self, formatter: &mut Formatter) -> fmt::Result { @@ -63,6 +52,7 @@ impl<'a, 'de> Visitor<'de> for EnumVisitor<'a> { struct_info, registration: self.registration, registry: self.registry, + processor: self.processor, }, )? .into(), @@ -71,9 +61,12 @@ impl<'a, 'de> Visitor<'de> for EnumVisitor<'a> { *TupleLikeInfo::field_at(tuple_info, 0)?.ty(), self.registry, )?; - let value = variant.newtype_variant_seed( - TypedReflectDeserializer::new_internal(registration, self.registry), - )?; + let value = + variant.newtype_variant_seed(TypedReflectDeserializer::new_internal( + registration, + self.registry, + self.processor, + ))?; let mut dynamic_tuple = DynamicTuple::default(); dynamic_tuple.insert_boxed(value); dynamic_tuple.into() @@ -85,6 +78,7 @@ impl<'a, 'de> Visitor<'de> for EnumVisitor<'a> { tuple_info, registration: self.registration, registry: self.registry, + processor: self.processor, }, )? .into(), @@ -151,13 +145,14 @@ impl<'de> DeserializeSeed<'de> for VariantDeserializer { } } -struct StructVariantVisitor<'a> { +struct StructVariantVisitor<'a, P> { struct_info: &'static StructVariantInfo, registration: &'a TypeRegistration, registry: &'a TypeRegistry, + processor: Option<&'a mut P>, } -impl<'a, 'de> Visitor<'de> for StructVariantVisitor<'a> { +impl<'de, P: ReflectDeserializerProcessor> Visitor<'de> for StructVariantVisitor<'_, P> { type Value = DynamicStruct; fn expecting(&self, formatter: &mut Formatter) -> fmt::Result { @@ -168,24 +163,37 @@ impl<'a, 'de> Visitor<'de> for StructVariantVisitor<'a> { where A: SeqAccess<'de>, { - visit_struct_seq(&mut seq, self.struct_info, self.registration, self.registry) + visit_struct_seq( + &mut seq, + self.struct_info, + self.registration, + self.registry, + self.processor, + ) } fn visit_map(self, mut map: V) -> Result where V: MapAccess<'de>, { - visit_struct(&mut map, self.struct_info, self.registration, self.registry) + visit_struct( + &mut map, + self.struct_info, + self.registration, + self.registry, + self.processor, + ) } } -struct TupleVariantVisitor<'a> { +struct TupleVariantVisitor<'a, P> { tuple_info: &'static TupleVariantInfo, registration: &'a TypeRegistration, registry: &'a TypeRegistry, + processor: Option<&'a mut P>, } -impl<'a, 'de> Visitor<'de> for TupleVariantVisitor<'a> { +impl<'de, P: ReflectDeserializerProcessor> Visitor<'de> for TupleVariantVisitor<'_, P> { type Value = DynamicTuple; fn expecting(&self, formatter: &mut Formatter) -> fmt::Result { @@ -196,6 +204,12 @@ impl<'a, 'de> Visitor<'de> for TupleVariantVisitor<'a> { where V: SeqAccess<'de>, { - visit_tuple(&mut seq, self.tuple_info, self.registration, self.registry) + visit_tuple( + &mut seq, + self.tuple_info, + self.registration, + self.registry, + self.processor, + ) } } diff --git a/crates/bevy_reflect/src/serde/de/lists.rs b/crates/bevy_reflect/src/serde/de/lists.rs index 7d4ab44f8a..b85e46874a 100644 --- a/crates/bevy_reflect/src/serde/de/lists.rs +++ b/crates/bevy_reflect/src/serde/de/lists.rs @@ -5,31 +5,25 @@ use crate::{ use core::{fmt, fmt::Formatter}; use serde::de::{SeqAccess, Visitor}; +use super::ReflectDeserializerProcessor; + /// A [`Visitor`] for deserializing [`List`] values. /// /// [`List`]: crate::List -pub(super) struct ListVisitor<'a> { - list_info: &'static ListInfo, - registry: &'a TypeRegistry, +pub(super) struct ListVisitor<'a, P> { + pub list_info: &'static ListInfo, + pub registry: &'a TypeRegistry, + pub processor: Option<&'a mut P>, } -impl<'a> ListVisitor<'a> { - pub fn new(list_info: &'static ListInfo, registry: &'a TypeRegistry) -> Self { - Self { - list_info, - registry, - } - } -} - -impl<'a, 'de> Visitor<'de> for ListVisitor<'a> { +impl<'de, P: ReflectDeserializerProcessor> Visitor<'de> for ListVisitor<'_, P> { type Value = DynamicList; fn expecting(&self, formatter: &mut Formatter) -> fmt::Result { formatter.write_str("reflected list value") } - fn visit_seq(self, mut seq: V) -> Result + fn visit_seq(mut self, mut seq: V) -> Result where V: SeqAccess<'de>, { @@ -38,6 +32,7 @@ impl<'a, 'de> Visitor<'de> for ListVisitor<'a> { while let Some(value) = seq.next_element_seed(TypedReflectDeserializer::new_internal( registration, self.registry, + self.processor.as_deref_mut(), ))? { list.push_box(value); } diff --git a/crates/bevy_reflect/src/serde/de/maps.rs b/crates/bevy_reflect/src/serde/de/maps.rs index fbb5f9d449..95b1c1f83e 100644 --- a/crates/bevy_reflect/src/serde/de/maps.rs +++ b/crates/bevy_reflect/src/serde/de/maps.rs @@ -5,28 +5,25 @@ use crate::{ use core::{fmt, fmt::Formatter}; use serde::de::{MapAccess, Visitor}; +use super::ReflectDeserializerProcessor; + /// A [`Visitor`] for deserializing [`Map`] values. /// /// [`Map`]: crate::Map -pub(super) struct MapVisitor<'a> { - map_info: &'static MapInfo, - registry: &'a TypeRegistry, +pub(super) struct MapVisitor<'a, P> { + pub map_info: &'static MapInfo, + pub registry: &'a TypeRegistry, + pub processor: Option<&'a mut P>, } -impl<'a> MapVisitor<'a> { - pub fn new(map_info: &'static MapInfo, registry: &'a TypeRegistry) -> Self { - Self { map_info, registry } - } -} - -impl<'a, 'de> Visitor<'de> for MapVisitor<'a> { +impl<'de, P: ReflectDeserializerProcessor> Visitor<'de> for MapVisitor<'_, P> { type Value = DynamicMap; fn expecting(&self, formatter: &mut Formatter) -> fmt::Result { formatter.write_str("reflected map value") } - fn visit_map(self, mut map: V) -> Result + fn visit_map(mut self, mut map: V) -> Result where V: MapAccess<'de>, { @@ -36,10 +33,12 @@ impl<'a, 'de> Visitor<'de> for MapVisitor<'a> { while let Some(key) = map.next_key_seed(TypedReflectDeserializer::new_internal( key_registration, self.registry, + self.processor.as_deref_mut(), ))? { let value = map.next_value_seed(TypedReflectDeserializer::new_internal( value_registration, self.registry, + self.processor.as_deref_mut(), ))?; dynamic_map.insert_boxed(key, value); } diff --git a/crates/bevy_reflect/src/serde/de/mod.rs b/crates/bevy_reflect/src/serde/de/mod.rs index 92a43ed175..b1ada1835e 100644 --- a/crates/bevy_reflect/src/serde/de/mod.rs +++ b/crates/bevy_reflect/src/serde/de/mod.rs @@ -1,5 +1,6 @@ pub use deserialize_with_registry::*; pub use deserializer::*; +pub use processor::*; pub use registrations::*; mod arrays; @@ -11,6 +12,7 @@ mod helpers; mod lists; mod maps; mod options; +mod processor; mod registration_utils; mod registrations; mod sets; @@ -24,12 +26,15 @@ mod tuples; mod tests { use bincode::Options; use core::{any::TypeId, f32::consts::PI, ops::RangeInclusive}; + use serde::de::IgnoredAny; + use serde::Deserializer; use serde::{de::DeserializeSeed, Deserialize}; use bevy_utils::{HashMap, HashSet}; - use crate as bevy_reflect; + use crate::serde::ReflectDeserializerProcessor; + use crate::{self as bevy_reflect, TypeRegistration}; use crate::{ serde::{ReflectDeserializer, ReflectSerializer, TypedReflectDeserializer}, DynamicEnum, FromReflect, PartialReflect, Reflect, ReflectDeserialize, TypeRegistry, @@ -275,15 +280,14 @@ mod tests { let mut registry = get_registry(); registry.register::(); let registration = registry.get(TypeId::of::()).unwrap(); - let reflect_deserializer = TypedReflectDeserializer::new_internal(registration, ®istry); + let reflect_deserializer = TypedReflectDeserializer::new(registration, ®istry); let mut ron_deserializer = ron::de::Deserializer::from_str(input).unwrap(); let dynamic_output = reflect_deserializer .deserialize(&mut ron_deserializer) .unwrap(); let output = - ::from_reflect(dynamic_output.as_ref().as_partial_reflect()) - .unwrap(); + ::from_reflect(dynamic_output.as_partial_reflect()).unwrap(); assert_eq!(expected, output); } @@ -517,6 +521,243 @@ mod tests { assert_eq!(error, ron::Error::Message("type `core::ops::RangeInclusive` did not register the `ReflectDeserialize` type data. For certain types, this may need to be registered manually using `register_type_data`".to_string())); } + #[test] + fn should_use_processor_for_custom_deserialization() { + #[derive(Reflect, Debug, PartialEq)] + struct Foo { + bar: i32, + qux: i64, + } + + struct FooProcessor; + + impl ReflectDeserializerProcessor for FooProcessor { + fn try_deserialize<'de, D>( + &mut self, + registration: &TypeRegistration, + _: &TypeRegistry, + deserializer: D, + ) -> Result, D>, D::Error> + where + D: Deserializer<'de>, + { + if registration.type_id() == TypeId::of::() { + let _ = deserializer.deserialize_ignored_any(IgnoredAny); + Ok(Ok(Box::new(456_i64))) + } else { + Ok(Err(deserializer)) + } + } + } + + let expected = Foo { bar: 123, qux: 456 }; + + let input = r#"( + bar: 123, + qux: 123, + )"#; + + let mut registry = get_registry(); + registry.register::(); + let registration = registry.get(TypeId::of::()).unwrap(); + let mut processor = FooProcessor; + let reflect_deserializer = + TypedReflectDeserializer::with_processor(registration, ®istry, &mut processor); + let mut ron_deserializer = ron::de::Deserializer::from_str(input).unwrap(); + let dynamic_output = reflect_deserializer + .deserialize(&mut ron_deserializer) + .unwrap(); + + let output = + ::from_reflect(dynamic_output.as_partial_reflect()).unwrap(); + assert_eq!(expected, output); + } + + #[test] + fn should_use_processor_for_multiple_registrations() { + #[derive(Reflect, Debug, PartialEq)] + struct Foo { + bar: i32, + qux: i64, + } + + struct FooProcessor; + + impl ReflectDeserializerProcessor for FooProcessor { + fn try_deserialize<'de, D>( + &mut self, + registration: &TypeRegistration, + _: &TypeRegistry, + deserializer: D, + ) -> Result, D>, D::Error> + where + D: Deserializer<'de>, + { + if registration.type_id() == TypeId::of::() { + let _ = deserializer.deserialize_ignored_any(IgnoredAny); + Ok(Ok(Box::new(123_i32))) + } else if registration.type_id() == TypeId::of::() { + let _ = deserializer.deserialize_ignored_any(IgnoredAny); + Ok(Ok(Box::new(456_i64))) + } else { + Ok(Err(deserializer)) + } + } + } + + let expected = Foo { bar: 123, qux: 456 }; + + let input = r#"( + bar: 0, + qux: 0, + )"#; + + let mut registry = get_registry(); + registry.register::(); + let registration = registry.get(TypeId::of::()).unwrap(); + let mut processor = FooProcessor; + let reflect_deserializer = + TypedReflectDeserializer::with_processor(registration, ®istry, &mut processor); + let mut ron_deserializer = ron::de::Deserializer::from_str(input).unwrap(); + let dynamic_output = reflect_deserializer + .deserialize(&mut ron_deserializer) + .unwrap(); + + let output = + ::from_reflect(dynamic_output.as_partial_reflect()).unwrap(); + assert_eq!(expected, output); + } + + #[test] + fn should_propagate_processor_deserialize_error() { + struct ErroringProcessor; + + impl ReflectDeserializerProcessor for ErroringProcessor { + fn try_deserialize<'de, D>( + &mut self, + registration: &TypeRegistration, + _: &TypeRegistry, + deserializer: D, + ) -> Result, D>, D::Error> + where + D: Deserializer<'de>, + { + if registration.type_id() == TypeId::of::() { + Err(serde::de::Error::custom("my custom deserialize error")) + } else { + Ok(Err(deserializer)) + } + } + } + + let registry = get_registry(); + + let input = r#"{"i32":123}"#; + let mut deserializer = ron::de::Deserializer::from_str(input).unwrap(); + let mut processor = ErroringProcessor; + let reflect_deserializer = ReflectDeserializer::with_processor(®istry, &mut processor); + let error = reflect_deserializer + .deserialize(&mut deserializer) + .unwrap_err(); + + #[cfg(feature = "debug_stack")] + assert_eq!( + error, + ron::Error::Message("my custom deserialize error (stack: `i32`)".to_string()) + ); + #[cfg(not(feature = "debug_stack"))] + assert_eq!( + error, + ron::Error::Message("my custom deserialize error".to_string()) + ); + } + + #[test] + fn should_access_local_scope_in_processor() { + struct ValueCountingProcessor<'a> { + values_found: &'a mut usize, + } + + impl ReflectDeserializerProcessor for ValueCountingProcessor<'_> { + fn try_deserialize<'de, D>( + &mut self, + _: &TypeRegistration, + _: &TypeRegistry, + deserializer: D, + ) -> Result, D>, D::Error> + where + D: Deserializer<'de>, + { + let _ = deserializer.deserialize_ignored_any(IgnoredAny)?; + *self.values_found += 1; + Ok(Ok(Box::new(123_i32))) + } + } + + let registry = get_registry(); + + let input = r#"{"i32":0}"#; + + let mut values_found = 0_usize; + let mut deserializer_processor = ValueCountingProcessor { + values_found: &mut values_found, + }; + + let mut deserializer = ron::de::Deserializer::from_str(input).unwrap(); + let reflect_deserializer = + ReflectDeserializer::with_processor(®istry, &mut deserializer_processor); + reflect_deserializer.deserialize(&mut deserializer).unwrap(); + assert_eq!(1, values_found); + } + + #[test] + fn should_fail_from_reflect_if_processor_returns_wrong_typed_value() { + #[derive(Reflect, Debug, PartialEq)] + struct Foo { + bar: i32, + qux: i64, + } + + struct WrongTypeProcessor; + + impl ReflectDeserializerProcessor for WrongTypeProcessor { + fn try_deserialize<'de, D>( + &mut self, + registration: &TypeRegistration, + _registry: &TypeRegistry, + deserializer: D, + ) -> Result, D>, D::Error> + where + D: Deserializer<'de>, + { + if registration.type_id() == TypeId::of::() { + let _ = deserializer.deserialize_ignored_any(IgnoredAny); + Ok(Ok(Box::new(42_i64))) + } else { + Ok(Err(deserializer)) + } + } + } + + let input = r#"( + bar: 123, + qux: 123, + )"#; + + let mut registry = get_registry(); + registry.register::(); + let registration = registry.get(TypeId::of::()).unwrap(); + let mut processor = WrongTypeProcessor; + let reflect_deserializer = + TypedReflectDeserializer::with_processor(registration, ®istry, &mut processor); + let mut ron_deserializer = ron::de::Deserializer::from_str(input).unwrap(); + let dynamic_output = reflect_deserializer + .deserialize(&mut ron_deserializer) + .unwrap(); + + assert!(::from_reflect(dynamic_output.as_partial_reflect()).is_none()); + } + #[cfg(feature = "functions")] mod functions { use super::*; diff --git a/crates/bevy_reflect/src/serde/de/options.rs b/crates/bevy_reflect/src/serde/de/options.rs index de9ded5075..f347c4a67d 100644 --- a/crates/bevy_reflect/src/serde/de/options.rs +++ b/crates/bevy_reflect/src/serde/de/options.rs @@ -8,22 +8,16 @@ use crate::{ use core::{fmt, fmt::Formatter}; use serde::de::{DeserializeSeed, Error, Visitor}; +use super::ReflectDeserializerProcessor; + /// A [`Visitor`] for deserializing [`Option`] values. -pub(super) struct OptionVisitor<'a> { - enum_info: &'static EnumInfo, - registry: &'a TypeRegistry, +pub(super) struct OptionVisitor<'a, P> { + pub enum_info: &'static EnumInfo, + pub registry: &'a TypeRegistry, + pub processor: Option<&'a mut P>, } -impl<'a> OptionVisitor<'a> { - pub fn new(enum_info: &'static EnumInfo, registry: &'a TypeRegistry) -> Self { - Self { - enum_info, - registry, - } - } -} - -impl<'a, 'de> Visitor<'de> for OptionVisitor<'a> { +impl<'de, P: ReflectDeserializerProcessor> Visitor<'de> for OptionVisitor<'_, P> { type Value = DynamicEnum; fn expecting(&self, formatter: &mut Formatter) -> fmt::Result { @@ -49,7 +43,11 @@ impl<'a, 'de> Visitor<'de> for OptionVisitor<'a> { VariantInfo::Tuple(tuple_info) if tuple_info.field_len() == 1 => { let field = tuple_info.field_at(0).unwrap(); let registration = try_get_registration(*field.ty(), self.registry)?; - let de = TypedReflectDeserializer::new_internal(registration, self.registry); + let de = TypedReflectDeserializer::new_internal( + registration, + self.registry, + self.processor, + ); let mut value = DynamicTuple::default(); value.insert_boxed(de.deserialize(deserializer)?); let mut option = DynamicEnum::default(); diff --git a/crates/bevy_reflect/src/serde/de/processor.rs b/crates/bevy_reflect/src/serde/de/processor.rs new file mode 100644 index 0000000000..7dbe0388b4 --- /dev/null +++ b/crates/bevy_reflect/src/serde/de/processor.rs @@ -0,0 +1,213 @@ +use crate::{PartialReflect, TypeRegistration, TypeRegistry}; + +/// 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`], or return +/// ownership of the deserializer back, and continue with the default logic. +/// +/// # 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: +/// +/// ``` +/// # use bevy_reflect::serde::{ReflectDeserializer, ReflectDeserializerProcessor}; +/// # use bevy_reflect::{PartialReflect, Reflect, TypeData, TypeRegistration, TypeRegistry}; +/// # use serde::de::{DeserializeSeed, Deserializer, Visitor}; +/// # use std::marker::PhantomData; +/// # +/// # #[derive(Debug, Clone, Reflect)] +/// # struct LoadedUntypedAsset; +/// # #[derive(Debug, Clone, Reflect)] +/// # struct Handle(T); +/// # #[derive(Debug, Clone, Reflect)] +/// # struct Mesh; +/// # +/// # struct LoadContext; +/// # impl LoadContext { +/// # fn load(&mut self) -> &mut Self { unimplemented!() } +/// # fn with_asset_type_id(&mut self, (): ()) -> &mut Self { unimplemented!() } +/// # fn untyped(&mut self) -> &mut Self { unimplemented!() } +/// # fn load_asset(&mut self, (): ()) -> Handle { unimplemented!() } +/// # } +/// # +/// # struct ReflectHandle; +/// # impl TypeData for ReflectHandle { +/// # fn clone_type_data(&self) -> Box { +/// # unimplemented!() +/// # } +/// # } +/// # impl ReflectHandle { +/// # fn asset_type_id(&self) { +/// # unimplemented!() +/// # } +/// # } +/// # +/// # struct AssetPathVisitor; +/// # impl<'de> Visitor<'de> for AssetPathVisitor { +/// # type Value = (); +/// # fn expecting(&self, formatter: &mut core::fmt::Formatter) -> core::fmt::Result { unimplemented!() } +/// # } +/// # type AssetError = Box; +/// #[derive(Debug, Clone, Reflect)] +/// struct MyAsset { +/// name: String, +/// mesh: Handle, +/// } +/// +/// fn load( +/// asset_bytes: &[u8], +/// type_registry: &TypeRegistry, +/// load_context: &mut LoadContext, +/// ) -> Result { +/// 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, D>, D::Error> +/// where +/// D: Deserializer<'de>, +/// { +/// let Some(reflect_handle) = registration.data::() 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 = self.load_context +/// .load() +/// .with_asset_type_id(asset_type_id) +/// .untyped() +/// .load_asset(asset_path); +/// # let _: Result<_, ()> = { +/// Ok(Box::new(handle)) +/// # }; +/// # unimplemented!() +/// } +/// } +/// +/// 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)?; +/// # unimplemented!() +/// } +/// ``` +/// +/// [`ReflectDeserializer`]: crate::serde::ReflectDeserializer +/// [`TypedReflectDeserializer`]: crate::serde::TypedReflectDeserializer +/// [`try_deserialize`]: Self::try_deserialize +/// [`DeserializeWithRegistry`]: crate::serde::DeserializeWithRegistry +pub trait ReflectDeserializerProcessor { + /// 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`] 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 bevy_reflect::{TypeRegistration, PartialReflect, TypeRegistry}; + /// # use bevy_reflect::serde::ReflectDeserializerProcessor; + /// # use core::any::TypeId; + /// use serde::de::IgnoredAny; + /// + /// struct ConstantI32Processor; + /// + /// impl ReflectDeserializerProcessor for ConstantI32Processor { + /// fn try_deserialize<'de, D>( + /// &mut self, + /// registration: &TypeRegistration, + /// _registry: &TypeRegistry, + /// deserializer: D, + /// ) -> Result, D>, D::Error> + /// where + /// D: serde::Deserializer<'de> + /// { + /// if registration.type_id() == TypeId::of::() { + /// _ = deserializer.deserialize_ignored_any(IgnoredAny); + /// Ok(Ok(Box::new(42_i32))) + /// } else { + /// Ok(Err(deserializer)) + /// } + /// } + /// } + /// ``` + /// + /// [`TypedReflectDeserializer`]: crate::serde::TypedReflectDeserializer + /// [`FromReflect`]: crate::FromReflect + fn try_deserialize<'de, D>( + &mut self, + registration: &TypeRegistration, + registry: &TypeRegistry, + deserializer: D, + ) -> Result, D>, D::Error> + where + D: serde::Deserializer<'de>; +} + +impl ReflectDeserializerProcessor for () { + fn try_deserialize<'de, D>( + &mut self, + _registration: &TypeRegistration, + _registry: &TypeRegistry, + deserializer: D, + ) -> Result, D>, D::Error> + where + D: serde::Deserializer<'de>, + { + Ok(Err(deserializer)) + } +} diff --git a/crates/bevy_reflect/src/serde/de/sets.rs b/crates/bevy_reflect/src/serde/de/sets.rs index faecf5bc39..ed1a469df3 100644 --- a/crates/bevy_reflect/src/serde/de/sets.rs +++ b/crates/bevy_reflect/src/serde/de/sets.rs @@ -5,28 +5,25 @@ use crate::{ use core::{fmt, fmt::Formatter}; use serde::de::{SeqAccess, Visitor}; +use super::ReflectDeserializerProcessor; + /// A [`Visitor`] for deserializing [`Set`] values. /// /// [`Set`]: crate::Set -pub(super) struct SetVisitor<'a> { - set_info: &'static SetInfo, - registry: &'a TypeRegistry, +pub(super) struct SetVisitor<'a, P> { + pub set_info: &'static SetInfo, + pub registry: &'a TypeRegistry, + pub processor: Option<&'a mut P>, } -impl<'a> SetVisitor<'a> { - pub fn new(set_info: &'static SetInfo, registry: &'a TypeRegistry) -> Self { - Self { set_info, registry } - } -} - -impl<'a, 'de> Visitor<'de> for SetVisitor<'a> { +impl<'de, P: ReflectDeserializerProcessor> Visitor<'de> for SetVisitor<'_, P> { type Value = DynamicSet; fn expecting(&self, formatter: &mut Formatter) -> fmt::Result { formatter.write_str("reflected set value") } - fn visit_seq(self, mut set: V) -> Result + fn visit_seq(mut self, mut set: V) -> Result where V: SeqAccess<'de>, { @@ -35,6 +32,7 @@ impl<'a, 'de> Visitor<'de> for SetVisitor<'a> { while let Some(value) = set.next_element_seed(TypedReflectDeserializer::new_internal( value_registration, self.registry, + self.processor.as_deref_mut(), ))? { dynamic_set.insert_boxed(value); } diff --git a/crates/bevy_reflect/src/serde/de/struct_utils.rs b/crates/bevy_reflect/src/serde/de/struct_utils.rs index 0833678753..8f3a3250ff 100644 --- a/crates/bevy_reflect/src/serde/de/struct_utils.rs +++ b/crates/bevy_reflect/src/serde/de/struct_utils.rs @@ -12,6 +12,8 @@ use crate::{ use core::slice::Iter; use serde::de::{Error, MapAccess, SeqAccess}; +use super::ReflectDeserializerProcessor; + /// A helper trait for accessing type information from struct-like types. pub(super) trait StructLikeInfo { fn field(&self, name: &str) -> Result<&NamedField, E>; @@ -83,15 +85,17 @@ impl StructLikeInfo for StructVariantInfo { /// Deserializes a [struct-like] type from a mapping of fields, returning a [`DynamicStruct`]. /// /// [struct-like]: StructLikeInfo -pub(super) fn visit_struct<'de, T, V>( +pub(super) fn visit_struct<'de, T, V, P>( map: &mut V, info: &'static T, registration: &TypeRegistration, registry: &TypeRegistry, + mut processor: Option<&mut P>, ) -> Result where T: StructLikeInfo, V: MapAccess<'de>, + P: ReflectDeserializerProcessor, { let mut dynamic_struct = DynamicStruct::default(); while let Some(Ident(key)) = map.next_key::()? { @@ -107,6 +111,7 @@ where let value = map.next_value_seed(TypedReflectDeserializer::new_internal( registration, registry, + processor.as_deref_mut(), ))?; dynamic_struct.insert_boxed(&key, value); } @@ -129,15 +134,17 @@ where /// Deserializes a [struct-like] type from a sequence of fields, returning a [`DynamicStruct`]. /// /// [struct-like]: StructLikeInfo -pub(super) fn visit_struct_seq<'de, T, V>( +pub(super) fn visit_struct_seq<'de, T, V, P>( seq: &mut V, info: &T, registration: &TypeRegistration, registry: &TypeRegistry, + mut processor: Option<&mut P>, ) -> Result where T: StructLikeInfo, V: SeqAccess<'de>, + P: ReflectDeserializerProcessor, { let mut dynamic_struct = DynamicStruct::default(); @@ -167,6 +174,7 @@ where .next_element_seed(TypedReflectDeserializer::new_internal( try_get_registration(*info.field_at(index)?.ty(), registry)?, registry, + processor.as_deref_mut(), ))? .ok_or_else(|| Error::invalid_length(index, &len.to_string().as_str()))?; dynamic_struct.insert_boxed(name, value); diff --git a/crates/bevy_reflect/src/serde/de/structs.rs b/crates/bevy_reflect/src/serde/de/structs.rs index 750c739e8e..0135e96358 100644 --- a/crates/bevy_reflect/src/serde/de/structs.rs +++ b/crates/bevy_reflect/src/serde/de/structs.rs @@ -5,30 +5,19 @@ use crate::{ use core::{fmt, fmt::Formatter}; use serde::de::{MapAccess, SeqAccess, Visitor}; +use super::ReflectDeserializerProcessor; + /// A [`Visitor`] for deserializing [`Struct`] values. /// /// [`Struct`]: crate::Struct -pub(super) struct StructVisitor<'a> { - struct_info: &'static StructInfo, - registration: &'a TypeRegistration, - registry: &'a TypeRegistry, +pub(super) struct StructVisitor<'a, P> { + pub struct_info: &'static StructInfo, + pub registration: &'a TypeRegistration, + pub registry: &'a TypeRegistry, + pub processor: Option<&'a mut P>, } -impl<'a> StructVisitor<'a> { - pub fn new( - struct_info: &'static StructInfo, - registration: &'a TypeRegistration, - registry: &'a TypeRegistry, - ) -> Self { - Self { - struct_info, - registration, - registry, - } - } -} - -impl<'a, 'de> Visitor<'de> for StructVisitor<'a> { +impl<'de, P: ReflectDeserializerProcessor> Visitor<'de> for StructVisitor<'_, P> { type Value = DynamicStruct; fn expecting(&self, formatter: &mut Formatter) -> fmt::Result { @@ -39,13 +28,25 @@ impl<'a, 'de> Visitor<'de> for StructVisitor<'a> { where A: SeqAccess<'de>, { - visit_struct_seq(&mut seq, self.struct_info, self.registration, self.registry) + visit_struct_seq( + &mut seq, + self.struct_info, + self.registration, + self.registry, + self.processor, + ) } fn visit_map(self, mut map: V) -> Result where V: MapAccess<'de>, { - visit_struct(&mut map, self.struct_info, self.registration, self.registry) + visit_struct( + &mut map, + self.struct_info, + self.registration, + self.registry, + self.processor, + ) } } diff --git a/crates/bevy_reflect/src/serde/de/tuple_structs.rs b/crates/bevy_reflect/src/serde/de/tuple_structs.rs index c9703cb504..af33b8d0b3 100644 --- a/crates/bevy_reflect/src/serde/de/tuple_structs.rs +++ b/crates/bevy_reflect/src/serde/de/tuple_structs.rs @@ -7,30 +7,19 @@ use serde::de::{DeserializeSeed, SeqAccess, Visitor}; use super::{registration_utils::try_get_registration, TypedReflectDeserializer}; +use super::ReflectDeserializerProcessor; + /// A [`Visitor`] for deserializing [`TupleStruct`] values. /// /// [`TupleStruct`]: crate::TupleStruct -pub(super) struct TupleStructVisitor<'a> { - tuple_struct_info: &'static TupleStructInfo, - registration: &'a TypeRegistration, - registry: &'a TypeRegistry, +pub(super) struct TupleStructVisitor<'a, P> { + pub tuple_struct_info: &'static TupleStructInfo, + pub registration: &'a TypeRegistration, + pub registry: &'a TypeRegistry, + pub processor: Option<&'a mut P>, } -impl<'a> TupleStructVisitor<'a> { - pub fn new( - tuple_struct_info: &'static TupleStructInfo, - registration: &'a TypeRegistration, - registry: &'a TypeRegistry, - ) -> Self { - Self { - tuple_struct_info, - registration, - registry, - } - } -} - -impl<'a, 'de> Visitor<'de> for TupleStructVisitor<'a> { +impl<'de, P: ReflectDeserializerProcessor> Visitor<'de> for TupleStructVisitor<'_, P> { type Value = DynamicTupleStruct; fn expecting(&self, formatter: &mut Formatter) -> fmt::Result { @@ -46,6 +35,7 @@ impl<'a, 'de> Visitor<'de> for TupleStructVisitor<'a> { self.tuple_struct_info, self.registration, self.registry, + self.processor, ) .map(DynamicTupleStruct::from) } @@ -71,7 +61,7 @@ impl<'a, 'de> Visitor<'de> for TupleStructVisitor<'a> { self.registry, )?; let reflect_deserializer = - TypedReflectDeserializer::new_internal(registration, self.registry); + TypedReflectDeserializer::new_internal(registration, self.registry, self.processor); let value = reflect_deserializer.deserialize(deserializer)?; tuple.insert_boxed(value.into_partial_reflect()); diff --git a/crates/bevy_reflect/src/serde/de/tuple_utils.rs b/crates/bevy_reflect/src/serde/de/tuple_utils.rs index ae49fe4084..9c96d78a67 100644 --- a/crates/bevy_reflect/src/serde/de/tuple_utils.rs +++ b/crates/bevy_reflect/src/serde/de/tuple_utils.rs @@ -8,6 +8,8 @@ use crate::{ }; use serde::de::{Error, SeqAccess}; +use super::ReflectDeserializerProcessor; + pub(super) trait TupleLikeInfo { fn field_at(&self, index: usize) -> Result<&UnnamedField, E>; fn field_len(&self) -> usize; @@ -64,15 +66,17 @@ impl TupleLikeInfo for TupleVariantInfo { /// Deserializes a [tuple-like] type from a sequence of elements, returning a [`DynamicTuple`]. /// /// [tuple-like]: TupleLikeInfo -pub(super) fn visit_tuple<'de, T, V>( +pub(super) fn visit_tuple<'de, T, V, P>( seq: &mut V, info: &T, registration: &TypeRegistration, registry: &TypeRegistry, + mut processor: Option<&mut P>, ) -> Result where T: TupleLikeInfo, V: SeqAccess<'de>, + P: ReflectDeserializerProcessor, { let mut tuple = DynamicTuple::default(); @@ -95,6 +99,7 @@ where .next_element_seed(TypedReflectDeserializer::new_internal( try_get_registration(*info.field_at(index)?.ty(), registry)?, registry, + processor.as_deref_mut(), ))? .ok_or_else(|| Error::invalid_length(index, &len.to_string().as_str()))?; tuple.insert_boxed(value); diff --git a/crates/bevy_reflect/src/serde/de/tuples.rs b/crates/bevy_reflect/src/serde/de/tuples.rs index ea06ad3154..87b9fc81c9 100644 --- a/crates/bevy_reflect/src/serde/de/tuples.rs +++ b/crates/bevy_reflect/src/serde/de/tuples.rs @@ -4,30 +4,19 @@ use crate::{ use core::{fmt, fmt::Formatter}; use serde::de::{SeqAccess, Visitor}; +use super::ReflectDeserializerProcessor; + /// A [`Visitor`] for deserializing [`Tuple`] values. /// /// [`Tuple`]: crate::Tuple -pub(super) struct TupleVisitor<'a> { - tuple_info: &'static TupleInfo, - registration: &'a TypeRegistration, - registry: &'a TypeRegistry, +pub(super) struct TupleVisitor<'a, P> { + pub tuple_info: &'static TupleInfo, + pub registration: &'a TypeRegistration, + pub registry: &'a TypeRegistry, + pub processor: Option<&'a mut P>, } -impl<'a> TupleVisitor<'a> { - pub fn new( - tuple_info: &'static TupleInfo, - registration: &'a TypeRegistration, - registry: &'a TypeRegistry, - ) -> Self { - Self { - tuple_info, - registration, - registry, - } - } -} - -impl<'a, 'de> Visitor<'de> for TupleVisitor<'a> { +impl<'de, P: ReflectDeserializerProcessor> Visitor<'de> for TupleVisitor<'_, P> { type Value = DynamicTuple; fn expecting(&self, formatter: &mut Formatter) -> fmt::Result { @@ -38,6 +27,12 @@ impl<'a, 'de> Visitor<'de> for TupleVisitor<'a> { where V: SeqAccess<'de>, { - visit_tuple(&mut seq, self.tuple_info, self.registration, self.registry) + visit_tuple( + &mut seq, + self.tuple_info, + self.registration, + self.registry, + self.processor, + ) } }