I use Serde to deserialize a custom configuration file written in YAML. The file can contain definitions of various kinds that I represent as internally tagged enums:
OfKindFoo:
kind: Foo
bar: bar;
baz: baz;
OfKindQux:
kind: Qux
quux: qux;
I represent it in Rust 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 user to be able to omit the kind
field completely, and when it is omitted Serde should default to deserializing it as Foo
.
I started to implement Deserialize
on Definition
. I'm trying to deserialize it as a map and look for the kind
key and return a respective enum variant based on this key and whether it is present.
I need to somehow "forward" the 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" the map into a deserializer or otherwise get a deserializer that "starts" on that particular map?
I cannot use #[serde(other)]
because it returns Err
for a missing tag. Even if it didn't, the documentation states that other
can only be applied to a "unit variant", a variant not containing any data.