Skip to content

Round-trip failure: untagged enum containing Vec variant is improperly deserialized #357

@obi1kenobi

Description

@obi1kenobi

Consider the following types:

#[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
#[serde(untagged)]
enum MyValue {
    Int(i64),
    String(String),
    Enum(Enum),
    List(Vec<MyValue>),
}

#[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
enum Enum {
    First(String),
    Second(i64),
}

Let's try serializing a MyValue::Enum value like the following: MyValue::Enum(Enum::First("foo".to_string())). Its RON-serialized value is First("foo").

That First("foo") value unfortunately deserializes to MyValue::List([MyValue::String("foo")]) instead of our original enum-based value. This is surprising to me, because the deserialization code decides to ignore the First prefix entirely, and skip forward until the ( then deserialize a list with it. It's especially surprising because the MyValue::Enum variant is before the MyValue::List variant, and yet we still get a MyValue::List back instead of MyValue::Enum.

Here's a complete repro:

#[cfg(test)]
mod tests {
    use serde::{Serialize, Deserialize};

    #[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
    #[serde(untagged)]
    enum MyValue {
        Int(i64),
        String(String),
        Enum(Enum),
        List(Vec<MyValue>),
    }

    #[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
    enum Enum {
        First(String),
        Second(i64),
    }

    fn serialize_then_deserialize(value: &MyValue) -> MyValue {
        ron::from_str(ron::to_string(value).unwrap().as_str()).unwrap()
    }

    #[test]
    fn test() {
        let value = MyValue::Enum(Enum::First("foo".to_string()));
        let deserialized = serialize_then_deserialize(&value);
        assert_eq!(value, deserialized, "Serialized as: {}", ron::to_string(&value).unwrap());
    }
}

This fails with:

running 1 test
thread 'file::tests::test' panicked at 'assertion failed: `(left == right)`
  left: `Enum(First("foo"))`,
 right: `List([String("foo")])`: Serialized as: First("foo")', src/file.rs:X:9

Thanks to everyone that contributes to building and maintaining this awesome library! Any advice on avoiding this issue would be much appreciated.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions