6

I have the JSON roughly like this:

[
  {
     "commonA": 1,
     "commonB": 2,
     "type": "Foo",
     "fooSpecificA": 3,
     "fooSpecificB": 4
  },
  {
     "commonA": 5,
     "commonB": 6,
     "type": "Bar",
     "barSpecificA": 7,
     "barSpecificB": 8
  },
  ...

In other words I have internally tagged objects, but some of the fields are common to every type. I'd like to deserialise it to something like this:

struct Entry {
  commonA: i64,
  commonB: i64,
  variant: EntryVariant,
}

enum EntryVariant {
  Foo(FooSpecific),
  Bar(BarSpecific),
}

struct FooSpecific {
  fooSpecificA: i64,
  fooSpecificB: i64,
}

struct BarSpecific {
  barSpecificA: i64,
  barSpecificB: i64,
}

Is that possible with Serde?

Timmmm
  • 88,195
  • 71
  • 364
  • 509
  • By the way, idiomatic Rust uses `snake_case` for variables, methods, macros, fields and modules; `UpperCamelCase` for types and enum variants; and `SCREAMING_SNAKE_CASE` for statics and constants. – Shepmaster Apr 14 '20 at 13:22
  • Yeah I know but a load of `#[rename_all()]` attributes would have made the example less clear. – Timmmm Apr 14 '20 at 14:28
  • 2
    You could rename the corresponding JSON, considering that you made it up to start with. – Shepmaster Apr 14 '20 at 14:30
  • True. Also not very important here! – Timmmm Apr 14 '20 at 14:31

1 Answers1

15

Combine internally tagged unions with struct flattening.

use serde::{Serialize, Deserialize};

#[derive(Debug, Serialize, Deserialize)]
struct Entry {
    #[serde(rename = "commonA")]
    common_a: i64,
    #[serde(rename = "commonB")]
    common_b: i64,
    #[serde(flatten)]
    variant: EntryVariant,
}

#[derive(Debug, Serialize, Deserialize)]
#[serde(tag = "type")]
enum EntryVariant {
    Foo(FooSpecific),
    Bar(BarSpecific),
}

#[derive(Debug, Serialize, Deserialize)]
struct FooSpecific {
    #[serde(rename = "fooSpecificA")]
    foo_specific_a: i64,
    #[serde(rename = "fooSpecificB")]
    foo_specific_b: i64,
}

#[derive(Debug, Serialize, Deserialize)]
struct BarSpecific {
    #[serde(rename = "barSpecificA")]
    bar_specific_a: i64,
    #[serde(rename = "barSpecificB")]
    bar_specific_b: i64,
}

Playground

E_net4
  • 27,810
  • 13
  • 101
  • 139