如何获取 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…
}

一直

  • 插入向量时转置内部列表的元素
  • 检查内部向量元素是否符合传递给反序列化的某种类型
  • 不进行任何临时分配

一开始,您必须意识到要反序列化三种不同的类型:XVec<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.

中节省一半的麻烦