反序列化可能是字符串数组或常量字符串的值?
Deserialize value that may be an array of strings or a constant string?
我正在使用 Serde 反序列化一些 JSON。我遇到的问题通常是一个字符串数组,但也可以是常量字符串 "all"
。在 JSON-schema 中表示如下:
{
"oneOf": [
{
"const": "all"
},
{
"type": "array",
"items": {
"type": "string"
}
}
]
}
我想将它序列化到这个枚举中:
enum MyList {
List(Vec<String>),
All
}
这里有几个例子:
["foo", "bar"] // Should be MyList::List
"all" // Should be MyList::All
"foo" // Should be an error!
问题是,如何使用 serde 反序列化此枚举? None 的 container attributes or variant attributes 似乎有帮助。如果需要,我可能会更改枚举的设计。但是,JSON 的结构超出了我的控制范围。
untagged enum representation and deserialize_with
variant attribute:
的组合是可能的
use serde::{Deserialize, Deserializer};
#[derive(Debug, Deserialize)]
// This annotation "flattens" the enum, allowing one to treat a list of strings
// directly as a List variant, without extra annotations.
// Serde will attempt to deserialize input as each variant in order,
// returning an error if no one matches.
#[serde(untagged)]
enum MyList {
// This annotation delegates deserialization of this variant to own code,
// since otherwise Serde wouldn't know what to do with the string.
#[serde(deserialize_with = "all")]
All,
// This variant is deserialized as usual.
List(Vec<String>),
}
// A custom deserialization function, referred to by `deserialize_with`.
// (reference: https://github.com/serde-rs/serde/issues/1158)
fn all<'de, D>(deserializer: D) -> Result<(), D::Error>
where
D: Deserializer<'de>,
{
#[derive(Deserialize)]
// This enum is, by default, "externally tagged";
// but, since it consists only of a single unit variant,
// it means that it can be deserialized only from
// the corresponding constant string - and that's exactly what we need
enum Helper {
#[serde(rename = "all")]
Variant,
}
// We're not interested in the deserialized value (we know what it is),
// so we can simply map it to (), as required by signature
Helper::deserialize(deserializer).map(|_| ())
}
fn main() {
// Trying to parse an array with both variants...
let json = r#"["all", ["a", "b", "c"]]"#;
let lists: Vec<MyList> = serde_json::from_str(json).expect("cannot parse");
// ...we can see that it is indeed parsed correctly...
println!("{:?}", lists);
// ...and any unexpected string results in an error
serde_json::from_str::<MyList>(r#""foo""#).unwrap_err();
}
我正在使用 Serde 反序列化一些 JSON。我遇到的问题通常是一个字符串数组,但也可以是常量字符串 "all"
。在 JSON-schema 中表示如下:
{
"oneOf": [
{
"const": "all"
},
{
"type": "array",
"items": {
"type": "string"
}
}
]
}
我想将它序列化到这个枚举中:
enum MyList {
List(Vec<String>),
All
}
这里有几个例子:
["foo", "bar"] // Should be MyList::List
"all" // Should be MyList::All
"foo" // Should be an error!
问题是,如何使用 serde 反序列化此枚举? None 的 container attributes or variant attributes 似乎有帮助。如果需要,我可能会更改枚举的设计。但是,JSON 的结构超出了我的控制范围。
untagged enum representation and deserialize_with
variant attribute:
use serde::{Deserialize, Deserializer};
#[derive(Debug, Deserialize)]
// This annotation "flattens" the enum, allowing one to treat a list of strings
// directly as a List variant, without extra annotations.
// Serde will attempt to deserialize input as each variant in order,
// returning an error if no one matches.
#[serde(untagged)]
enum MyList {
// This annotation delegates deserialization of this variant to own code,
// since otherwise Serde wouldn't know what to do with the string.
#[serde(deserialize_with = "all")]
All,
// This variant is deserialized as usual.
List(Vec<String>),
}
// A custom deserialization function, referred to by `deserialize_with`.
// (reference: https://github.com/serde-rs/serde/issues/1158)
fn all<'de, D>(deserializer: D) -> Result<(), D::Error>
where
D: Deserializer<'de>,
{
#[derive(Deserialize)]
// This enum is, by default, "externally tagged";
// but, since it consists only of a single unit variant,
// it means that it can be deserialized only from
// the corresponding constant string - and that's exactly what we need
enum Helper {
#[serde(rename = "all")]
Variant,
}
// We're not interested in the deserialized value (we know what it is),
// so we can simply map it to (), as required by signature
Helper::deserialize(deserializer).map(|_| ())
}
fn main() {
// Trying to parse an array with both variants...
let json = r#"["all", ["a", "b", "c"]]"#;
let lists: Vec<MyList> = serde_json::from_str(json).expect("cannot parse");
// ...we can see that it is indeed parsed correctly...
println!("{:?}", lists);
// ...and any unexpected string results in an error
serde_json::from_str::<MyList>(r#""foo""#).unwrap_err();
}