Integer is not parsed as float in untagged enum
Thanks to https://github.com/3Hren/msgpack-rust/pull/204, it is possible to parse integers as floats. However, this does not seem to work if the parsed type is nested inside an untagged enum.
For this MessagePack data:
{b'heartbeat-interval': 1}
and this code:
use serde::{Deserialize};
#[derive(Deserialize)]
#[serde(rename_all = "kebab-case")]
pub struct MessageFloat {
pub heartbeat_interval: f64,
}
#[derive(Deserialize)]
#[serde(rename_all = "kebab-case")]
pub struct MessageInt {
pub heartbeat_interval: u64,
}
#[derive(Deserialize)]
#[serde(untagged)]
pub enum MessageWrapper<T> {
Message(T),
}
fn main() {
let data = std::fs::read("data.bin").unwrap();
// parsing message is fine if the type is exact
let msg: MessageInt = rmp_serde::from_slice(&data).unwrap();
// parsing message is fine if the type is not exact
let msg: MessageFloat = rmp_serde::from_slice(&data).unwrap();
// parsing nested message is fine if the type is exact
let msg: MessageWrapper<MessageInt> = rmp_serde::from_slice(&data).unwrap();
// parsing nested message fails if the type is not exact
let msg: MessageWrapper<MessageFloat> = rmp_serde::from_slice(&data).unwrap();
}
all parses work except the last one.
If you consider this to be a bug, let me know if I can help fixing this (point me to some API/file where I could start).
I have prepared a reproduction repository here:
https://github.com/Kobzol/msgpack-nested-float-int
The msgpack binary is in the root of the repository (data.bin).
It'd be great if you could help with this. Have a look at https://github.com/3Hren/msgpack-rust/blob/3f25c4d26434f3e4fccc25dfcea38a72ecba812b/rmp-serde/src/decode.rs
Perhaps here? https://github.com/3Hren/msgpack-rust/blob/3f25c4d26434f3e4fccc25dfcea38a72ecba812b/rmp-serde/src/decode.rs#L616
or maybe it need special case instead of forward_to_deserialize_any
So the difference seems to be that if the struct is deserialized directly, it calls deserialize_struct, which forwards to deserialize_f64, which can parse integers. But if there's an untagged enum, serde instead forwards to deserialize_any, which just parses a Map<str, u8>, returns that to serde and it fails because it expects Map<str, f64>.
I'm not sure how to work around this. It seems to be possible, because the same thing works in serde_json, however I checked it out and it seems to do number parsing in a different way than rmp.