如何获取 serde SeqAccess 的内部序列的 SeqAccess 类型?
How do I get a SeqAccess type for an inner sequence of a serde SeqAccess?
我正在编写一个库来解析 json 如下所示的数据:
{"x": [[1, "a"], [2, "b"]]}
即我有一个列表列表的键,其中内部列表可以包含不同的数据类型,但每个内部列表都具有相同的类型序列。内部列表的类型顺序可以根据不同的 json 模式而改变,但会提前知道。
所需的输出类似于:
vec![vec![1,2], vec!["a", "b"]]
(数据包装在不同数据类型的一些适当的枚举中)。
我开始为 Vec<DataTypes>
实现 DeserializeSeed
,下面是一些类似的伪代码。
enum DataTypes {
I32,
I64,
String,
F32,
F64
}
fn visit_seq<S>(self, mut seq: S) -> Result<Self::Value, S::Error>
where
S: SeqAccess<'de>,
{
let types: Vec<DataTypes> = self.0.data;
let out: Vec<Vec<...>>;
while let Some(inner_seq: S) = seq.next_element::<S>()? { // <-- this is the line
for (i, type) in types.enumerate() {
match type {
DataTypes::I32 => out[i].push(inner_seq.next_element::<i32>()?),
DataTypes::I64 => out[i].push(inner_seq.next_element::<i64>()?),
...
}
}
}
}
我的问题是我似乎无法找到一种方法来获取内部列表的 SeqAccess 并且我不想将它们反序列化为 Vec<serde_json::Value>
之类的东西,因为我不想分配附加向量。
请系好安全带,这很啰嗦。
我假设您想反序列化一些 JSON 数据
{"x": [[1, "a"], [2, "b"]]}
一些 Rust 结构
struct X {
x: Vec<Vec<Value>>, // Value is some enum containing string/int/float…
}
一直
- 插入向量时转置内部列表的元素
- 检查内部向量元素是否符合传递给反序列化的某种类型
- 不进行任何临时分配
一开始,您必须意识到要反序列化三种不同的类型:X
、Vec<Vec<Value>>>
和Vec<Value>
。 (Value
本身你不需要,因为你真正想要反序列化的是字符串和整数等等,而不是 Value
本身。)所以,你需要三个反序列化器和三个访问者。
最里面的 Deserialize
有一个对 Vec<Vec<Value>>
的可变引用,并将单个 [1, "a"]
的元素分配给每个 Vec<Value>
.
struct ExtendVecs<'a>(&'a mut Vec<Vec<Value>>, &'a [DataTypes]);
impl<'de, 'a> DeserializeSeed<'de> for ExtendVecs<'a> {
type Value = ();
fn deserialize<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
where
D: Deserializer<'de>,
{
struct ExtendVecVisitor<'a>(&'a mut Vec<Vec<Value>>, &'a [DataTypes]);
impl<'de, 'a> Visitor<'de> for ExtendVecVisitor<'a> {
type Value = ();
fn visit_seq<A>(self, mut seq: A) -> Result<(), A::Error>
where
A: SeqAccess<'de>,
{
for (i, typ) in self.1.iter().enumerate() {
match typ {
// too_short checks for None and turns it into Err("expected more elements")
DataTypes::Stri => self.0[i].push(Value::Stri(too_short(self.1, seq.next_element::<String>())?)),
DataTypes::Numb => self.0[i].push(Value::Numb(too_short(self.1, seq.next_element::<f64>())?)),
}
}
// TODO: check all elements consumed
Ok(())
}
}
deserializer.deserialize_seq(ExtendVecVisitor(self.0, self.1))
}
}
中间的Deserialize
构造了Vec<Vec<Value>>
,让最里面的ExtendVecs
访问了Vec<Vec<Value>>
,让ExtendVecs
看了每一个的 [[…], […]]
:
struct TransposeVecs<'a>(&'a [DataTypes]);
impl<'de, 'a> DeserializeSeed<'de> for TransposeVecs<'a> {
type Value = Vec<Vec<Value>>;
fn deserialize<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
where
D: Deserializer<'de>,
{
struct TransposeVecsVisitor<'a>(&'a [DataTypes]);
impl<'de, 'a> Visitor<'de> for TransposeVecsVisitor<'a> {
type Value = Vec<Vec<Value>>;
fn visit_seq<A>(self, mut seq: A) -> Result<Vec<Vec<Value>>, A::Error>
where
A: SeqAccess<'de>,
{
let mut vec = Vec::new();
vec.resize_with(self.0.len(), || vec![]);
while let Some(()) = seq.next_element_seed(ExtendVecs(&mut vec, self.0))? {}
Ok(vec)
}
}
Ok(deserializer.deserialize_seq(TransposeVecsVisitor(self.0))?)
}
}
最后,最外面的 Deserialize
没什么特别的了,它只是将对类型数组的访问权交给了下层:
struct XD<'a>(&'a [DataTypes]);
impl<'de, 'a> DeserializeSeed<'de> for XD<'a> {
type Value = X;
fn deserialize<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
where
D: Deserializer<'de>,
{
struct XV<'a>(&'a [DataTypes]);
impl<'de, 'a> Visitor<'de> for XV<'a> {
type Value = X;
fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
where
A: serde::de::MapAccess<'de>,
{
let k = map.next_key::<String>()?;
// TODO: check k = "x"
Ok(X { x: map.next_value_seed(TransposeVecs(self.0))? })
}
}
Ok(deserializer.deserialize_struct("X", &["x"], XV(self.0))?)
}
}
现在,您可以使用所需的类型列表为最外层的 Deserialize
播种,并使用它反序列化一个 X
,例如:
XD(&[DataTypes::Numb, DataTypes::Stri]).deserialize(
&mut serde_json::Deserializer::from_str(r#"{"x": [[1, "a"], [2, "b"]]}"#)
)
Playground with all the left-out error handling
侧节点:如果可以(即,如果您要反序列化的格式是 self-describing,如 JSON),我建议在反序列化后进行类型检查。为什么?因为做during意味着所有的反序列化器到top deserializer都必须是DeserializeSeed
,不能用#[derive(Deserialize)]
。如果之后进行类型检查,则可以 #[derive(Deserialize)]
和 #[serde(deserialize_with = "TransposeVecs_deserialize_as_free_function")} x: Vec<Vec<Value>>
,并在 post.
中节省一半的麻烦
我正在编写一个库来解析 json 如下所示的数据:
{"x": [[1, "a"], [2, "b"]]}
即我有一个列表列表的键,其中内部列表可以包含不同的数据类型,但每个内部列表都具有相同的类型序列。内部列表的类型顺序可以根据不同的 json 模式而改变,但会提前知道。
所需的输出类似于:
vec![vec![1,2], vec!["a", "b"]]
(数据包装在不同数据类型的一些适当的枚举中)。
我开始为 Vec<DataTypes>
实现 DeserializeSeed
,下面是一些类似的伪代码。
enum DataTypes {
I32,
I64,
String,
F32,
F64
}
fn visit_seq<S>(self, mut seq: S) -> Result<Self::Value, S::Error>
where
S: SeqAccess<'de>,
{
let types: Vec<DataTypes> = self.0.data;
let out: Vec<Vec<...>>;
while let Some(inner_seq: S) = seq.next_element::<S>()? { // <-- this is the line
for (i, type) in types.enumerate() {
match type {
DataTypes::I32 => out[i].push(inner_seq.next_element::<i32>()?),
DataTypes::I64 => out[i].push(inner_seq.next_element::<i64>()?),
...
}
}
}
}
我的问题是我似乎无法找到一种方法来获取内部列表的 SeqAccess 并且我不想将它们反序列化为 Vec<serde_json::Value>
之类的东西,因为我不想分配附加向量。
请系好安全带,这很啰嗦。
我假设您想反序列化一些 JSON 数据
{"x": [[1, "a"], [2, "b"]]}
一些 Rust 结构
struct X {
x: Vec<Vec<Value>>, // Value is some enum containing string/int/float…
}
一直
- 插入向量时转置内部列表的元素
- 检查内部向量元素是否符合传递给反序列化的某种类型
- 不进行任何临时分配
一开始,您必须意识到要反序列化三种不同的类型:X
、Vec<Vec<Value>>>
和Vec<Value>
。 (Value
本身你不需要,因为你真正想要反序列化的是字符串和整数等等,而不是 Value
本身。)所以,你需要三个反序列化器和三个访问者。
最里面的 Deserialize
有一个对 Vec<Vec<Value>>
的可变引用,并将单个 [1, "a"]
的元素分配给每个 Vec<Value>
.
struct ExtendVecs<'a>(&'a mut Vec<Vec<Value>>, &'a [DataTypes]);
impl<'de, 'a> DeserializeSeed<'de> for ExtendVecs<'a> {
type Value = ();
fn deserialize<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
where
D: Deserializer<'de>,
{
struct ExtendVecVisitor<'a>(&'a mut Vec<Vec<Value>>, &'a [DataTypes]);
impl<'de, 'a> Visitor<'de> for ExtendVecVisitor<'a> {
type Value = ();
fn visit_seq<A>(self, mut seq: A) -> Result<(), A::Error>
where
A: SeqAccess<'de>,
{
for (i, typ) in self.1.iter().enumerate() {
match typ {
// too_short checks for None and turns it into Err("expected more elements")
DataTypes::Stri => self.0[i].push(Value::Stri(too_short(self.1, seq.next_element::<String>())?)),
DataTypes::Numb => self.0[i].push(Value::Numb(too_short(self.1, seq.next_element::<f64>())?)),
}
}
// TODO: check all elements consumed
Ok(())
}
}
deserializer.deserialize_seq(ExtendVecVisitor(self.0, self.1))
}
}
中间的Deserialize
构造了Vec<Vec<Value>>
,让最里面的ExtendVecs
访问了Vec<Vec<Value>>
,让ExtendVecs
看了每一个的 [[…], […]]
:
struct TransposeVecs<'a>(&'a [DataTypes]);
impl<'de, 'a> DeserializeSeed<'de> for TransposeVecs<'a> {
type Value = Vec<Vec<Value>>;
fn deserialize<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
where
D: Deserializer<'de>,
{
struct TransposeVecsVisitor<'a>(&'a [DataTypes]);
impl<'de, 'a> Visitor<'de> for TransposeVecsVisitor<'a> {
type Value = Vec<Vec<Value>>;
fn visit_seq<A>(self, mut seq: A) -> Result<Vec<Vec<Value>>, A::Error>
where
A: SeqAccess<'de>,
{
let mut vec = Vec::new();
vec.resize_with(self.0.len(), || vec![]);
while let Some(()) = seq.next_element_seed(ExtendVecs(&mut vec, self.0))? {}
Ok(vec)
}
}
Ok(deserializer.deserialize_seq(TransposeVecsVisitor(self.0))?)
}
}
最后,最外面的 Deserialize
没什么特别的了,它只是将对类型数组的访问权交给了下层:
struct XD<'a>(&'a [DataTypes]);
impl<'de, 'a> DeserializeSeed<'de> for XD<'a> {
type Value = X;
fn deserialize<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
where
D: Deserializer<'de>,
{
struct XV<'a>(&'a [DataTypes]);
impl<'de, 'a> Visitor<'de> for XV<'a> {
type Value = X;
fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
where
A: serde::de::MapAccess<'de>,
{
let k = map.next_key::<String>()?;
// TODO: check k = "x"
Ok(X { x: map.next_value_seed(TransposeVecs(self.0))? })
}
}
Ok(deserializer.deserialize_struct("X", &["x"], XV(self.0))?)
}
}
现在,您可以使用所需的类型列表为最外层的 Deserialize
播种,并使用它反序列化一个 X
,例如:
XD(&[DataTypes::Numb, DataTypes::Stri]).deserialize(
&mut serde_json::Deserializer::from_str(r#"{"x": [[1, "a"], [2, "b"]]}"#)
)
Playground with all the left-out error handling
侧节点:如果可以(即,如果您要反序列化的格式是 self-describing,如 JSON),我建议在反序列化后进行类型检查。为什么?因为做during意味着所有的反序列化器到top deserializer都必须是DeserializeSeed
,不能用#[derive(Deserialize)]
。如果之后进行类型检查,则可以 #[derive(Deserialize)]
和 #[serde(deserialize_with = "TransposeVecs_deserialize_as_free_function")} x: Vec<Vec<Value>>
,并在 post.