Serde tuple serialization with single element is a sequence why?

    #[test]
    fn test_msg_serde2() {
        use serde::{Deserialize, Serialize};
        #[derive(Serialize, Deserialize, Debug)]
        struct WhyAmIaSequence<T>(#[serde(skip)] u8, T);
        let msg_inp = WhyAmIaSequence(1, "hello");
        let json_out = serde_json::to_string(&msg_inp).unwrap();
        println!("json_out: {}", json_out); // json_out: ["hello"]

        #[derive(Serialize, Deserialize, Debug)]
        struct HoweverIAmNotSequence<T>(T);
        let msg_inp = HoweverIAmNotSequence("hello");
        let json_out = serde_json::to_string(&msg_inp).unwrap();
        println!("json_out: {}", json_out); // json_out: "hello"
    }

Looking at macro expansions, it seems like one gets implemented via Serializer::serialize_newtype_struct and the other via Serializer::serialize_tuple_struct.


Edit:

I’m not sure of the exact motivations. Maybe they want #[serde(skip)] to be consistent with alternatives such as skipping only serialization or only deserialization of the field, or skipping conditionally, in which case it’s probably problematic to avoid the sequence for the json representation.

If you want to work around the issue, one option could be to use #[serde(transparent)]. This is a bit different yet again, as it’s implemented by skipping the struct alltogether and directly calling into the serialization of the single (serialized) field, but at least for JSON serialization, the effect should be the same as the implicit serialize_newtype_struct approach of the HoweverIAmNotSequence struct:

        #[derive(Serialize, Deserialize, Debug)]
        #[serde(transparent)]
        struct WhyAmIaSequence<T>(#[serde(skip)] u8, T);
2 Likes

Your first data structure WhyAmIaSequence is considered to be a tuple struct by Serde's derive macros. This is a syntax thing that doesn't get affect by #[serde(skip)]. The type HoweverIAmNotSequence is a tuple struct with a single field, also known as a New type or Unit struct. They are commonly used to implement new functions or traits on a type where orphan rules would not permit. Syn, the parser used by Serde's derives, detects this as Fields::Unit and judging the intent of the type as a Newtype, Serde delegates to the Serialize or Deserialize implementation of the inner type. Whilst with the tuple struct, it interprets it as a fixed length list of differently typed items

Here is an excerpt from the expanded Serialize implementation of WhyAmIaSequence:

let mut __serde_state =  _serde::Serializer::serialize_tuple_struct(__serializer, "WhyAmIaSequence", 0 + 1)?;
_serde::ser::SerializeTupleStruct::serialize_field(&mut __serde_state, &self.1)?;
_serde::ser::SerializeTupleStruct::end(__serde_state)

And a similar excerpt from HoweverIAmNotSequence:

_serde::Serializer::serialize_newtype_struct(__serializer, "HoweverIAmNotSequence", &self.0)
2 Likes

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.