Serde polymorphic deserialization

I have a toml configuration that has a retries field. This can be none, an integer or inf/infinite. Currently I require that the user specify this as a string in all cases, and there's a piece of code that tries to convert the string into a number:

#[derive(Deserialize)]
struct Config {
  retries: Option<String>
}

What I'd like instead:

#[derive(Deserialize)]
enum Retries {
  None,
  Num(usize),
  Infinite
}

#[derive(Deserialize)]
struct Config {
  retries: Option<Retries>
}

While I've used serde quite a bit, it has been very superficial. I basically only know about simple use-cases of #[derive(Deserialize)]. How can the enum Retries be implemented to support the Config use-case? Will implementing Deserialize manually allow this? Is there a shortcut? deserialize_with? Is there some way to tag the Retries enum with magic serde pixie dust to make it work the way I want?

Try this:

#[derive(Deserialize)]
#[serde(untagged)]
enum Retries {
  Num(usize),
  Infinite(InfiniteRetries)
}

#[derive(Deserialize)]
enum InfiniteRetries {
  #[serde(rename = "inf/infinite")]
  InfiniteRetries
}

#[derive(Deserialize)]
struct Config {
  retries: Option<Retries>
}
3 Likes

Thank you -- sticking the #[serde(rename = "inf/infinite")] on the InfiniteRetries variant of the InfiniteRetries enum, rather than within the Retries, makes it work.

I'm a little impressed by the amount of things one can do without manually implementing Deserialize.

Got it! I have edited the snippet on my reply :smiley:.

You can also only mark the Num variant as untagged and avoid the InfiniteRetries enum:

#[derive(Deserialize, Debug, PartialEq)]
enum Retries {
    #[serde(rename = "inf")]
    Infinite,
    #[serde(untagged)]
    Num(usize),
}

#[derive(Deserialize, Debug)]
struct Config {
    retries: Option<Retries>,
}

Playground.

5 Likes

Ah, interesting! I had not seen that untagged was also in the list of variant attributes.

First time I saw it, too. But apparently the attribute has been around for over a year now.

3 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.