-
Notifications
You must be signed in to change notification settings - Fork 745
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Default variant for an internally tagged enum #1221
Comments
#[macro_use]
extern crate serde_derive;
extern crate serde;
extern crate serde_json;
use serde::de::{self, Deserialize, Deserializer};
use serde_json::Value;
#[derive(Debug)]
enum ConnectRequest {
Unspecified(UnspecifiedSecurity),
Wpa2(Wpa2Security),
}
#[derive(Deserialize, Debug)]
struct UnspecifiedSecurity {
ssid: String,
psk: Option<String>,
}
#[derive(Deserialize, Debug)]
struct Wpa2Security {
ssid: String,
psk: String,
}
impl<'de> Deserialize<'de> for ConnectRequest {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
#[derive(Deserialize)]
#[serde(field_identifier, rename_all = "lowercase")]
enum Tag {
Wpa2,
Other(String),
}
let v = Value::deserialize(deserializer)?;
match Option::deserialize(&v["security"]).map_err(de::Error::custom)? {
Some(Tag::Wpa2) => {
let inner = Wpa2Security::deserialize(v).map_err(de::Error::custom)?;
Ok(ConnectRequest::Wpa2(inner))
}
None => {
let inner = UnspecifiedSecurity::deserialize(v).map_err(de::Error::custom)?;
Ok(ConnectRequest::Unspecified(inner))
}
Some(Tag::Other(other)) => {
const VARIANTS: &[&str] = &["wpa2"];
Err(de::Error::unknown_variant(&other, VARIANTS))
}
}
}
}
fn main() {
let present = r#"{"ssid": "foo", "psk": "bar", "security": "wpa2"}"#;
println!("{:?}", serde_json::from_str::<ConnectRequest>(&present).unwrap());
let missing = r#"{"ssid": "foo", "psk": "bar"}"#;
println!("{:?}", serde_json::from_str::<ConnectRequest>(&missing).unwrap());
let unknown = r#"{"ssid": "foo", "psk": "bar", "security": "unrecognized"}"#;
println!("{}", serde_json::from_str::<ConnectRequest>(&unknown).unwrap_err());
} |
I'm currently staring down a situation just like what's described above but my enum may have as many as 73 variants. Deserializing it is also showing up in my profile, so I'm a bit bothered by the bookkeeping of the approach you've suggested above as well as what looks like a possible performance penalty from deserializing twice (I'd like to measure but I don't have an alternate approach). Is there anything more to your simple explanation above? Do you plan on supporting a |
The trouble with internally tagged enums is that in general you may receive many fields of data before the tag, and those fields can only be meaningfully interpreted after knowing the tag. So it seems inherent that you would need to do two passes to deserialize fully. If your data always contains the tag field first, you may be able to do better. Or if the variants have many fields in common then you may be able to handle those fields better. |
Deserialization for invoke transactions is now done by hand, since the `version` property is optional. Serde doesn't support deriving deserialize for internally tagged enums where the tag property may be missing: serde-rs/serde#1221 Unfortunately `InvokeTransaction::deserialize` now makes multiple deserialization passes on the data...
Deserialization for invoke transactions is now done by hand, since the `version` property is optional. Serde doesn't support deriving deserialize for internally tagged enums where the tag property may be missing: serde-rs/serde#1221 Unfortunately `InvokeTransaction::deserialize` now makes multiple deserialization passes on the data...
Deserialization for invoke transactions is now done by hand, since the `version` property is optional. Serde doesn't support deriving deserialize for internally tagged enums where the tag property may be missing: serde-rs/serde#1221 Unfortunately `InvokeTransaction::deserialize` now makes multiple deserialization passes on the data...
Deserialization for invoke transactions is now done by hand, since the `version` property is optional. Serde doesn't support deriving deserialize for internally tagged enums where the tag property may be missing: serde-rs/serde#1221 Unfortunately `InvokeTransaction::deserialize` now makes multiple deserialization passes on the data...
Deserialization for invoke transactions is now done by hand, since the `version` property is optional. Serde doesn't support deriving deserialize for internally tagged enums where the tag property may be missing: serde-rs/serde#1221 Unfortunately `InvokeTransaction::deserialize` now makes multiple deserialization passes on the data...
Deserialization for invoke transactions is now done by hand, since the `version` property is optional. Serde doesn't support deriving deserialize for internally tagged enums where the tag property may be missing: serde-rs/serde#1221 Unfortunately `InvokeTransaction::deserialize` now makes multiple deserialization passes on the data...
Deserialization for invoke transactions is now done by hand, since the `version` property is optional. Serde doesn't support deriving deserialize for internally tagged enums where the tag property may be missing: serde-rs/serde#1221 Unfortunately `InvokeTransaction::deserialize` now makes multiple deserialization passes on the data...
Deserialization for invoke transactions is now done by hand, since the `version` property is optional. Serde doesn't support deriving deserialize for internally tagged enums where the tag property may be missing: serde-rs/serde#1221 Unfortunately `InvokeTransaction::deserialize` now makes multiple deserialization passes on the data...
Question from IRC:
The text was updated successfully, but these errors were encountered: