I have a TOML file with lots of strings which are either plain strings (like a
in the below example) or tables with translated strings (like b
):
a = "Hi"
b = { en:"Hello", de:"Hallo" }
I want to deserialize those with Rust+Serde:
use serde::{self, Deserialize};
#[derive(Debug, Deserialize)]
struct MultiLangString {
de: Option<String>,
en: Option<String>,
}
#[derive(Debug, Deserialize)]
enum LangString {
SingleLang(String),
MultiLang(MultiLangString),
}
This does not work and serde returns this error:
Error {
inner: Error {
inner: TomlError {
message: "wanted exactly 1 element, more than 1 element",
raw: None,
keys: ["feature", "title"],
span: None
}
}
}
How do I deserialize such an enum where the variants have different content with Rust+serde?
Working Solution
Serde knows different ways to represent enums, documented here. The example TOML code in the question is an example of the untagged enum representation. Adding #[serde(untagged)]
does the trick:
#[derive(Debug, Deserialize)]
struct MultiLangString {
de: Option<String>,
en: Option<String>,
}
#[derive(Debug, Deserialize)]
#[serde(untagged)] // <-- this works
enum LangString {
SingleLang(String),
MultiLang(MultiLangString),
}
Not Working
Adding #[serde(flatten)]
like so does not work because serde will refuse to recognize the flatten
attribute on an enum
:
#[derive(Debug, Deserialize)]
struct MultiLangString {
de: Option<String>,
en: Option<String>,
}
#[derive(Debug, Deserialize)]
enum LangString {
SingleLang(String),
#[serde(flatten)] // <-- does not compile
MultiLang(MultiLangString),
}