serde icon indicating copy to clipboard operation
serde copied to clipboard

Adjacently tagged enum unit variant does not allow sequence representation of size 1

Open Kobzol opened this issue 4 years ago • 3 comments

Hi! I noticed that there is a discrepancy in deserializing adjacently tagged unit variants. If there is an adjacently tagged unit variant, like this:

#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)]
#[serde(tag = "type", content = "payload")]
pub enum Example {
    Variant1
}

serde will serialize this as a struct containing a single key type with the value Variant1. The concrete implementation might encode this struct either as a map or as a sequence.

During deserialization, either a map or a seq is expected. If the input is a map, the code assumes that it might only contain the tag field, and not the content field (https://github.com/serde-rs/serde/blob/master/serde_derive/src/de.rs#L1567). However, this assumption is provided only for the map representation. If the adjacently tagged enum unit variant is encoded with a seq, the code assumes that the sequence must have two elements.

For example, if you serialize the unit variant as {"type": "Variant1"}, during deserialization it will be okay. But if you serialize it as ["Variant1"], the deserialization will fail (invalid length 1, expected adjacently tagged enum Example). This causes problems in msgpack-rust (https://github.com/3Hren/msgpack-rust/issues/250).

Is this behaviour intended? Or would you be willing to change it so that sequences of length 1 are okay? I can send a PR if you can guide me a little bit.

Kobzol avatar Jun 20 '21 21:06 Kobzol

I tried to create a prototype implementation here. I'd be glad for any fedback.

Kobzol avatar Jun 21 '21 07:06 Kobzol

You don't want to just check for unit variants. You want to check for new type variants as well. They might have an optional type.

gcoakes avatar Feb 17 '22 06:02 gcoakes