msgpack-rust icon indicating copy to clipboard operation
msgpack-rust copied to clipboard

Can't handle #[serde(tag = "someKey")] for structure while Deserialization

Open harshkumar314e opened this issue 1 year ago • 5 comments

use rmp_serde::Serializer;
use serde::Serialize;

extern crate rmp_serde;
extern crate serde;
#[macro_use]
extern crate serde_derive;

#[derive(Debug, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
struct  A {
    b: B,
}

#[derive(Debug, Serialize, Deserialize)]
#[serde(tag = "kind", content = "data")]
#[serde(rename_all = "snake_case")]
pub enum B {
    First(i32),
    Second(Messagedata)
}

#[derive(Debug, Serialize, Deserialize)]
#[serde(tag = "someKey")]
pub struct Messagedata {
    status: String,
    message: String,
}

fn main() {
    let a = A {
        b: B::Second (Messagedata { status: "Failure".to_string(), message: "You are not getting the things".to_string() }),
    };
    //SERDE
    let string_data = serde_json::to_string(&a).unwrap();
    println!("data: {:?}", string_data);
    let data = serde_json::from_str::<A>(&string_data).unwrap();
    println!("A: {:?}", data);
    println!("-------------------------------------------------------------------------------");

    //MESSAGEPACK
    let mut buf = Vec::new();
    a.serialize(&mut Serializer::new(&mut buf)).unwrap();
    // println!("a: {:?}", buf);
    let a = rmp_serde::from_slice::<A>(&buf).unwrap();
    println!("a: {:?}", a);
}

Here is error I am getting:

data: "{\"b\":{\"kind\":\"second\",\"data\":{\"someKey\":\"Messagedata\",\"status\":\"Failure\",\"message\":\"You are not getting the things\"}}}"
A: A { b: Second(Messagedata { status: "Failure", message: "You are not getting the things" }) }
-------------------------------------------------------------------------------
thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: LengthMismatch(2)', src/main.rs:45:46
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

There is no problem with serializing and deserializing with serde. With rmp_serde there is no problem in serializing a struct with a given tag but while deserializing it is not able to take tag provided as key and giving length error.

harshkumar314e avatar Oct 18 '22 07:10 harshkumar314e

Default encoding doesn't keep field names, so it's unable to know which field was the tag field. If you use .with_struct_map() option it works.

kornelski avatar Oct 20 '22 12:10 kornelski

Here is a more minimalist reproduction of this issue - https://github.com/e-ivkov/rmp-bug-repro

I understand that this is not directly a bug, but I would call it an interface inconsistency. It is natural to expect, that if something serialized successfully, it will also de-serialize back. All other serde libraries behave like that.

I would suggest to always use named serialization in rmp_serde, otherwise it simply does not map to serde interface.

e-ivkov avatar Jun 09 '23 11:06 e-ivkov

It looks like there are hard trade offs here, as some people want the efficient representation.

https://github.com/3Hren/msgpack-rust/issues/319

kornelski avatar Jun 10 '23 19:06 kornelski

Just seconding the view that the interface inconsistency is actually broken. Anything that can be serialized should successfully deserialize, and vice-versa. I'm all for stripping names unless opted-in, but that doesn't justify self-inconsistent code.

Does this need a from_slice_named() so that it has to be explicit on both sides? The current behavior is just straight broken.

shimaowo avatar Jul 05 '23 22:07 shimaowo

Serde doesn't tell the serialiser about existence of any extra options, so at serialisation time there's no way to know if the name is going to be necessary to deserialise or not.

So unfortunately it's up to the user to choose named serialisation if they rely on it.

kornelski avatar Jul 06 '23 00:07 kornelski