Serde: deserialize enum with OPTIONAL internal tag

I use Serde to deserialize a custom configuration file written in yaml. The file can contain definitions of various kinds that I represent as intentally tagged enums, like this:

OfKindFoo:
  kind: Foo
  bar: bar;
  baz: baz;

OfKindQux:
  kind: Qux
  quux: qux;

In Rust, I represent it like this:

#[derive(Deserialize)]
#[serde(tag = "kind")]
enum Definition {
  Foo(Foo),
  Qux(Qux)
}

#[derive(Deserialize)]
struct Foo {
  bar: String,
  baz: String
}

#[derive(Deserialize)]
struct Qux {
  quux: String
}

I want the app user to be able to omit the "kind" field completely, and when it is omitted Serde defaults to deserializing as Foo.

I started to implement custom Deserialize on Definition, I'm trying to deserialize it as map and manually look for "kind" key and return a respective enum variant based on this key and whether it is present. But I need to somehow "forward" deserialization of other map fields to Foo::deserialize or Bar::deserialize, respectively. fn deserialize only takes one argument which is Deserializer. Is there a way to "convert" map into a deserializer or somehow else get a deserializer that "starts" on that particular map? Performance is a non issue.

You can wrap the optional field with Option and add #[serde(default)] to the field. In general anything that implements the Default trait can use serde's default attribute.

This will result in baz containing an empty string:

#[derive(Deserialize)]
struct Foo {
    bar: String,
    #[serde(default)]
    baz: String,
}

This will result in baz being None:

#[derive(Deserialize)]
struct Foo {
    bar: String,
    #[serde(default)]
    baz: Option<String>,
}

Thanks but that's not exactly what I need, I need to be able to omit the tag key for internally tagged enum

You can use #[serde(untagged)] on the enum, and serde will choose the appropriate variant.

Then there's no tag at all, I needed to be able to specify tag but fall back to default when it's omitted. Thanks anyway, I figured it out

Turns out there is IntoDeserializer trait in serde::de that is implemented for HashMap

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.