简体   繁体   English

通过实现 serde `Deserializer` 将值的 Vec 反序列化为结构

[英]Deserialize a Vec of values into a struct by implementing serde `Deserializer`

I have a data format using custom enum of values.我有一个使用自定义枚举值的数据格式。 From the database I receive a Vec<MyVal> .我从数据库收到一个Vec<MyVal> I want to convert this to a struct (and fail if it doesn't work).我想将其转换为结构(如果它不起作用则失败)。 I want to use serde because after processing I want to return the API response as a json, and serde makes this super easy.我想使用 serde,因为处理后我想将 API 响应作为 json 返回,而 serde 使这变得非常简单。

Playground link for the example 该示例的游乐场链接

enum MyVal {
  Bool(bool),
  Text(String)
}

#[derive(Serialize, Deserialize)]
struct User {
  name: String,
  registered: bool
}

The challenge is with converting the data format into the serde data model. For this I can implement a Deserializer and implement the visit_seq method ie visit the Vec<MyVal> as if it were a sequence and return the values one by one.挑战在于将数据格式转换为 serde 数据 model。为此,我可以实现Deserializer并实现visit_seq方法,即访问Vec<MyVal>就好像它是一个序列并一个一个地返回值。 The visitor for User can consume the visited values to build the struct User . User的访问者可以使用访问的值来构建struct User

However I'm not able to figure out how to convert the Vec into something visitor_seq can consume.但是我无法弄清楚如何将Vec转换为visitor_seq可以使用的东西。 Here's some sample code.这是一些示例代码。

struct MyWrapper(Vec<MyVal>);

impl<'de> Deserializer<'de> for MyWrapper {
    type Error = de::value::Error;

    // skip unncessary

    fn deserialize_seq<V>(self, visitor: V) -> Result<V::Value, Self::Error>
    where
        V: serde::de::Visitor<'de>,
    {
        let convert_myval = move |myval: &MyVal| match myval {
            MyVal::Bool(b) => visitor.visit_bool(*b),
            MyVal::Text(s) => visitor.visit_string(s.clone())
        };

        // now I have a vec of serde values
        let rec_vec: Vec<Result<V::Value, Self::Error>> =
            self.0.iter().map(|myval| convert_myval(myval)).collect();
        // giving error!!
        visitor.visit_seq(rec_vec.into_iter())
    }
}

The error is错误是

92   |         visitor.visit_seq(rec_vec.into_iter())
     |                 --------- ^^^^^^^^^^^^^^^^^^^ the trait `SeqAccess<'de>` is not implemented for `std::vec::IntoIter<Result<<V as Visitor<'de>>::Value, _::_serde::de::value::Error>>`
     |                 |
     |                 required by a bound introduced by this call

So I looked into SeqAccess and it has an implementor that requires that whatever is passed to it implement the Iterator trait.所以我研究了SeqAccess ,它有一个实现器,要求传递给它的任何东西都实现Iterator特性。 But I thought I had that covered, because vec.into_iter returns an IntoIter , a consuming iterator which does implement the Iterator trait.但我认为我已经涵盖了这一点,因为vec.into_iter返回一个IntoIter ,一个确实实现Iterator特性的消费迭代器。

So I'm completely lost as to what's going wrong here.所以我完全不知道这里出了什么问题。 Surely there must be a way to visit a Vec<Result<Value, Error>> as a seq?当然必须有一种方法可以将Vec<Result<Value, Error>>作为 seq 访问吗?

Preface: The question wants to treat a Rust data structure Vec<MyData> like a serialized piece of data (eg: like a JSON string) and allow deserializing that into any other Rust data structure that implements Deserialize .前言:问题想要将 Rust 数据结构Vec<MyData>视为序列化数据(例如:像 JSON 字符串),并允许将其反序列化为任何其他实现Deserialize的 Rust 数据结构。 This is a quite unusual, but not without precedent.这是相当不寻常的,但并非没有先例。 And since the MyVal s are actually pieces of data with various types which get returned from a database access crate, this approach does make sense.由于MyVal实际上是从数据库访问包返回的各种类型的数据片段,因此这种方法确实有意义。

The main problem with the code in the question is that it tries to deserialize two different data structures ( MyWrapper<Vec<MyVal>> and MyVal ) with a single Deserializer .问题中代码的主要问题是它试图使用单个Deserializer序列化两个不同的数据结构( MyWrapper<Vec<MyVal>>MyVal )。 The obvious way out is to define a second struct MyValWrapper(MyVal) and implement Deserializer for it:显而易见的出路是定义第二个struct MyValWrapper(MyVal)并为其实现Deserializer

struct MyValWrapper(MyVal);
impl<'de> Deserializer<'de> for MyValWrapper {
    type Error = de::value::Error;

    fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Self::Error>
    where
        V: de::Visitor<'de>,
    {
        match self.0 {
            MyVal::Bool(b) => visitor.visit_bool(b),
            MyVal::Text(s) => visitor.visit_string(s.clone()),
        }
    }

    // Maybe you should call deserialize_any from all other deserialize_* functions to get a passable error message, e.g.:
    forward_to_deserialize_any! {
        bool i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 f32 f64 char str string
        bytes byte_buf option unit unit_struct newtype_struct seq tuple
        tuple_struct map struct enum identifier ignored_any
    }
    // Though maybe you want to handle deserialize_enum differently...
}

MyValWrapper now can deserialize a MyVal . MyValWrapper现在可以反序列MyVal To use MyValWrapper to deserialize a Vec of MyVal s, the serde::value::SeqDeserializer adapter is convenient, it can turn an iterator of ( Into ) Deserializer into a sequence Deserializer :要使用MyValWrapper反序列化MyValVecserde::value::SeqDeserializer适配器很方便,它可以将 ( Into ) Deserializer的迭代器转换为序列Deserializer

let data: Vec<MyData> = …;
// Vec deserialization snippet
let mut sd = SeqDeserializer::new(data.into_iter().map(|myval| MyValWrapper(myval)));
let res = visitor.visit_seq(&mut sd)?;
sd.end()?;
Ok(res)

For some reason, SeqDeserializer requires the iterator items to be IntoDeserializer , but no impl<T: IntoDeserializer> Deserializer for T exists, so we need to make sure that MyValWrapper is not only a Deserializer but trivially also an IntoDeserializer :出于某种原因, SeqDeserializer要求迭代器项为IntoDeserializer ,但不存在impl<T: IntoDeserializer> Deserializer for T ,因此我们需要确保MyValWrapper不仅是Deserializer ,而且通常也是IntoDeserializer

impl<'de> IntoDeserializer<'de> for MyValWrapper {
    type Deserializer = MyValWrapper;
    fn into_deserializer(self) -> Self::Deserializer {
        self
    }
}

Finally, you need to impl Deserializer for MyWrapper (you can use the "Vec deserialization snippet" for that) — if you do actually need Deserializer to be implemented, which I suspect you don't: the SeqDeserializer already implements Deserializer , and it is a wrapper struct (just as MyWrapper is a wrapper struct).最后,你需要impl Deserializer for MyWrapper (你可以为此使用“Vec 反序列化片段”)——如果你确实需要实现Deserializer ,我怀疑你不需要: SeqDeserializer已经实现了Deserializer ,它是包装器结构(就像MyWrapper是包装器结构一样)。 Especially, if your final goal is having a function like特别是,如果您的最终目标是拥有 function 之类的

fn turn_bad_myvals_into_good_T<T: DeserializeOwned>(v: Vec<MyVal>) -> T {
    T::deserialize(SeqDeserializer::new(
        v.into_iter().map(|myval| MyValWrapper(myval)),
    ))
}

then you entirely don't need MyWrapper .那么你完全不需要MyWrapper

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM