Open coriolinus opened 1 year ago
To implement DeserializeAs
and SerializeAs
in this situation, one can simply use the derived Deserialize
and Serialize
impls by using Metadata<DeserializeAsWrap<T>>
/ Metadata<SerializeAsWrap<T>>
and repacking the types as needed:
impl<T, U> SerializeAs<Metadata<T>> for Metadata<U>
where
U: SerializeAs<T>,
{
fn serialize_as<S>(source: &Metadata<T>, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
let source = Metadata::<SerializeAsWrap<T, U>> {
value: source.value.as_ref().map(SerializeAsWrap::new),
original_value: source.original_value.as_ref().map(SerializeAsWrap::new),
has_been_vetted: source.has_been_vetted,
};
source.serialize(serializer)
}
}
impl<'de, T, U> DeserializeAs<'de, Metadata<T>> for Metadata<U>
where
U: DeserializeAs<'de, T>,
{
fn deserialize_as<D>(deserializer: D) -> Result<Metadata<T>, D::Error>
where
D: Deserializer<'de>,
{
let this = Metadata::<DeserializeAsWrap<T, U>>::deserialize(deserializer)?;
Ok(Metadata {
value: this.value.map(DeserializeAsWrap::into_inner),
original_value: this.original_value.map(DeserializeAsWrap::into_inner),
has_been_vetted: this.has_been_vetted,
})
}
}
The SerializeAs
implementation above may require copying or cloning.
If cloning is not possible or undesireable, then the type definition probably has to be duplicated and tweaked to only contain references.
Consider a generic metadata struct:
For basic use cases, this is fine. However, we need to implement
SerializeAs
andDeserializeAs
in order to support modifications to the interior. The desired use case looks likeFor that use case, we need implementations for
SerializeAs
andDeserializeAs
:Unfortunately, the documentation is very unclear as to how precisely to accomplish this, and I'm finding myself confused about how to proceed. At this point, it seems as though the best process might actually be to
cargo expand
theSerialize
andDeserialize
implementations, and then adjust wherever generic values are present in order to wrap them withSerializeAsWrap
orDeserializeAsWrap
wherever a generic parameter exists, essentially reimplementing precisely the same logic thatserde
already does for field naming, optional fields, etc. But that is extremely cumbersome, so hopefully there is a better way!