Skip to content

Binary serialize/deserialize inconsistency of enums with skipped fields #2614

@farmaazon

Description

@farmaazon

When running tests on this snippet:

use serde::{Serialize, Deserialize};

#[derive(Debug, Eq, PartialEq, Serialize, Deserialize)]
enum Abcd {
    A,
    #[serde(skip)]
    B,
    C,
    D,
}

#[cfg(test)]
mod tests {
    use super::*;
    #[test]
    fn bincode() {
        let c = Abcd::C;
        let serialized = bincode2::serialize(&c).unwrap();
        let deserialized: Abcd = bincode2::deserialize(&serialized).unwrap();
        assert_eq!(deserialized, Abcd::C);
    }

    #[test]
    fn postcard() {
        let c = Abcd::C;
        let serialized = postcard::to_allocvec(&c).unwrap();
        let deserialized: Abcd = postcard::from_bytes(&serialized).unwrap();
        assert_eq!(deserialized, Abcd::C);
    }
}

both of them fail, because deserialized is a variant D.

This seems to be a serde_derive problem: when expanding macro, the serialization the value index of C variant is 2:

// ...
        fn serialize<__S>(&self, __serializer: __S) -> _serde::__private::Result<__S::Ok, __S::Error> where __S: _serde::Serializer, {
            match *self {
                Abcd::A => _serde::Serializer::serialize_unit_variant(__serializer, "Abcd", 0u32, "A" ),
                Abcd::B => _serde::__private::Err(_serde::ser::Error::custom("the enum variant Abcd::B cannot be serialized")),
                Abcd::C => _serde::Serializer::serialize_unit_variant(__serializer, "Abcd", 2u32, "C" ),
                Abcd::D => _serde::Serializer::serialize_unit_variant(__serializer, "Abcd", 3u32, "D" ),
            }
        }
// ...

While the FieldVisitor in derived Deserialize expects C being represented by 1u64 if I read code correctly:

// ...
struct __FieldVisitor;
            impl<'de> _serde::de::Visitor<'de> for __FieldVisitor {
                type Value = __Field;
                fn expecting(&self, __formatter: &mut _serde::__private::Formatter) -> _serde::__private::fmt::Result { _serde::__private::Formatter::write_str(__formatter, "variant identifier") }
                fn visit_u64<__E>(self, __value: u64) -> _serde::__private::Result<Self::Value, __E> where __E: _serde::de::Error, {
                    match __value {
                        0u64 => _serde::__private::Ok(__Field::__field0),
                        1u64 => _serde::__private::Ok(__Field::__field2),
                        2u64 => _serde::__private::Ok(__Field::__field3),
                        _ => _serde::__private::Err(_serde::de::Error::invalid_value(_serde::de::Unexpected::Unsigned(__value), &"variant index 0 <= i < 3" )),
                    }
                }
// ...

And indeed, when I implement Deserialize by hand changing only those values, the tests pass.

I'd expect that when both Serialize and Deserialize are derived, then serializing and then deserializing a value always gives same value, regardless of the data format.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions