ipld / ipld/rust-ipld-core

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

Open
#19 10 comments 0 reactions 0 assignees View on GitHub
Dominant language
Rust
Stars
34
Forks
10
PR merge metrics
No merged PRs in 30d

Description

Similar to the issue previously reported on https://github.com/ipld/serde_ipld_dagcbor/pull/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.

```rust
#[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.

- https://github.com/serde-rs/json/issues/740
- https://github.com/serde-rs/serde/issues/1682

However, we can work around this problem by changing `Ipld::Integer` to have `i64` instead of `i128`.
my experimental branch:
https://github.com/sugyan/rust-ipld-core/commit/539530d6d9f20e9e34143d9a9d8f92375bbb0bf6

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`](https://github.com/sugyan/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...

Contributor guide

No contributing guide indexed for this repository

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.