Rust将u32的Vec反序列化为enum的Vec



我正在寻找一种很好的方法来反序列化u32VecenumVec。我接收到的json对象是这样的:

{
"Account": "r...",
"Flags": 20,
...
}

我试图将其反序列化成如下所示的struct:

#[skip_serializing_none]
#[derive(Debug, Serialize, Deserialize)]
#[serde(rename_all(serialize = "PascalCase", deserialize = "snake_case"))]
pub struct Foo<'a> {
account: &'a str,
flags: Option<Vec<FooFlag>>
}

FooFlag看起来像这样:

#[derive(Debug, Eq, PartialEq, Clone, Serialize, Deserialize, Display, AsRefStr)]
pub enum FooFlag {
Example1 = 5,
Example2 = 15,
...
}

现在,在我收到json之后,我想从u32Flags值中导出Vec<FooFlag>。所以在这个例子中,它应该是vec![FooFlag::Example1, FooFlag::Example2](5 + 15 = 20)。我如何决定这两个枚举现在不重要。我想有一个反序列化函数,我可以使用多个结构,如Foo。我知道有像serde_repr这样的箱子用于c类枚举,但我没有设法以通用的方式把它放在一起。


到目前为止,我已经写了一个mod:

mod flag_conversion {
use alloc::vec::Vec;
use serde::{Deserializer, Serializer, Deserialize};
fn serialize<'a, T, S>(flags: &'a Option<Vec<T>>, s: S) -> Result<S::Ok, S::Error>
where
T: Into<u32>,
S: Serializer,
{
s.serialize_option(
{
if let Some(flags) = &flags {
let transaction_flags: Vec<u32> = flags.into_iter().map(|&flag| {
let f = flag;
let n = f.into();
n
}).collect();
transaction_flags.iter().sum::<u32>()
} else {
0
}
}
)
}
fn deserialize<'de, D>(d: D) -> Result<D::Ok, D::Error>
where
D: Deserializer<'de>,
{
let specified_flags = u32::deserialize(d).unwrap();
d.deserialize_u32(
{
if specified_flags == 0 {
None
} else {
todo!()  // convert to `Vec` of `...Flag` enum
}
}
)
}
}

所以我可以像这样使用Foo结构中的模块:

#[skip_serializing_none]
#[derive(Debug, Serialize, Deserialize)]
#[serde(rename_all(serialize = "PascalCase", deserialize = "snake_case"))]
pub struct Foo<'a> {
account: &'a str,
#[serde(with = "flag_conversion")]
flags: Option<Vec<FooFlag>>
}

我想你离成功已经很近了。

关键是将#[serde(with="some_module")]属性添加到flags字段。您需要在该模块中实现Option<Vec<FooFlag>>的序列化/反序列化。(你可以从FooFlag结构体中删除Serialize/Deserialize)

我不确定您想要如何将int型转换为标志,所以我硬编码了这部分代码。我通常会用2的幂来表示你没有做的标记…

use serde::Deserializer;
use serde::Serializer;
use serde::{Deserialize, Serialize}; // 1.0.147
use serde_json; // 1.0.87
use std::fmt::Display;
#[derive(Debug, Serialize, Deserialize)]
#[serde(rename_all(serialize = "PascalCase", deserialize = "PascalCase"))]
pub struct Foo<'a> {
account: &'a str,
#[serde(with = "foo_flag_serde")]
flags: Option<Vec<FooFlag>>,
}
#[derive(Debug, Eq, PartialEq, Clone, Serialize, Deserialize)]
pub enum FooFlag {
Example1 = 5,
Example2 = 15,
}
impl FooFlag {
pub fn from_u32(d: u32) -> Vec<FooFlag> {
vec![FooFlag::Example1, FooFlag::Example2]
}
pub fn to_u32(v: &[FooFlag]) -> u32 {
123
}
}
pub mod foo_flag_serde {
use super::*;
pub fn serialize<S>(flags: &Option<Vec<FooFlag>>, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
let v: Option<u32> = flags.as_ref().map(|f| FooFlag::to_u32(&f));
v.serialize(serializer)
}
pub fn deserialize<'de, D>(deserializer: D) -> Result<Option<Vec<FooFlag>>, D::Error>
where
D: Deserializer<'de>,
{
let v: Option<u32> = Option::deserialize(deserializer)?;
Ok(v.map(FooFlag::from_u32))
}
}
pub fn main() {
let data = r#"{"Account": "some_account","Flags": 20}"#;
let deserialized: Foo = serde_json::from_str(&data).unwrap();
println!("deserialized = {:?}", deserialized);
let serialized = serde_json::to_string(&deserialized).unwrap();
println!("serialized = {:?}", serialized);
}

在生锈的操场上工作

最新更新