Is there a way to move serde's enum tag one level above?

Consider this code:

use serde::{Deserialize, Serialize};

#[derive(Debug, Serialize, Deserialize)]
struct MyStruct {
    my_enum: MyEnum,
}

#[derive(Debug, Serialize, Deserialize)]
#[serde(tag = "type")]
#[serde(rename_all = "snake_case")]
enum MyEnum {
    TypeA {
        foo: usize,
    },
    TypeB {
        bar: usize,
    }
}

fn main() {
    let s = MyStruct {
        my_enum: MyEnum::TypeA {
            foo: 42,
        },
    };
    println!("{}", serde_json::to_string_pretty(&s).unwrap());
}

Right now it prints this:

{
  "my_enum": {
    "type": "type_a",
    "foo": 42
  }
}

I want it to print this:

{
  "type": "type_a",
  "my_enum": {
    "foo": 42
  }
}

I was able to achieve this with this code:

use serde::{Deserialize, Serialize};

#[derive(Debug, Serialize, Deserialize)]
struct MyStruct {
    #[serde(flatten)]
    my_enum: MyEnum,
}

#[derive(Debug, Serialize, Deserialize)]
#[serde(tag = "type", content = "my_enum")]
#[serde(rename_all = "snake_case")]
enum MyEnum {
    TypeA {
        foo: usize,
    },
    TypeB {
        bar: usize,
    }
}

fn main() {
    let s = MyStruct {
        my_enum: MyEnum::TypeA {
            foo: 42,
        },
    };
    println!("{}", serde_json::to_string_pretty(&s).unwrap());
}

But it basically radically changes the serialized form of MyEnum, and I want to avoid that. Is there another way to do it, so that MyEnum serialization behaviour remains default?

I don't get it. You want to change how the enum is serialized, yet you want it to remain the same?

Sorry for not being clear. I want to change how the struct is serialized, but now affect the way the enum is serialized

Ah, so you only want to apply those changes when the enum is in the struct? I don't think that is possible; however, you could write a macro that creates two versions of your enum: one with the attributes (that is used only within the struct), and another without. (Throw in From/Into conversions in both directions for ease of use.)

If you don't want to do this, then you'll probably need to implement Serialize manually on the struct, and leave the derived impl of the enum as-is (ie. remove the tagging attributes).

1 Like

I was afraid of this... Thank you! :slight_smile: