#Serde externally tagged enum wit a single element

1 messages · Page 1 of 1 (latest)

daring canyon
#

Serde seems to have problems deserializing this:

#[derive(Debug, Clone, Copy, Deserialize)]
#[serde(tag = "0", content = "1")]
pub enum Position {
    Stretch,
    Trim(Trim),
}

In the first branch, it tries to read two elements, when the serialzied data is just ["Stretch"]. Does this require a dedicated deserializer or is there any workaround?

daring canyon
#

So far, my only option seems to be a custom deserializer:

struct PositionVisitor;

impl<'de> serde::de::Visitor<'de> for PositionVisitor {
    type Value = Position;

    fn expecting(
        &self,
        formatter: &mut std::fmt::Formatter,
    ) -> std::fmt::Result {
        formatter.write_str("a position, being either a single item or a pair")
    }

    fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
    where
        A: serde::de::SeqAccess<'de>,
    {
        let variant = seq
            .next_element::<String>()?
            .ok_or_else(|| serde::de::Error::invalid_length(0, &self))?;

        let deserialized = match &variant[..] {
            "Trim" => {
                Position::Trim(seq.next_element()?.ok_or_else(|| {
                    serde::de::Error::invalid_length(1, &self)
                })?)
            }
            "Stretch" => Position::Stretch,
            _ => {
                return Err(serde::de::Error::custom(format!(
                    "unknown type {variant}"
                )))
            }
        };

        Ok(deserialized)
    }
}

impl<'de> Deserialize<'de> for Position {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: Deserializer<'de>,
    {
        deserializer.deserialize_tuple(2, PositionVisitor)
    }
}
median sundial
#

Related issues:

daring canyon
#

Thanks for the reference issues

median sundial
#

It's less than ideal 🙂

daring canyon
#

Yep, not nice

median sundial
#

Another workaround might be

#[serde(other)]
Stretch
#

But (assuming it works) it's not what you want semantically

#

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).

median sundial
#

Maybe you could finish the PR? 😉

daring canyon
daring canyon