I am deserializing a bunch of documents into an enum. My documents have a field that can be used to pick the correct variant. I want the following three points to happen:
Other variant.I have tried the few following solutions but didn't manage to achieve all three points:
Just #[serde(other)]
#[derive(Deserialize)]
#[serde(tag = "type")]
enum Document {
Config {
path: PathBuf,
},
#[serde(other)]
Other,
}
With this, the content of the document is not deserialized if it doesn't match Config.
Untagged enum:
#[derive(Deserialize)]
#[serde(untagged)]
enum Document {
Config {
type: String,
path: PathBuf,
},
Other(serde_yaml::Value),
}
With this one I get the content of documents that don't match as a Value. Unfortunately if somebody write a file of type: Config with a typo like say paht: /etc/, it will result in being deserialized as Other instead of panicking.
Finally, with a nested enum:
#[derive(Deserialize)]
#[serde(untagged)]
enum Document {
Config(Config),
Other(serde_yaml::Value),
}
#[derive(Deserialize)]
#[serde(tag = "type")]
enum Config {
path: PathBuf,
}
This seems to behave exactly like the previous case (simple untagged enum).
How can I get both Other deserialized as a serde_yaml::Value when nothing matches and panicking if the tag matches but not the content of the structure?
This is (now? it isn't clear to me since when) implemented in serde. This is named #[serde(untagged)]:
#[derive(Deserialize)]
#[serde(tag = "type")]
enum Document {
Config {
path: PathBuf,
},
#[serde(untagged)]
Other {},
}
The {} is necessary, otherwise serde assumes there can't be properties in this object.
If you want to capture the data, you can do that too:
#[derive(Deserialize)]
#[serde(tag = "type")]
enum Document {
Config {
path: PathBuf,
},
#[serde(untagged)]
Other(serde_yaml::Value),
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With