Am I passing metadata through DeserializeSeed to facilitate deserialization of algebraic datatypes as intended
hirenhpatel opened this issue · 2 comments
I have data types that need to be deserialized from json that look like this:
// inlining inner Node struct to better illustrate structure of data-tree:
struct MyData {
field1: Dynamic<(Float, String, Node {fieldA: Scalar<Int>, ...} )>,
field2: Scalar<String>,
}
The datatypes that appear are quite varied, and as a result, I am essentially writing my own implementations of Deserialize
.
I have now reached a situation where I need extra information (let's call it MyMetadata
) to properly deserialize the Node
struct.
Happily, I found DeserializeSeed
and started to rewrite all my Deserialize
implementations to DeserializeSeed
implementations since I can then utilize the extra seed
to argument pipe MyMetadata
through deserialization. My thought here is MyMetadata
tags along for the ride remaining unused, until a Node
is encountered by the Visitor
at which point I can use it to facilitate deserialization.
Unfortunately, I've run into an awkward problem: it seems that I'm not supposed to implement DeserializeSeed
on Dynamic
, Scalar
, Float
like I am supposed to in Deserialize
. Rather, I'm supposed to implement it on a new data structure, and the associated return type is supposed to be one of Dynamic
, Scalar
, Float
. With that interface, it's not clear to me how I should be using DeserializeSeed
to move the MyMetadata
through the deserialization process?
Should I add an unused generic parameter on MyMetadata
and implement DeserializeSeed
on the various concrete types, converting them to other concrete types in my implementation of Visitor
?
Usually you would implement DeserializeSeed
on the same type that also has the corresponding Visitor
impl. So a canonical impl would look like:
impl<'de> DeserializeSeed<'de> for TheVisitor {
type Value = <Self as Visitor<'de>>::Value;
fn deserialize<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
where
D: Deserializer<'de>,
{
deserializer.deserialize_………(self)
}
}
The thought of implementing DeserializeSeed
on Visitor
never occurred to me! After studying your suggestion some more, I have settled on the pattern of having a surrogate nested visitor type DynamicVisitor<TupleVisitor<..., NodeVisitor<...>>
that mirrors the target deserialization datatype: Dynamic<(..., NodeVisitor<...>)>
.
I have implemented DeserializeSeed<'de>
on all of the *Visitor
structs, which have the metadata as needed. Then, most of the my deserialize calls look like this
deserializer.deserialize_*(self.0)
to pass the inner visitor to the next step in the recursion.
Have I understand your guidance correctly?
Further, do I understand correctly that, in my recursive deserialization implementations, I should
not mix Deserialize
with DeserializeSeed
? That is, in any chain, I will be dealing with Deserialize<'de>
exclusively, or with DeserializeSeed<'de>
exclusively?
Thanks in advance