Skip to content

Instantly share code, notes, and snippets.

@andreievg
Created September 26, 2022 07:18
Show Gist options
  • Save andreievg/5338a3694e15e9b032132551474d3f92 to your computer and use it in GitHub Desktop.
Save andreievg/5338a3694e15e9b032132551474d3f92 to your computer and use it in GitHub Desktop.
Rust serde for enum with unknown value in associated string variant
use serde::{Deserialize, Deserializer, Serialize, Serializer};
const FROM: &'static str = r#"[{"value":"unknown"},{"value": "one"}]"#;
#[derive(Serialize, Deserialize, Debug)]
#[serde(rename_all = "snake_case")]
pub enum To {
One,
Two,
Three,
Four,
Five,
Other(String),
}
#[derive(Serialize, Deserialize, Debug)]
struct Check {
#[serde(deserialize_with = "check_enum_de")]
#[serde(serialize_with = "check_enum_se")]
value: To,
}
pub fn check_enum_de<'de, D: Deserializer<'de>>(d: D) -> Result<To, D::Error> {
let as_string = String::deserialize(d)?;
serde_json::from_str(&format!(r#""{}""#, &as_string)).or(Ok(To::Other(as_string)))
}
pub fn check_enum_se<S: Serializer>(value: &To, s: S) -> Result<S::Ok, S::Error> {
if let To::Other(string) = value {
string.serialize(s)
} else {
value.serialize(s)
}
}
fn main() {
let result: Vec<Check> = serde_json::from_str(FROM).unwrap();
println!("{result:?} - {}", serde_json::to_string(&result).unwrap());
// [Check { value: Other("unknown") }, Check { value: One }] - [{"value":"unknown"},{"value":"one"}]
}
@andreievg
Copy link
Author

Thanks to jonasbb and bruh![moment] from rust discord, a slight imrovement

pub fn check_enum_de<'de, D: Deserializer<'de>>(d: D) -> Result<To, D::Error> {
    let as_string = String::deserialize(d)?;
    let str_d: StrDeserializer<D::Error> = as_string.as_str().into_deserializer();
    To::deserialize(str_d).or(Ok(To::Other(as_string)))
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment