#serde-json #enums #serialization #variant #tagged #complex #untagged

serde_sated

为 serde 实现相邻标记枚举反序列化(带有未标记的变体)

4 个版本

0.1.3 2024年5月6日
0.1.2 2024年4月22日
0.1.1 2024年4月20日
0.1.0 2024年4月20日

编码 中排名第 1091

Download history 264/week @ 2024-04-17 43/week @ 2024-04-24 125/week @ 2024-05-01 24/week @ 2024-05-08 2/week @ 2024-05-15 4/week @ 2024-05-22 2/week @ 2024-05-29 1/week @ 2024-07-03

每月下载量 168

MIT 许可协议

14KB
190 行(不包括注释)

serde-sated(相邻标记枚举反序列化[带未标记变体])

此包提供衍生宏,用于在反序列化相邻标记枚举变体时覆盖 serde::Deserialize 的默认行为,并使用未标记值作为后备。

默认 Deserialize 有什么问题?

看看下面的代码

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);
}

这将打印

Resource: Unknown(
    Object {
        "resource": Object {
            "a": Number(2000),
        },
        "resourceType": String("Complex"),
    },
)

如您所见,Complex 变体中缺少字段 "b" 导致 serde 默认到未标记变体。

解决方案

这可能不是预期的行为 - 此 crate 允许更改此行为,而不是默认到未标记变体,它将返回正确的错误。

让我们将 ResourceStruct derive 属性更改为使用 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);
}

现在结果将是

Resource: Err(
    Error("missing field `b`", line: 0, column: 0),
)

依赖关系

~245–670KB
~16K SLoC