I have an enum similar to the following:
#[derive(Deserialize)]
enum ExampleEnum {
#[serde(rename = "variant1-rename")]
Variant1,
#[serde(rename = "variant2-rename")]
Variant2,
Other(String),
}
It should deserialize like this:
Serialized | Deserialized |
---|---|
"variant1-rename" |
ExampleEnum::Variant1 |
"variant2-rename" |
ExampleEnum::Variant2 |
"foobar" |
ExampleEnum::Other("foobar") |
With my current code, the first two work as intended, but the last one does not, the program errors saying that it expected either "variant1-rename", "variant2-rename", or "Other".
It seems like the #[serde(other)]
attribute would result in the desired behavior, but it can only be used with internally tagged or adjacently tagged enums.
The (JSON) data I am deserializing has a property that should be deserialized into the enum, so it would look like this:
{
"property": "variant1-rename"
}
Here is my code that solved the problem, based off of Caesar's answer and the Manually implementing Deserialize for a struct page in serde
's documentation.
use serde::{ Deserialize, de };
impl<'de> Deserialize<'de> for ExampleEnum {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
struct ExampleEnumVisitor;
impl<'de> de::Visitor<'de> for ExampleEnumVisitor {
type Value = ExampleEnum;
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
formatter.write_str("`variant1-rename`, `variant2-rename`, or some other string")
}
fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
where
E: de::Error,
{
match v {
"variant1-rename" => Ok(ExampleEnum::Variant1),
"variant2-rename" => Ok(ExampleEnum::Variant2),
_ => Ok(ExampleEnum::Other(v.to_string())),
}
}
}
deserializer.deserialize_identifier(ExampleEnumVisitor)
}
}
If you wish for a shorter solution, use Caesar's. Read the comments under their solution to understand the differences.