使用泛型进行Rust和Serde反序列化 [英] Rust and serde deserializing using generics

查看:756
本文介绍了使用泛型进行Rust和Serde反序列化的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试使用泛型从文件中反序列化结构,以与Swagger生成的API一起使用.因此,我将其结合在一起几乎可以正常工作,但是我无法从拥有的"指针中解压缩外部Struct对象,如在测试中所见.

I am trying to use generics to deserialize structs from file for use with a Swagger generated API. So I have hacked together this which almost works, but I am unable to unpack the external Struct object from the "Owned" pointer, as you can see in the tests.

这可能是错误的策略,但是问题是我有各种yaml文件,我想读入这些文件并反序列化,以提示正确的Struct进行反序列化.我不想为每个Struct实现一个"readfile"功能,因为有很多功能.因此,我正在尝试使该通用库工作,该库应反序列化为正确的Struct,并与Swagger API结合使用.

This might be the wrong strategy, but the problem is that I have various yaml files, which I want to read in and deserialise hinting the correct Struct to deserialise as. I don't want to implement a "readfile" function for each Struct, as there are many. So I am trying to make this generic lib work which should deserialise into the correct Struct, and use with the Swagger API.

它已经很接近工作了,但是我似乎无法将Outer<ExternalStructA>解包为ExternalStructA.

It's very close to working but I cannot seem to unwrap the Outer<ExternalStructA> into just ExternalStructA.

Owned(ExternalStructA { x: 1, y: 2 })
Owned(ExternalStructB { a: 1, b: 2 })

lib.rs:

#[cfg(test)]
mod tests {
    use crate::generics_yaml_deserializer::Outer;
    use serde::{de, Deserialize, Deserializer, Serialize, Serializer};

    #[derive(Debug, Serialize, Deserialize)]
    pub struct ExternalStructA {
        x: u32,
        y: u32,
    }

    #[derive(Debug, Serialize, Deserialize)]
    pub struct ExternalStructB {
        a: u64,
        b: u64,
    }

    #[test]
    fn deserialize() {
        let a = r#"---
ptr:
  x: 1
  y: 2
     "#;

        let b = r#"---
ptr:
  a: 1
  b: 2
        "#;

        let resulta: Outer<ExternalStructA> = serde_yaml::from_str(a).unwrap();
        assert_eq!(1, resulta.ptr.x); // I can't seem to get into ptr ExternalStructA
        let resultb: Outer<ExternalStructB> = serde_yaml::from_str(b).unwrap();
        assert_eq!(1, resultb.ptr.a); // I can't seem to get into ptr ExternalStructB 
    }
}

mod generics_yaml_deserializer {
    use serde::{de, Deserialize, Deserializer, Serialize, Serializer};
    use std::error::Error;

    // empty holding struct which owns a owned ptr
    #[derive(Deserialize, Debug)]
    pub struct Outer<'a, T: 'a + ?Sized> {
        #[serde(bound(deserialize = "Ptr<'a, T>: Deserialize<'de>"))]
        pub ptr: Ptr<'a, T>,
    }

    #[derive(Debug)]
    pub enum Ptr<'a, T: 'a + ?Sized> {
        Ref(&'a T),
        Owned(Box<T>),
    }

    impl<'de, 'a, T: 'a + ?Sized> Deserialize<'de> for Ptr<'a, T>
    where
        Box<T>: Deserialize<'de>,
    {
        fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
            where
                D: Deserializer<'de>,
        {
            Deserialize::deserialize(deserializer).map(Ptr::Owned)
        }
    }
}

货物依赖性:

serde = { version = "1.0", features = ["derive"] }
serde_derive = "1.0"
serde_yaml = "0.7.5"
serde_json = "1.0"

更新:

我在通过以下方式获得Struct方面取得了部分成功:

I have had partial success getting the Struct out with:

let resulta: Outer<ExternalStructA> = serde_yaml::from_str(a).unwrap();
    match resulta.ptr {
        Ptr::Owned(e) => {assert_eq!(1, e.x);},
        Ptr::Ref(e) => {println!("error")},
        Ptr::Owned(_) => {println!("error")}
    };
}

但是当我尝试使用泛型类型将此功能实现为函数时,会出现很多错误,主要是:

But when I try implement this as a function using generic typing, I get lots of errors, the main being:

the trait `for<'de> tests::_IMPL_DESERIALIZE_FOR_ExternalStructA::_serde::Deserialize<'de>` is not implemented for `T`

非工作代码已添加到modgenerics_yaml_deserializer

Non-Working code added to mod generics_yaml_deserializer

fn readfile<T>(filename: String) -> Result<Box<T>, Box<std::error::Error>> {
    let f = std::fs::File::open(filename)?;
    let config_data: Outer<T> = serde_yaml::from_reader(f)?;
    Ok(Box::new(config_data))
}

fn readconfig<T>(filename: String) -> Result<Box<T>, &'static str> {
    // read the config file
    let config_data = readfile(filename);
    match config_data {
        Ok(e) => {
            Ok(Box::new(e))
        },
        Err(_) => {
            Err("nadda")
        }
    }
}

推荐答案

只需声明TDeserializeOwned:

fn readfile<T: de::DeserializeOwned>(filename: String) -> Result<Box<T>, Box<std::error::Error>> {
    let f = std::fs::File::open(filename)?;
    let config_data: Outer<T> = serde_yaml::from_reader(f)?;
    match config_data.ptr {
        Ptr::Owned(data) => Ok(data),
        _ => unimplemented!(),
    }
}

readconfig

这篇关于使用泛型进行Rust和Serde反序列化的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆