我有一个接受JSON有效负载的Rust Web服务端点.有效负载包含嵌套的枚举 struct ,类似于:
#[derive(Serialize, Deserialize, Debug, PartialEq)]
#[serde(rename_all = "snake_case")]
enum InnerEnum {
ValueA(String),
ValueB
}
#[derive(Serialize, Deserialize, Debug, PartialEq)]
#[serde(rename_all = "snake_case")]
enum OuterEnum {
Wrapped(InnerEnum),
Other
}
#[derive(Serialize, Deserialize, Debug, PartialEq)]
struct Message {
message: OuterEnum
}
序列化是一块蛋糕,对于像{ "message": { "wrapped": { "value_a": "foo" } } }
这样的有效负载,序列化效果很好,但是该API的旧版本没有对蛇的情况进行重命名,也没有用OuterEnum
包装InnerEnum
,所以较老的客户端倾向于使用像{ "message": { "ValueA": "foo" } }
这样的有效负载进行调用
我希望通过允许将任一有效负载反序列化为当前 struct 来支持那些旧的客户端,而无需公开API的多个版本或维护端点的多个版本.
到目前为止,我已经try 在message
字段上使用#[serde(deserialize_with = "...")]
来调用如下函数
fn enum_deserializer<'de, D>(de: D) -> Result<OuterEnum, D::Error> where D: serde::Deserializer<'de> {
if let Ok(inner) = InnerEnum::deserialize(de) {
Ok(OuterEnum::Wrapped(inner))
} else {
OuterEnum::deserialize(de)
}
}
但是deserialize
调用使用反序列化程序,所以我不能两次调用它.我曾try 为OuterEnum
构建一个定制的反序列化程序,但我不知道如何以通用的方式将字段反序列化为映射,或者在反序列化之前查看枚举标记.我甚至try 在OuterEnum::Other
上使用#[serde(other)]
作为备用,但显然这既要求枚举变量是单元类型,也要求输入json字段是简单的字符串而不是映射/数组/等等.有什么合理的方法可以实现这一点吗?