如何获取 serde SeqAccess 内部序列的 SeqAccess 类型?

wno*_*own 3 rust serde serde-json

我正在编写一个库来解析 json 数据,如下所示:

{"x": [[1, "a"], [2, "b"]]}
Run Code Online (Sandbox Code Playgroud)

即我有一个带有列表列表的键,其中内部列表可以包含不同的数据类型,但每个内部列表具有相同的类型序列。内部列表的类型序列可以针对不同的 json 模式而改变,但会提前知道。

所需的输出将类似于:( vec![vec![1,2], vec!["a", "b"]] 数据包装在不同数据类型的适当枚举中)。

我开始实现DeserializeSeedfor Vec<DataTypes>,下面是一些类似的伪代码。

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>()?),
                   ...
               }
           }
        }
    }
Run Code Online (Sandbox Code Playgroud)

我的问题是我似乎找不到一种方法来获取内部列表的 SeqAccess,并且我不想将它们反序列化为类似的东西,Vec<serde_json::Value>因为我不想分配额外的向量。

Cae*_*sar 6

请系好安全带,这很冗长。

\n

我假设您想要反序列化一些 JSON 数据

\n
{"x": [[1, "a"], [2, "b"]]}\n
Run Code Online (Sandbox Code Playgroud)\n

一些 Rust 结构

\n
struct X {\n    x: Vec<Vec<Value>>, // Value is some enum containing string/int/float\xe2\x80\xa6\n}\n
Run Code Online (Sandbox Code Playgroud)\n

一直

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

首先,您必须意识到要反序列化三种不同的类型:XVec<Vec<Value>>>Vec<Value>。(Value它本身你不需要,因为你真正想要反序列化的是字符串和整数等等,而不是Value它本身。)所以,你需要三个反序列化器和三个访问者。

\n

最里面Deserialize有一个对 a 的可变引用Vec<Vec<Value>>,并将单个 的元素分配[1, "a"]给每个Vec<Value>

\n
struct ExtendVecs<\'a>(&\'a mut Vec<Vec<Value>>, &\'a [DataTypes]);\nimpl<\'de, \'a> DeserializeSeed<\'de> for ExtendVecs<\'a> {\n    type Value = ();\n    fn deserialize<D>(self, deserializer: D) -> Result<Self::Value, D::Error>\n    where\n        D: Deserializer<\'de>,\n    {\n        struct ExtendVecVisitor<\'a>(&\'a mut Vec<Vec<Value>>, &\'a [DataTypes]);\n        impl<\'de, \'a> Visitor<\'de> for ExtendVecVisitor<\'a> {\n            type Value = ();\n            fn visit_seq<A>(self, mut seq: A) -> Result<(), A::Error>\n            where\n                A: SeqAccess<\'de>,\n            {\n                for (i, typ) in self.1.iter().enumerate() {\n                    match typ {\n                        // too_short checks for None and turns it into Err("expected more elements")\n                        DataTypes::Stri => self.0[i].push(Value::Stri(too_short(self.1, seq.next_element::<String>())?)),\n                        DataTypes::Numb => self.0[i].push(Value::Numb(too_short(self.1, seq.next_element::<f64>())?)),\n                    }\n                }\n                // TODO: check all elements consumed\n                Ok(())\n            }\n        }\n        deserializer.deserialize_seq(ExtendVecVisitor(self.0, self.1))\n    }\n}\n
Run Code Online (Sandbox Code Playgroud)\n

中间Deserialize构造Vec<Vec<Value>>,提供对 的最内部ExtendVecs访问Vec<Vec<Value>>,并要求ExtendVecs 查看每个[[\xe2\x80\xa6], [\xe2\x80\xa6]]

\n
struct TransposeVecs<\'a>(&\'a [DataTypes]);\nimpl<\'de, \'a> DeserializeSeed<\'de> for TransposeVecs<\'a> {\n    type Value = Vec<Vec<Value>>;\n    fn deserialize<D>(self, deserializer: D) -> Result<Self::Value, D::Error>\n    where\n        D: Deserializer<\'de>,\n    {\n        struct TransposeVecsVisitor<\'a>(&\'a [DataTypes]);\n        impl<\'de, \'a> Visitor<\'de> for TransposeVecsVisitor<\'a> {\n            type Value = Vec<Vec<Value>>;\n            fn visit_seq<A>(self, mut seq: A) -> Result<Vec<Vec<Value>>, A::Error>\n            where\n                A: SeqAccess<\'de>,\n            {\n                let mut vec = Vec::new();\n                vec.resize_with(self.0.len(), || vec![]);\n                while let Some(()) = seq.next_element_seed(ExtendVecs(&mut vec, self.0))? {}\n                Ok(vec)\n            }\n        }\n\n        Ok(deserializer.deserialize_seq(TransposeVecsVisitor(self.0))?)\n    }\n}\n
Run Code Online (Sandbox Code Playgroud)\n

最后,最外层Deserialize不再有什么特别的了,它只是将类型数组的访问权交给了下面的人:

\n
struct XD<\'a>(&\'a [DataTypes]);\nimpl<\'de, \'a> DeserializeSeed<\'de> for XD<\'a> {\n    type Value = X;\n    fn deserialize<D>(self, deserializer: D) -> Result<Self::Value, D::Error>\n    where\n        D: Deserializer<\'de>,\n    {\n        struct XV<\'a>(&\'a [DataTypes]);\n        impl<\'de, \'a> Visitor<\'de> for XV<\'a> {\n            type Value = X;\n            fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>\n            where\n                A: serde::de::MapAccess<\'de>,\n            {\n                let k = map.next_key::<String>()?;\n                // TODO: check k = "x"\n                Ok(X { x: map.next_value_seed(TransposeVecs(self.0))? })\n            }\n        }\n\n        Ok(deserializer.deserialize_struct("X", &["x"], XV(self.0))?)\n    }\n}\n
Run Code Online (Sandbox Code Playgroud)\n

现在,您可以在最外层添加Deserialize所需的类型列表,并使用它来反序列化一个X,例如:

\n
XD(&[DataTypes::Numb, DataTypes::Stri]).deserialize(\n    &mut serde_json::Deserializer::from_str(r#"{"x": [[1, "a"], [2, "b"]]}"#)\n)\n
Run Code Online (Sandbox Code Playgroud)\n

带有所有遗漏错误处理的游乐场

\n
\n

侧面节点:如果可以(即,如果您要反序列化的格式是自描述的,如 JSON),我建议在反序列化后进行类型检查。为什么?因为在期间执行此操作意味着直到顶部解串器的所有解串器都必须是DeserializeSeed,并且您不能使用#[derive(Deserialize)]。如果您之后进行类型检查,您可以#[derive(Deserialize)]#[serde(deserialize_with = "TransposeVecs_deserialize_as_free_function")} x: Vec<Vec<Value>>,并在这篇文章中节省一半的废话。

\n