4 releases
0.1.3 | May 6, 2024 |
---|---|
0.1.2 | Apr 22, 2024 |
0.1.1 | Apr 20, 2024 |
0.1.0 | Apr 20, 2024 |
#2204 in Encoding
14KB
190 lines
serde-sated (sane adjacently tagged enum deserialization [with untagged variant])
This crate provides a derive macro to override default serde::Deserialize behavior when deserializing adjacently tagged enum variants with fallback untagged value.
What is wrong with default Deserialize?
Take a look at following code:
use serde::{Deserialize, Serialize};
use serde_json::json;
#[derive(Debug, Deserialize, Serialize)]
#[serde(tag = "resourceType", content = "resource")]
pub enum ResourceStruct {
Number(u64),
String(String),
Complex(Complex),
#[serde(untagged)]
Unknown(serde_json::Value),
}
#[derive(Debug, Deserialize, Serialize)]
pub struct Complex {
pub a: u64,
pub b: u64,
}
#[test]
fn deserialize_json() {
let missing_field_b_in_complex_variant = json!({
"resourceType": "Complex",
"resource": {
"a": 2000
}
});
let result = serde_json::from_value::<ResourceStruct>(missing_field_b_in_complex_variant).unwrap();
eprintln!("Resource: {:#?}", result);
}
This will print:
Resource: Unknown(
Object {
"resource": Object {
"a": Number(2000),
},
"resourceType": String("Complex"),
},
)
As you can see, missing field "b" in Complex variant caused serde to default to untagged variant.
Solution
This may or may not be the desired behavior - this crate allows to change that, instead of defaulting to untagged variant it will return the correct error.
Let's change the ResourceStruct derive attribute to use serde_sated::deserialize_enum_with_untagged_as_fallback
use serde::{Deserialize, Serialize};
use serde_json::json;
use serde_sated::deserialize_enum_with_untagged_as_fallback;
#[derive(Debug, deserialize_enum_with_untagged_as_fallback, Serialize)]
#[serde(tag = "resourceType", content = "resource")]
pub enum ResourceStruct {
Number(u64),
String(String),
Complex(Complex),
#[serde(untagged)]
Unknown(serde_json::Value),
}
#[derive(Debug, Deserialize, Serialize)]
pub struct Complex {
pub a: u64,
pub b: u64,
}
#[test]
fn deserialize_json() {
let missing_field_b_in_complex_variant = json!({
"resourceType": "Complex",
"resource": {
"a": 2000
}
});
let result = serde_json::from_value::<ResourceStruct>(missing_field_b_in_complex_variant);
eprintln!("Resource: {:#?}", result);
}
Now the result will be:
Resource: Err(
Error("missing field `b`", line: 0, column: 0),
)
Dependencies
~265–700KB
~17K SLoC