serde-rs/json

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