Skip to content

serde deserializer fails deserialize to untagged enums which has integer(i128) values #19

@sugyan

Description

@sugyan

Similar to the issue previously reported on ipld/serde_ipld_dagcbor#21, when trying to deserialize to an Internally tagged or Untagged enum, it seems that the serde internally calls deserialize_any, in which case i128 is not supported.

The following test fails.

#[test]
fn ipld_deserializer_integer_untagged() {
    #[derive(Clone, Debug, Deserialize, PartialEq)]
    #[serde(untagged)]
    enum MyEnum {
        Foo { value: bool },
        Bar { value: i32 },
    }

    // foo: OK
    {
        let ipld = Ipld::Map(BTreeMap::from([("value".into(), Ipld::Bool(true))]));
        match MyEnum::deserialize(ipld) {
            Ok(deserialized) => {
                assert_eq!(deserialized, MyEnum::Foo { value: true });
            }
            Err(e) => {
                panic!("{e:?}");
            }
        }
    }
    // bar: FAIL
    {
        let ipld = Ipld::Map(BTreeMap::from([("value".into(), Ipld::Integer(42))]));
        match MyEnum::deserialize(ipld) {
            Ok(deserialized) => {
                assert_eq!(deserialized, MyEnum::Bar { value: 42 });
            }
            Err(e) => {
                panic!("{e:?}");
            }
        }
    }
}
SerdeError("invalid type: integer `42` as i128, expected any value")

I think this is a serde's unresolved issue, so it may not be the responsibility of this library.

However, we can work around this problem by changing Ipld::Integer to have i64 instead of i128.
my experimental branch:
sugyan@539530d

Since the IPLD specification requires minimum support for values up to 2^53, the change to i64 is destructive but still meets the specification.
https://ipld.io/design/tricky-choices/numeric-domain/#integers

Is it possible to change it so that, for example, "if a certain feature flag is specified, the Ipld::Integer of i64 is used"?

My background is that I am developing a library atrium, and I would like to provide a function to hold unknown values received from the server as an Ipld and deserialize them to an arbitrary type on the user side. However, I am having trouble converting from Ipld to other types due to this problem...

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